[CMAKE]
[reactos.git] / subsystems / win32 / win32k / ntuser / window.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Windows
5 * FILE: subsystems/win32/win32k/ntuser/window.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISION HISTORY:
8 * 06-06-2001 CSH Created
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <win32k.h>
14
15 #define NDEBUG
16 #include <debug.h>
17
18
19 /* dialog resources appear to pass this in 16 bits, handle them properly */
20 #define CW_USEDEFAULT16 (0x8000)
21
22 #define POINT_IN_RECT(p, r) (((r.bottom >= p.y) && (r.top <= p.y))&&((r.left <= p.x )&&( r.right >= p.x )))
23
24 /* PRIVATE FUNCTIONS **********************************************************/
25
26 /*
27 * InitWindowImpl
28 *
29 * Initialize windowing implementation.
30 */
31
32 NTSTATUS FASTCALL
33 InitWindowImpl(VOID)
34 {
35 return STATUS_SUCCESS;
36 }
37
38 /*
39 * CleanupWindowImpl
40 *
41 * Cleanup windowing implementation.
42 */
43
44 NTSTATUS FASTCALL
45 CleanupWindowImpl(VOID)
46 {
47 return STATUS_SUCCESS;
48 }
49
50 /* HELPER FUNCTIONS ***********************************************************/
51
52 BOOL FASTCALL UserUpdateUiState(PWND Wnd, WPARAM wParam)
53 {
54 WORD Action = LOWORD(wParam);
55 WORD Flags = HIWORD(wParam);
56
57 if (Flags & ~(UISF_HIDEFOCUS | UISF_HIDEACCEL | UISF_ACTIVE))
58 {
59 SetLastWin32Error(ERROR_INVALID_PARAMETER);
60 return FALSE;
61 }
62
63 switch (Action)
64 {
65 case UIS_INITIALIZE:
66 SetLastWin32Error(ERROR_INVALID_PARAMETER);
67 return FALSE;
68
69 case UIS_SET:
70 if (Flags & UISF_HIDEFOCUS)
71 Wnd->HideFocus = TRUE;
72 if (Flags & UISF_HIDEACCEL)
73 Wnd->HideAccel = TRUE;
74 break;
75
76 case UIS_CLEAR:
77 if (Flags & UISF_HIDEFOCUS)
78 Wnd->HideFocus = FALSE;
79 if (Flags & UISF_HIDEACCEL)
80 Wnd->HideAccel = FALSE;
81 break;
82 }
83
84 return TRUE;
85 }
86
87 PWINDOW_OBJECT FASTCALL IntGetWindowObject(HWND hWnd)
88 {
89 PWINDOW_OBJECT Window;
90
91 if (!hWnd) return NULL;
92
93 Window = UserGetWindowObject(hWnd);
94 if (Window)
95 {
96 ASSERT(Window->head.cLockObj >= 0);
97
98 Window->head.cLockObj++;
99
100 ASSERT(Window->Wnd);
101 }
102 return Window;
103 }
104
105 /* temp hack */
106 PWINDOW_OBJECT FASTCALL UserGetWindowObject(HWND hWnd)
107 {
108 PTHREADINFO ti;
109 PWINDOW_OBJECT Window;
110
111 if (PsGetCurrentProcess() != PsInitialSystemProcess)
112 {
113 ti = GetW32ThreadInfo();
114 if (ti == NULL)
115 {
116 SetLastWin32Error(ERROR_ACCESS_DENIED);
117 return NULL;
118 }
119 }
120
121 if (!hWnd)
122 {
123 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
124 return NULL;
125 }
126
127 Window = (PWINDOW_OBJECT)UserGetObject(gHandleTable, hWnd, otWindow);
128 if (!Window || 0 != (Window->state & WINDOWSTATUS_DESTROYED))
129 {
130 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
131 return NULL;
132 }
133
134 ASSERT(Window->head.cLockObj >= 0);
135
136 ASSERT(Window->Wnd);
137
138 return Window;
139 }
140
141
142 /*
143 * IntIsWindow
144 *
145 * The function determines whether the specified window handle identifies
146 * an existing window.
147 *
148 * Parameters
149 * hWnd
150 * Handle to the window to test.
151 *
152 * Return Value
153 * If the window handle identifies an existing window, the return value
154 * is TRUE. If the window handle does not identify an existing window,
155 * the return value is FALSE.
156 */
157
158 BOOL FASTCALL
159 IntIsWindow(HWND hWnd)
160 {
161 PWINDOW_OBJECT Window;
162
163 if (!(Window = UserGetWindowObject(hWnd)))
164 return FALSE;
165
166 return TRUE;
167 }
168
169
170
171 PWINDOW_OBJECT FASTCALL
172 IntGetParent(PWINDOW_OBJECT Wnd)
173 {
174 if (Wnd->Wnd->style & WS_POPUP)
175 {
176 return Wnd->spwndOwner;
177 }
178 else if (Wnd->Wnd->style & WS_CHILD)
179 {
180 return Wnd->spwndParent;
181 }
182
183 return NULL;
184 }
185
186
187 /*
188 * IntWinListChildren
189 *
190 * Compile a list of all child window handles from given window.
191 *
192 * Remarks
193 * This function is similar to Wine WIN_ListChildren. The caller
194 * must free the returned list with ExFreePool.
195 */
196
197 HWND* FASTCALL
198 IntWinListChildren(PWINDOW_OBJECT Window)
199 {
200 PWINDOW_OBJECT Child;
201 HWND *List;
202 UINT Index, NumChildren = 0;
203
204 if (!Window) return NULL;
205
206 for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
207 ++NumChildren;
208
209 List = ExAllocatePoolWithTag(PagedPool, (NumChildren + 1) * sizeof(HWND), TAG_WINLIST);
210 if(!List)
211 {
212 DPRINT1("Failed to allocate memory for children array\n");
213 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
214 return NULL;
215 }
216 for (Child = Window->spwndChild, Index = 0;
217 Child != NULL;
218 Child = Child->spwndNext, ++Index)
219 List[Index] = Child->hSelf;
220 List[Index] = NULL;
221
222 return List;
223 }
224
225 /***********************************************************************
226 * IntSendDestroyMsg
227 */
228 static void IntSendDestroyMsg(HWND hWnd)
229 {
230
231 PWINDOW_OBJECT Window;
232 #if 0 /* FIXME */
233
234 GUITHREADINFO info;
235
236 if (GetGUIThreadInfo(GetCurrentThreadId(), &info))
237 {
238 if (hWnd == info.hwndCaret)
239 {
240 DestroyCaret();
241 }
242 }
243 #endif
244
245 Window = UserGetWindowObject(hWnd);
246 if (Window)
247 {
248 // USER_REFERENCE_ENTRY Ref;
249 // UserRefObjectCo(Window, &Ref);
250
251 if (!Window->spwndOwner && !IntGetParent(Window))
252 {
253 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (LPARAM) hWnd);
254 }
255
256 // UserDerefObjectCo(Window);
257 }
258
259 /* The window could already be destroyed here */
260
261 /*
262 * Send the WM_DESTROY to the window.
263 */
264
265 co_IntSendMessage(hWnd, WM_DESTROY, 0, 0);
266
267 /*
268 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
269 * make sure that the window still exists when we come back.
270 */
271 #if 0 /* FIXME */
272
273 if (IsWindow(Wnd))
274 {
275 HWND* pWndArray;
276 int i;
277
278 if (!(pWndArray = WIN_ListChildren( hwnd )))
279 return;
280
281 /* start from the end (FIXME: is this needed?) */
282 for (i = 0; pWndArray[i]; i++)
283 ;
284
285 while (--i >= 0)
286 {
287 if (IsWindow( pWndArray[i] ))
288 WIN_SendDestroyMsg( pWndArray[i] );
289 }
290 HeapFree(GetProcessHeap(), 0, pWndArray);
291 }
292 else
293 {
294 DPRINT("destroyed itself while in WM_DESTROY!\n");
295 }
296 #endif
297 }
298
299 static VOID
300 UserFreeWindowInfo(PTHREADINFO ti, PWINDOW_OBJECT WindowObject)
301 {
302 PCLIENTINFO ClientInfo = GetWin32ClientInfo();
303 PWND Wnd = WindowObject->Wnd;
304
305 if (!Wnd) return;
306
307 if (ClientInfo->CallbackWnd.pvWnd == DesktopHeapAddressToUser(WindowObject->Wnd))
308 {
309 ClientInfo->CallbackWnd.hWnd = NULL;
310 ClientInfo->CallbackWnd.pvWnd = NULL;
311 }
312
313 if (Wnd->strName.Buffer != NULL)
314 {
315 Wnd->strName.Length = 0;
316 Wnd->strName.MaximumLength = 0;
317 DesktopHeapFree(Wnd->head.rpdesk,
318 Wnd->strName.Buffer);
319 Wnd->strName.Buffer = NULL;
320 }
321
322 DesktopHeapFree(Wnd->head.rpdesk, Wnd);
323 WindowObject->Wnd = NULL;
324 }
325
326 /***********************************************************************
327 * IntDestroyWindow
328 *
329 * Destroy storage associated to a window. "Internals" p.358
330 *
331 * This is the "functional" DestroyWindows function ei. all stuff
332 * done in CreateWindow is undone here and not in DestroyWindow:-P
333
334 */
335 static LRESULT co_UserFreeWindow(PWINDOW_OBJECT Window,
336 PPROCESSINFO ProcessData,
337 PTHREADINFO ThreadData,
338 BOOLEAN SendMessages)
339 {
340 HWND *Children;
341 HWND *ChildHandle;
342 PWINDOW_OBJECT Child;
343 PMENU_OBJECT Menu;
344 BOOLEAN BelongsToThreadData;
345 PWND Wnd;
346
347 ASSERT(Window);
348
349 Wnd = Window->Wnd;
350
351 if(Window->state & WINDOWSTATUS_DESTROYING)
352 {
353 DPRINT("Tried to call IntDestroyWindow() twice\n");
354 return 0;
355 }
356 Window->state |= WINDOWSTATUS_DESTROYING;
357 Wnd->style &= ~WS_VISIBLE;
358
359 IntNotifyWinEvent(EVENT_OBJECT_DESTROY, Wnd, OBJID_WINDOW, 0);
360
361 /* remove the window already at this point from the thread window list so we
362 don't get into trouble when destroying the thread windows while we're still
363 in IntDestroyWindow() */
364 RemoveEntryList(&Window->ThreadListEntry);
365
366 BelongsToThreadData = IntWndBelongsToThread(Window, ThreadData);
367
368 IntDeRegisterShellHookWindow(Window->hSelf);
369
370 if(SendMessages)
371 {
372 /* Send destroy messages */
373 IntSendDestroyMsg(Window->hSelf);
374 }
375
376 /* free child windows */
377 Children = IntWinListChildren(Window);
378 if (Children)
379 {
380 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
381 {
382 if ((Child = IntGetWindowObject(*ChildHandle)))
383 {
384 if(!IntWndBelongsToThread(Child, ThreadData))
385 {
386 /* send WM_DESTROY messages to windows not belonging to the same thread */
387 IntSendDestroyMsg(Child->hSelf);
388 }
389 else
390 co_UserFreeWindow(Child, ProcessData, ThreadData, SendMessages);
391
392 UserDereferenceObject(Child);
393 }
394 }
395 ExFreePool(Children);
396 }
397
398 if(SendMessages)
399 {
400 /*
401 * Clear the update region to make sure no WM_PAINT messages will be
402 * generated for this window while processing the WM_NCDESTROY.
403 */
404 co_UserRedrawWindow(Window, NULL, 0,
405 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE |
406 RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
407 if(BelongsToThreadData)
408 co_IntSendMessage(Window->hSelf, WM_NCDESTROY, 0, 0);
409 }
410 DestroyTimersForWindow(ThreadData, Window);
411 HOOK_DestroyThreadHooks(ThreadData->pEThread); // This is needed here too!
412
413 /* flush the message queue */
414 MsqRemoveWindowMessagesFromQueue(Window);
415
416 /* from now on no messages can be sent to this window anymore */
417 Window->state |= WINDOWSTATUS_DESTROYED;
418 Wnd->state |= WNDS_DESTROYED;
419 Wnd->fnid |= FNID_FREED;
420
421 /* don't remove the WINDOWSTATUS_DESTROYING bit */
422
423 /* reset shell window handles */
424 if(ThreadData->rpdesk)
425 {
426 if (Window->hSelf == ThreadData->rpdesk->rpwinstaParent->ShellWindow)
427 ThreadData->rpdesk->rpwinstaParent->ShellWindow = NULL;
428
429 if (Window->hSelf == ThreadData->rpdesk->rpwinstaParent->ShellListView)
430 ThreadData->rpdesk->rpwinstaParent->ShellListView = NULL;
431 }
432
433 /* Unregister hot keys */
434 UnregisterWindowHotKeys (Window);
435
436 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
437
438 #if 0 /* FIXME */
439
440 WinPosCheckInternalPos(Window->hSelf);
441 if (Window->hSelf == GetCapture())
442 {
443 ReleaseCapture();
444 }
445
446 /* free resources associated with the window */
447 TIMER_RemoveWindowTimers(Window->hSelf);
448 #endif
449
450 if (!(Wnd->style & WS_CHILD) && Wnd->IDMenu
451 && (Menu = UserGetMenuObject((HMENU)Wnd->IDMenu)))
452 {
453 IntDestroyMenuObject(Menu, TRUE, TRUE);
454 Wnd->IDMenu = 0;
455 }
456
457 if(Window->SystemMenu
458 && (Menu = UserGetMenuObject(Window->SystemMenu)))
459 {
460 IntDestroyMenuObject(Menu, TRUE, TRUE);
461 Window->SystemMenu = (HMENU)0;
462 }
463
464 DceFreeWindowDCE(Window); /* Always do this to catch orphaned DCs */
465 #if 0 /* FIXME */
466
467 WINPROC_FreeProc(Window->winproc, WIN_PROC_WINDOW);
468 CLASS_RemoveWindow(Window->Class);
469 #endif
470
471 IntUnlinkWindow(Window);
472
473 UserReferenceObject(Window);
474 UserDeleteObject(Window->hSelf, otWindow);
475
476 IntDestroyScrollBars(Window);
477
478 /* dereference the class */
479 IntDereferenceClass(Wnd->pcls,
480 Window->pti->pDeskInfo,
481 Window->pti->ppi);
482 Wnd->pcls = NULL;
483
484 if(Window->hrgnClip)
485 {
486 GreDeleteObject(Window->hrgnClip);
487 }
488
489 ASSERT(Window->Wnd != NULL);
490 UserFreeWindowInfo(Window->pti, Window);
491
492 UserDereferenceObject(Window);
493
494 IntClipboardFreeWindow(Window);
495
496 return 0;
497 }
498
499 VOID FASTCALL
500 IntGetWindowBorderMeasures(PWINDOW_OBJECT Window, UINT *cx, UINT *cy)
501 {
502 PWND Wnd = Window->Wnd;
503 if(HAS_DLGFRAME(Wnd->style, Wnd->ExStyle) && !(Wnd->style & WS_MINIMIZE))
504 {
505 *cx = UserGetSystemMetrics(SM_CXDLGFRAME);
506 *cy = UserGetSystemMetrics(SM_CYDLGFRAME);
507 }
508 else
509 {
510 if(HAS_THICKFRAME(Wnd->style, Wnd->ExStyle)&& !(Wnd->style & WS_MINIMIZE))
511 {
512 *cx = UserGetSystemMetrics(SM_CXFRAME);
513 *cy = UserGetSystemMetrics(SM_CYFRAME);
514 }
515 else if(HAS_THINFRAME(Wnd->style, Wnd->ExStyle))
516 {
517 *cx = UserGetSystemMetrics(SM_CXBORDER);
518 *cy = UserGetSystemMetrics(SM_CYBORDER);
519 }
520 else
521 {
522 *cx = *cy = 0;
523 }
524 }
525 }
526
527 //
528 // Same as User32:IntGetWndProc.
529 //
530 WNDPROC FASTCALL
531 IntGetWindowProc(PWND pWnd,
532 BOOL Ansi)
533 {
534 INT i;
535 PCLS Class;
536 WNDPROC gcpd, Ret = 0;
537
538 ASSERT(UserIsEnteredExclusive() == TRUE);
539
540 Class = pWnd->pcls;
541
542 if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
543 {
544 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
545 {
546 if (GETPFNSERVER(i) == pWnd->lpfnWndProc)
547 {
548 if (Ansi)
549 Ret = GETPFNCLIENTA(i);
550 else
551 Ret = GETPFNCLIENTW(i);
552 }
553 }
554 return Ret;
555 }
556
557 if (Class->fnid == FNID_EDIT)
558 Ret = pWnd->lpfnWndProc;
559 else
560 {
561 Ret = pWnd->lpfnWndProc;
562
563 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
564 {
565 if (Ansi)
566 {
567 if (GETPFNCLIENTW(Class->fnid) == pWnd->lpfnWndProc)
568 Ret = GETPFNCLIENTA(Class->fnid);
569 }
570 else
571 {
572 if (GETPFNCLIENTA(Class->fnid) == pWnd->lpfnWndProc)
573 Ret = GETPFNCLIENTW(Class->fnid);
574 }
575 }
576 if ( Ret != pWnd->lpfnWndProc)
577 return Ret;
578 }
579 if ( Ansi == !!(pWnd->state & WNDS_ANSIWINDOWPROC) )
580 return Ret;
581
582 gcpd = (WNDPROC)UserGetCPD(
583 pWnd,
584 (Ansi ? UserGetCPDA2U : UserGetCPDU2A )|UserGetCPDWindow,
585 (ULONG_PTR)Ret);
586
587 return (gcpd ? gcpd : Ret);
588 }
589
590 static WNDPROC
591 IntSetWindowProc(PWND pWnd,
592 WNDPROC NewWndProc,
593 BOOL Ansi)
594 {
595 INT i;
596 PCALLPROCDATA CallProc;
597 PCLS Class;
598 WNDPROC Ret, chWndProc = NULL;
599
600 // Retrieve previous window proc.
601 Ret = IntGetWindowProc(pWnd, Ansi);
602
603 Class = pWnd->pcls;
604
605 if (IsCallProcHandle(NewWndProc))
606 {
607 CallProc = UserGetObject(gHandleTable, NewWndProc, otCallProc);
608 if (CallProc)
609 { // Reset new WndProc.
610 NewWndProc = CallProc->pfnClientPrevious;
611 // Reset Ansi from CallProc handle. This is expected with wine "deftest".
612 Ansi = !!(CallProc->wType & UserGetCPDU2A);
613 }
614 }
615 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
616 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
617 {
618 if (GETPFNCLIENTW(i) == NewWndProc)
619 {
620 chWndProc = GETPFNSERVER(i);
621 break;
622 }
623 if (GETPFNCLIENTA(i) == NewWndProc)
624 {
625 chWndProc = GETPFNSERVER(i);
626 break;
627 }
628 }
629 // If match, set/reset to Server Side and clear ansi.
630 if (chWndProc)
631 {
632 pWnd->lpfnWndProc = chWndProc;
633 pWnd->Unicode = TRUE;
634 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
635 pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
636 }
637 else
638 {
639 pWnd->Unicode = !Ansi;
640 // Handle the state change in here.
641 if (Ansi)
642 pWnd->state |= WNDS_ANSIWINDOWPROC;
643 else
644 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
645
646 if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
647 pWnd->state &= ~WNDS_SERVERSIDEWINDOWPROC;
648
649 if (!NewWndProc) NewWndProc = pWnd->lpfnWndProc;
650
651 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
652 {
653 if (Ansi)
654 {
655 if (GETPFNCLIENTW(Class->fnid) == NewWndProc)
656 chWndProc = GETPFNCLIENTA(Class->fnid);
657 }
658 else
659 {
660 if (GETPFNCLIENTA(Class->fnid) == NewWndProc)
661 chWndProc = GETPFNCLIENTW(Class->fnid);
662 }
663 }
664 // Now set the new window proc.
665 pWnd->lpfnWndProc = (chWndProc ? chWndProc : NewWndProc);
666 }
667 return Ret;
668 }
669
670 // Move this to user space!
671 BOOL FASTCALL
672 IntGetWindowInfo(PWINDOW_OBJECT Window, PWINDOWINFO pwi)
673 {
674 PWND Wnd = Window->Wnd;
675
676 pwi->cbSize = sizeof(WINDOWINFO);
677 pwi->rcWindow = Window->Wnd->rcWindow;
678 pwi->rcClient = Window->Wnd->rcClient;
679 pwi->dwStyle = Wnd->style;
680 pwi->dwExStyle = Wnd->ExStyle;
681 pwi->dwWindowStatus = (UserGetForegroundWindow() == Window->hSelf); /* WS_ACTIVECAPTION */
682 IntGetWindowBorderMeasures(Window, &pwi->cxWindowBorders, &pwi->cyWindowBorders);
683 pwi->atomWindowType = (Wnd->pcls ? Wnd->pcls->atomClassName : 0);
684 pwi->wCreatorVersion = 0x400; /* FIXME - return a real version number */
685 return TRUE;
686 }
687
688 static BOOL FASTCALL
689 IntSetMenu(
690 PWINDOW_OBJECT Window,
691 HMENU Menu,
692 BOOL *Changed)
693 {
694 PMENU_OBJECT OldMenu, NewMenu = NULL;
695 PWND Wnd = Window->Wnd;
696
697 if ((Wnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
698 {
699 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
700 return FALSE;
701 }
702
703 *Changed = (Wnd->IDMenu != (UINT) Menu);
704 if (! *Changed)
705 {
706 return TRUE;
707 }
708
709 if (Wnd->IDMenu)
710 {
711 OldMenu = IntGetMenuObject((HMENU) Wnd->IDMenu);
712 ASSERT(NULL == OldMenu || OldMenu->MenuInfo.Wnd == Window->hSelf);
713 }
714 else
715 {
716 OldMenu = NULL;
717 }
718
719 if (NULL != Menu)
720 {
721 NewMenu = IntGetMenuObject(Menu);
722 if (NULL == NewMenu)
723 {
724 if (NULL != OldMenu)
725 {
726 IntReleaseMenuObject(OldMenu);
727 }
728 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
729 return FALSE;
730 }
731 if (NULL != NewMenu->MenuInfo.Wnd)
732 {
733 /* Can't use the same menu for two windows */
734 if (NULL != OldMenu)
735 {
736 IntReleaseMenuObject(OldMenu);
737 }
738 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
739 return FALSE;
740 }
741
742 }
743
744 Wnd->IDMenu = (UINT) Menu;
745 if (NULL != NewMenu)
746 {
747 NewMenu->MenuInfo.Wnd = Window->hSelf;
748 IntReleaseMenuObject(NewMenu);
749 }
750 if (NULL != OldMenu)
751 {
752 OldMenu->MenuInfo.Wnd = NULL;
753 IntReleaseMenuObject(OldMenu);
754 }
755
756 return TRUE;
757 }
758
759
760 /* INTERNAL ******************************************************************/
761
762
763 VOID FASTCALL
764 co_DestroyThreadWindows(struct _ETHREAD *Thread)
765 {
766 PTHREADINFO WThread;
767 PLIST_ENTRY Current;
768 PWINDOW_OBJECT Wnd;
769 USER_REFERENCE_ENTRY Ref;
770 WThread = (PTHREADINFO)Thread->Tcb.Win32Thread;
771
772 while (!IsListEmpty(&WThread->WindowListHead))
773 {
774 Current = WThread->WindowListHead.Flink;
775 Wnd = CONTAINING_RECORD(Current, WINDOW_OBJECT, ThreadListEntry);
776
777 DPRINT("thread cleanup: while destroy wnds, wnd=0x%x\n",Wnd);
778
779 /* window removes itself from the list */
780
781 /*
782 fixme: it is critical that the window removes itself! if now, we will loop
783 here forever...
784 */
785
786 //ASSERT(co_UserDestroyWindow(Wnd));
787
788 UserRefObjectCo(Wnd, &Ref);//faxme: temp hack??
789 if (!co_UserDestroyWindow(Wnd))
790 {
791 DPRINT1("Unable to destroy window 0x%x at thread cleanup... This is _VERY_ bad!\n", Wnd);
792 }
793 UserDerefObjectCo(Wnd);//faxme: temp hack??
794 }
795 }
796
797
798
799 /*!
800 * Internal function.
801 * Returns client window rectangle relative to the upper-left corner of client area.
802 *
803 * \note Does not check the validity of the parameters
804 */
805 VOID FASTCALL
806 IntGetClientRect(PWINDOW_OBJECT Window, RECTL *Rect)
807 {
808 ASSERT( Window );
809 ASSERT( Rect );
810
811 Rect->left = Rect->top = 0;
812 Rect->right = Window->Wnd->rcClient.right - Window->Wnd->rcClient.left;
813 Rect->bottom = Window->Wnd->rcClient.bottom - Window->Wnd->rcClient.top;
814 }
815
816
817 #if 0
818 HWND FASTCALL
819 IntGetFocusWindow(VOID)
820 {
821 PUSER_MESSAGE_QUEUE Queue;
822 PDESKTOP pdo = IntGetActiveDesktop();
823
824 if( !pdo )
825 return NULL;
826
827 Queue = (PUSER_MESSAGE_QUEUE)pdo->ActiveMessageQueue;
828
829 if (Queue == NULL)
830 return(NULL);
831 else
832 return(Queue->FocusWindow);
833 }
834 #endif
835
836 PMENU_OBJECT FASTCALL
837 IntGetSystemMenu(PWINDOW_OBJECT Window, BOOL bRevert, BOOL RetMenu)
838 {
839 PMENU_OBJECT Menu, NewMenu = NULL, SysMenu = NULL, ret = NULL;
840 PTHREADINFO W32Thread;
841 HMENU hNewMenu, hSysMenu;
842 ROSMENUITEMINFO ItemInfo;
843
844 if(bRevert)
845 {
846 W32Thread = PsGetCurrentThreadWin32Thread();
847
848 if(!W32Thread->rpdesk)
849 return NULL;
850
851 if(Window->SystemMenu)
852 {
853 Menu = UserGetMenuObject(Window->SystemMenu);
854 if(Menu)
855 {
856 IntDestroyMenuObject(Menu, TRUE, TRUE);
857 Window->SystemMenu = (HMENU)0;
858 }
859 }
860
861 if(W32Thread->rpdesk->rpwinstaParent->SystemMenuTemplate)
862 {
863 /* clone system menu */
864 Menu = UserGetMenuObject(W32Thread->rpdesk->rpwinstaParent->SystemMenuTemplate);
865 if(!Menu)
866 return NULL;
867
868 NewMenu = IntCloneMenu(Menu);
869 if(NewMenu)
870 {
871 Window->SystemMenu = NewMenu->MenuInfo.Self;
872 NewMenu->MenuInfo.Flags |= MF_SYSMENU;
873 NewMenu->MenuInfo.Wnd = Window->hSelf;
874 ret = NewMenu;
875 //IntReleaseMenuObject(NewMenu);
876 }
877 }
878 else
879 {
880 hSysMenu = UserCreateMenu(FALSE);
881 if (NULL == hSysMenu)
882 {
883 return NULL;
884 }
885 SysMenu = IntGetMenuObject(hSysMenu);
886 if (NULL == SysMenu)
887 {
888 UserDestroyMenu(hSysMenu);
889 return NULL;
890 }
891 SysMenu->MenuInfo.Flags |= MF_SYSMENU;
892 SysMenu->MenuInfo.Wnd = Window->hSelf;
893 hNewMenu = co_IntLoadSysMenuTemplate();
894 if(!hNewMenu)
895 {
896 IntReleaseMenuObject(SysMenu);
897 UserDestroyMenu(hSysMenu);
898 return NULL;
899 }
900 Menu = IntGetMenuObject(hNewMenu);
901 if(!Menu)
902 {
903 IntReleaseMenuObject(SysMenu);
904 UserDestroyMenu(hSysMenu);
905 return NULL;
906 }
907
908 NewMenu = IntCloneMenu(Menu);
909 if(NewMenu)
910 {
911 NewMenu->MenuInfo.Flags |= MF_SYSMENU | MF_POPUP;
912 IntReleaseMenuObject(NewMenu);
913 UserSetMenuDefaultItem(NewMenu, SC_CLOSE, FALSE);
914
915 ItemInfo.cbSize = sizeof(MENUITEMINFOW);
916 ItemInfo.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_SUBMENU;
917 ItemInfo.fType = MF_POPUP;
918 ItemInfo.fState = MFS_ENABLED;
919 ItemInfo.dwTypeData = NULL;
920 ItemInfo.cch = 0;
921 ItemInfo.hSubMenu = NewMenu->MenuInfo.Self;
922 IntInsertMenuItem(SysMenu, (UINT) -1, TRUE, &ItemInfo);
923
924 Window->SystemMenu = SysMenu->MenuInfo.Self;
925
926 ret = SysMenu;
927 }
928 IntDestroyMenuObject(Menu, FALSE, TRUE);
929 }
930 if(RetMenu)
931 return ret;
932 else
933 return NULL;
934 }
935 else
936 {
937 if(Window->SystemMenu)
938 return IntGetMenuObject((HMENU)Window->SystemMenu);
939 else
940 return NULL;
941 }
942 }
943
944
945 BOOL FASTCALL
946 IntIsChildWindow(PWINDOW_OBJECT Parent, PWINDOW_OBJECT BaseWindow)
947 {
948 PWINDOW_OBJECT Window;
949 PWND Wnd;
950
951 Window = BaseWindow;
952 while (Window)
953 {
954 Wnd = Window->Wnd;
955 if (Window == Parent)
956 {
957 return(TRUE);
958 }
959 if(!(Wnd->style & WS_CHILD))
960 {
961 break;
962 }
963
964 Window = Window->spwndParent;
965 }
966
967 return(FALSE);
968 }
969
970 BOOL FASTCALL
971 IntIsWindowVisible(PWINDOW_OBJECT BaseWindow)
972 {
973 PWINDOW_OBJECT Window;
974 PWND Wnd;
975
976 Window = BaseWindow;
977 while(Window)
978 {
979 Wnd = Window->Wnd;
980 if(!(Wnd->style & WS_CHILD))
981 {
982 break;
983 }
984 if(!(Wnd->style & WS_VISIBLE))
985 {
986 return FALSE;
987 }
988
989 Window = Window->spwndParent;
990 }
991
992 if(Window && Wnd->style & WS_VISIBLE)
993 {
994 return TRUE;
995 }
996
997 return FALSE;
998 }
999
1000 VOID FASTCALL
1001 IntLinkWnd(
1002 PWND Wnd,
1003 PWND WndParent,
1004 PWND WndPrevSibling) /* set to NULL if top sibling */
1005 {
1006 Wnd->spwndParent = WndParent;
1007 if ((Wnd->spwndPrev = WndPrevSibling))
1008 {
1009 /* link after WndPrevSibling */
1010 if ((Wnd->spwndNext = WndPrevSibling->spwndNext))
1011 Wnd->spwndNext->spwndPrev = Wnd;
1012
1013 Wnd->spwndPrev->spwndNext = Wnd;
1014 }
1015 else
1016 {
1017 /* link at top */
1018 if ((Wnd->spwndNext = WndParent->spwndChild))
1019 Wnd->spwndNext->spwndPrev = Wnd;
1020
1021 WndParent->spwndChild = Wnd;
1022 }
1023
1024 }
1025
1026 /* link the window into siblings and parent. children are kept in place. */
1027 VOID FASTCALL
1028 IntLinkWindow(
1029 PWINDOW_OBJECT Wnd,
1030 PWINDOW_OBJECT WndParent,
1031 PWINDOW_OBJECT WndPrevSibling /* set to NULL if top sibling */
1032 )
1033 {
1034 PWINDOW_OBJECT Parent;
1035
1036 IntLinkWnd(Wnd->Wnd,
1037 WndParent->Wnd,
1038 WndPrevSibling ? WndPrevSibling->Wnd : NULL);
1039
1040 Wnd->spwndParent = WndParent;
1041 if ((Wnd->spwndPrev = WndPrevSibling))
1042 {
1043 /* link after WndPrevSibling */
1044 if ((Wnd->spwndNext = WndPrevSibling->spwndNext))
1045 Wnd->spwndNext->spwndPrev = Wnd;
1046 Wnd->spwndPrev->spwndNext = Wnd;
1047 }
1048 else
1049 {
1050 /* link at top */
1051 Parent = Wnd->spwndParent;
1052 if ((Wnd->spwndNext = WndParent->spwndChild))
1053 Wnd->spwndNext->spwndPrev = Wnd;
1054 else if (Parent)
1055 {
1056 Parent->spwndChild = Wnd;
1057 return;
1058 }
1059 if(Parent)
1060 {
1061 Parent->spwndChild = Wnd;
1062 }
1063 }
1064
1065 }
1066
1067 HWND FASTCALL
1068 IntSetOwner(HWND hWnd, HWND hWndNewOwner)
1069 {
1070 PWINDOW_OBJECT Wnd, WndOldOwner, WndNewOwner;
1071 HWND ret;
1072
1073 Wnd = IntGetWindowObject(hWnd);
1074 if(!Wnd)
1075 return NULL;
1076
1077 WndOldOwner = Wnd->spwndOwner;
1078
1079 ret = WndOldOwner ? WndOldOwner->hSelf : 0;
1080
1081 if((WndNewOwner = UserGetWindowObject(hWndNewOwner)))
1082 {
1083 Wnd->spwndOwner= WndNewOwner;
1084 Wnd->Wnd->spwndOwner = WndNewOwner->Wnd;
1085 }
1086 else
1087 {
1088 Wnd->spwndOwner = NULL;
1089 Wnd->Wnd->spwndOwner = NULL;
1090 }
1091
1092 UserDereferenceObject(Wnd);
1093 return ret;
1094 }
1095
1096 PWINDOW_OBJECT FASTCALL
1097 co_IntSetParent(PWINDOW_OBJECT Wnd, PWINDOW_OBJECT WndNewParent)
1098 {
1099 PWINDOW_OBJECT WndOldParent, Sibling, InsertAfter;
1100 // HWND hWnd, hWndNewParent;
1101 BOOL WasVisible;
1102
1103 ASSERT(Wnd);
1104 ASSERT(WndNewParent);
1105 ASSERT_REFS_CO(Wnd);
1106 ASSERT_REFS_CO(WndNewParent);
1107
1108 // hWnd = Wnd->hSelf;
1109 // hWndNewParent = WndNewParent->hSelf;
1110
1111 /* Some applications try to set a child as a parent */
1112 if (IntIsChildWindow(Wnd, WndNewParent))
1113 {
1114 SetLastWin32Error( ERROR_INVALID_PARAMETER );
1115 return NULL;
1116 }
1117
1118 /*
1119 * Windows hides the window first, then shows it again
1120 * including the WM_SHOWWINDOW messages and all
1121 */
1122 WasVisible = co_WinPosShowWindow(Wnd, SW_HIDE);
1123
1124 // /* Validate that window and parent still exist */
1125 // if (!IntIsWindow(hWnd) || !IntIsWindow(hWndNewParent))
1126 // return NULL;
1127
1128 /* Window must belong to current process */
1129 if (Wnd->pti->pEThread->ThreadsProcess != PsGetCurrentProcess())
1130 return NULL;
1131
1132 WndOldParent = Wnd->spwndParent;
1133
1134 if (WndOldParent) UserReferenceObject(WndOldParent); /* caller must deref */
1135
1136 if (WndNewParent != WndOldParent)
1137 {
1138 IntUnlinkWindow(Wnd);
1139 InsertAfter = NULL;
1140 if (0 == (Wnd->Wnd->ExStyle & WS_EX_TOPMOST))
1141 {
1142 /* Not a TOPMOST window, put after TOPMOSTs of new parent */
1143 Sibling = WndNewParent->spwndChild;
1144 while (NULL != Sibling && 0 != (Sibling->Wnd->ExStyle & WS_EX_TOPMOST))
1145 {
1146 InsertAfter = Sibling;
1147 Sibling = Sibling->spwndNext;
1148 }
1149 }
1150 if (NULL == InsertAfter)
1151 {
1152 IntLinkWindow(Wnd, WndNewParent, InsertAfter /*prev sibling*/);
1153 }
1154 else
1155 {
1156 // UserReferenceObject(InsertAfter);
1157 IntLinkWindow(Wnd, WndNewParent, InsertAfter /*prev sibling*/);
1158 // UserDereferenceObject(InsertAfter);
1159 }
1160 }
1161
1162 /*
1163 * SetParent additionally needs to make hwnd the top window
1164 * in the z-order and send the expected WM_WINDOWPOSCHANGING and
1165 * WM_WINDOWPOSCHANGED notification messages.
1166 */
1167 co_WinPosSetWindowPos(Wnd, (0 == (Wnd->Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOP : HWND_TOPMOST),
1168 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE
1169 | (WasVisible ? SWP_SHOWWINDOW : 0));
1170
1171 /*
1172 * FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
1173 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE
1174 */
1175
1176 /*
1177 * Validate that the old parent still exist, since it migth have been
1178 * destroyed during the last callbacks to user-mode
1179 */
1180 // if(WndOldParent)
1181 // {
1182 // if(!IntIsWindow(WndOldParent->hSelf))
1183 // {
1184 // UserDereferenceObject(WndOldParent);
1185 // return NULL;
1186 // }
1187
1188 /* don't dereference the window object here, it must be done by the caller
1189 of IntSetParent() */
1190 // return WndOldParent;
1191 // }
1192
1193 return WndOldParent;//NULL;
1194 }
1195
1196 BOOL FASTCALL
1197 IntSetSystemMenu(PWINDOW_OBJECT Window, PMENU_OBJECT Menu)
1198 {
1199 PMENU_OBJECT OldMenu;
1200 if(Window->SystemMenu)
1201 {
1202 OldMenu = IntGetMenuObject(Window->SystemMenu);
1203 if(OldMenu)
1204 {
1205 OldMenu->MenuInfo.Flags &= ~ MF_SYSMENU;
1206 IntReleaseMenuObject(OldMenu);
1207 }
1208 }
1209
1210 if(Menu)
1211 {
1212 /* FIXME check window style, propably return FALSE ? */
1213 Window->SystemMenu = Menu->MenuInfo.Self;
1214 Menu->MenuInfo.Flags |= MF_SYSMENU;
1215 }
1216 else
1217 Window->SystemMenu = (HMENU)0;
1218
1219 return TRUE;
1220 }
1221
1222 /* unlink the window from siblings and parent. children are kept in place. */
1223 VOID FASTCALL
1224 IntUnlinkWnd(PWND Wnd)
1225 {
1226 if (Wnd->spwndNext)
1227 Wnd->spwndNext->spwndPrev = Wnd->spwndPrev;
1228
1229 if (Wnd->spwndPrev)
1230 Wnd->spwndPrev->spwndNext = Wnd->spwndNext;
1231
1232 if (Wnd->spwndParent && Wnd->spwndParent->spwndChild == Wnd)
1233 Wnd->spwndParent->spwndChild = Wnd->spwndNext;
1234
1235 Wnd->spwndPrev = Wnd->spwndNext = Wnd->spwndParent = NULL;
1236 }
1237
1238
1239 /* unlink the window from siblings and parent. children are kept in place. */
1240 VOID FASTCALL
1241 IntUnlinkWindow(PWINDOW_OBJECT Wnd)
1242 {
1243 PWINDOW_OBJECT WndParent = Wnd->spwndParent;
1244
1245 IntUnlinkWnd(Wnd->Wnd);
1246
1247 if (Wnd->spwndNext)
1248 Wnd->spwndNext->spwndPrev = Wnd->spwndPrev;
1249
1250 if (Wnd->spwndPrev)
1251 Wnd->spwndPrev->spwndNext = Wnd->spwndNext;
1252 else if (WndParent && WndParent->spwndChild == Wnd)
1253 WndParent->spwndChild = Wnd->spwndNext;
1254
1255 Wnd->spwndPrev = Wnd->spwndNext = Wnd->spwndParent = NULL;
1256 }
1257
1258 BOOL FASTCALL
1259 IntIsWindowInDestroy(PWINDOW_OBJECT Window)
1260 {
1261 return ((Window->state & WINDOWSTATUS_DESTROYING) == WINDOWSTATUS_DESTROYING);
1262 }
1263
1264
1265 BOOL
1266 FASTCALL
1267 IntGetWindowPlacement(PWINDOW_OBJECT Window, WINDOWPLACEMENT *lpwndpl)
1268 {
1269 PWND Wnd;
1270 POINT Size;
1271
1272 Wnd = Window->Wnd;
1273 if (!Wnd) return FALSE;
1274
1275 if(lpwndpl->length != sizeof(WINDOWPLACEMENT))
1276 {
1277 return FALSE;
1278 }
1279
1280 lpwndpl->flags = 0;
1281 if (0 == (Wnd->style & WS_VISIBLE))
1282 {
1283 lpwndpl->showCmd = SW_HIDE;
1284 }
1285 else if (0 != (Window->state & WINDOWOBJECT_RESTOREMAX) ||
1286 0 != (Wnd->style & WS_MAXIMIZE))
1287 {
1288 lpwndpl->showCmd = SW_MAXIMIZE;
1289 }
1290 else if (0 != (Wnd->style & WS_MINIMIZE))
1291 {
1292 lpwndpl->showCmd = SW_MINIMIZE;
1293 }
1294 else if (0 != (Wnd->style & WS_VISIBLE))
1295 {
1296 lpwndpl->showCmd = SW_SHOWNORMAL;
1297 }
1298
1299 Size.x = Wnd->rcWindow.left;
1300 Size.y = Wnd->rcWindow.top;
1301 WinPosInitInternalPos(Window, &Size,
1302 &Wnd->rcWindow);
1303
1304 lpwndpl->rcNormalPosition = Wnd->InternalPos.NormalRect;
1305 lpwndpl->ptMinPosition = Wnd->InternalPos.IconPos;
1306 lpwndpl->ptMaxPosition = Wnd->InternalPos.MaxPos;
1307
1308 return TRUE;
1309 }
1310
1311
1312 /* FUNCTIONS *****************************************************************/
1313
1314 /*
1315 * @unimplemented
1316 */
1317 DWORD APIENTRY
1318 NtUserAlterWindowStyle(DWORD Unknown0,
1319 DWORD Unknown1,
1320 DWORD Unknown2)
1321 {
1322 UNIMPLEMENTED
1323
1324 return(0);
1325 }
1326
1327 /*
1328 * As best as I can figure, this function is used by EnumWindows,
1329 * EnumChildWindows, EnumDesktopWindows, & EnumThreadWindows.
1330 *
1331 * It's supposed to build a list of HWNDs to return to the caller.
1332 * We can figure out what kind of list by what parameters are
1333 * passed to us.
1334 */
1335 /*
1336 * @implemented
1337 */
1338 NTSTATUS
1339 APIENTRY
1340 NtUserBuildHwndList(
1341 HDESK hDesktop,
1342 HWND hwndParent,
1343 BOOLEAN bChildren,
1344 ULONG dwThreadId,
1345 ULONG lParam,
1346 HWND* pWnd,
1347 ULONG* pBufSize)
1348 {
1349 NTSTATUS Status;
1350 ULONG dwCount = 0;
1351
1352 if (pBufSize == 0)
1353 return ERROR_INVALID_PARAMETER;
1354
1355 if (hwndParent || !dwThreadId)
1356 {
1357 PDESKTOP Desktop;
1358 PWINDOW_OBJECT Parent, Window;
1359
1360 if(!hwndParent)
1361 {
1362 if(hDesktop == NULL && !(Desktop = IntGetActiveDesktop()))
1363 {
1364 return ERROR_INVALID_HANDLE;
1365 }
1366
1367 if(hDesktop)
1368 {
1369 Status = IntValidateDesktopHandle(hDesktop,
1370 UserMode,
1371 0,
1372 &Desktop);
1373 if(!NT_SUCCESS(Status))
1374 {
1375 return ERROR_INVALID_HANDLE;
1376 }
1377 }
1378 hwndParent = Desktop->DesktopWindow;
1379 }
1380 else
1381 {
1382 hDesktop = 0;
1383 }
1384
1385 if((Parent = UserGetWindowObject(hwndParent)) &&
1386 (Window = Parent->spwndChild))
1387 {
1388 BOOL bGoDown = TRUE;
1389
1390 Status = STATUS_SUCCESS;
1391 while(TRUE)
1392 {
1393 if (bGoDown)
1394 {
1395 if(dwCount++ < *pBufSize && pWnd)
1396 {
1397 _SEH2_TRY
1398 {
1399 ProbeForWrite(pWnd, sizeof(HWND), 1);
1400 *pWnd = Window->hSelf;
1401 pWnd++;
1402 }
1403 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1404 {
1405 Status = _SEH2_GetExceptionCode();
1406 }
1407 _SEH2_END
1408 if(!NT_SUCCESS(Status))
1409 {
1410 SetLastNtError(Status);
1411 break;
1412 }
1413 }
1414 if (Window->spwndChild && bChildren)
1415 {
1416 Window = Window->spwndChild;
1417 continue;
1418 }
1419 bGoDown = FALSE;
1420 }
1421 if (Window->spwndNext)
1422 {
1423 Window = Window->spwndNext;
1424 bGoDown = TRUE;
1425 continue;
1426 }
1427 Window = Window->spwndParent;
1428 if (Window == Parent)
1429 {
1430 break;
1431 }
1432 }
1433 }
1434
1435 if(hDesktop)
1436 {
1437 ObDereferenceObject(Desktop);
1438 }
1439 }
1440 else
1441 {
1442 PETHREAD Thread;
1443 PTHREADINFO W32Thread;
1444 PLIST_ENTRY Current;
1445 PWINDOW_OBJECT Window;
1446
1447 Status = PsLookupThreadByThreadId((HANDLE)dwThreadId, &Thread);
1448 if(!NT_SUCCESS(Status))
1449 {
1450 return ERROR_INVALID_PARAMETER;
1451 }
1452 if(!(W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread))
1453 {
1454 ObDereferenceObject(Thread);
1455 DPRINT("Thread is not a GUI Thread!\n");
1456 return ERROR_INVALID_PARAMETER;
1457 }
1458
1459 Current = W32Thread->WindowListHead.Flink;
1460 while(Current != &(W32Thread->WindowListHead))
1461 {
1462 Window = CONTAINING_RECORD(Current, WINDOW_OBJECT, ThreadListEntry);
1463 ASSERT(Window);
1464
1465 if(bChildren || Window->spwndOwner != NULL)
1466 {
1467 if(dwCount < *pBufSize && pWnd)
1468 {
1469 Status = MmCopyToCaller(pWnd++, &Window->hSelf, sizeof(HWND));
1470 if(!NT_SUCCESS(Status))
1471 {
1472 SetLastNtError(Status);
1473 break;
1474 }
1475 }
1476 dwCount++;
1477 }
1478 Current = Current->Flink;
1479 }
1480
1481 ObDereferenceObject(Thread);
1482 }
1483
1484 *pBufSize = dwCount;
1485 return STATUS_SUCCESS;
1486 }
1487
1488
1489 /*
1490 * @implemented
1491 */
1492 HWND APIENTRY
1493 NtUserChildWindowFromPointEx(HWND hwndParent,
1494 LONG x,
1495 LONG y,
1496 UINT uiFlags)
1497 {
1498 PWINDOW_OBJECT Parent;
1499 POINTL Pt;
1500 HWND Ret;
1501 HWND *List, *phWnd;
1502
1503 if(!(Parent = UserGetWindowObject(hwndParent)))
1504 {
1505 return NULL;
1506 }
1507
1508 Pt.x = x;
1509 Pt.y = y;
1510
1511 if(Parent->hSelf != IntGetDesktopWindow())
1512 {
1513 Pt.x += Parent->Wnd->rcClient.left;
1514 Pt.y += Parent->Wnd->rcClient.top;
1515 }
1516
1517 if(!IntPtInWindow(Parent, Pt.x, Pt.y))
1518 {
1519 return NULL;
1520 }
1521
1522 Ret = Parent->hSelf;
1523 if((List = IntWinListChildren(Parent)))
1524 {
1525 for(phWnd = List; *phWnd; phWnd++)
1526 {
1527 PWINDOW_OBJECT Child;
1528 PWND ChildWnd;
1529 if((Child = UserGetWindowObject(*phWnd)))
1530 {
1531 ChildWnd = Child->Wnd;
1532 if(!(ChildWnd->style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE))
1533 {
1534 continue;
1535 }
1536 if((ChildWnd->style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED))
1537 {
1538 continue;
1539 }
1540 if((ChildWnd->ExStyle & WS_EX_TRANSPARENT) && (uiFlags & CWP_SKIPTRANSPARENT))
1541 {
1542 continue;
1543 }
1544 if(IntPtInWindow(Child, Pt.x, Pt.y))
1545 {
1546 Ret = Child->hSelf;
1547 break;
1548 }
1549 }
1550 }
1551 ExFreePool(List);
1552 }
1553
1554 return Ret;
1555 }
1556
1557 void FASTCALL
1558 IntFixWindowCoordinates(CREATESTRUCTW* Cs, PWINDOW_OBJECT ParentWindow, DWORD* dwShowMode)
1559 {
1560 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1561
1562 /* default positioning for overlapped windows */
1563 if(!(Cs->style & (WS_POPUP | WS_CHILD)))
1564 {
1565 RECTL WorkArea;
1566 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
1567
1568 UserSystemParametersInfo(SPI_GETWORKAREA, 0, &WorkArea, 0);
1569
1570 ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
1571
1572 if (IS_DEFAULT(Cs->x))
1573 {
1574 if (!IS_DEFAULT(Cs->y)) *dwShowMode = Cs->y;
1575
1576 if(ProcessParams->WindowFlags & STARTF_USEPOSITION)
1577 {
1578 Cs->x = ProcessParams->StartingX;
1579 Cs->y = ProcessParams->StartingY;
1580 }
1581 else
1582 {
1583 Cs->x = WorkArea.left;
1584 Cs->y = WorkArea.top;
1585 }
1586 }
1587
1588 if (IS_DEFAULT(Cs->cx))
1589 {
1590 if (ProcessParams->WindowFlags & STARTF_USEPOSITION)
1591 {
1592 Cs->cx = ProcessParams->CountX;
1593 Cs->cy = ProcessParams->CountY;
1594 }
1595 else
1596 {
1597 Cs->cx = (WorkArea.right - WorkArea.left) * 3 / 4 - Cs->x;
1598 Cs->cy = (WorkArea.bottom - WorkArea.top) * 3 / 4 - Cs->y;
1599 }
1600 }
1601 /* neither x nor cx are default. Check the y values .
1602 * In the trace we see Outlook and Outlook Express using
1603 * cy set to CW_USEDEFAULT when opening the address book.
1604 */
1605 else if (IS_DEFAULT(Cs->cy))
1606 {
1607 DPRINT("Strange use of CW_USEDEFAULT in nHeight\n");
1608 Cs->cy = (WorkArea.bottom - WorkArea.top) * 3 / 4 - Cs->y;
1609 }
1610 }
1611 else
1612 {
1613 /* if CW_USEDEFAULT is set for non-overlapped windows, both values are set to zero */
1614 if(IS_DEFAULT(Cs->x))
1615 {
1616 Cs->x = 0;
1617 Cs->y = 0;
1618 }
1619 if(IS_DEFAULT(Cs->cx))
1620 {
1621 Cs->cx = 0;
1622 Cs->cy = 0;
1623 }
1624 }
1625
1626 #undef IS_DEFAULT
1627 }
1628
1629 /* Allocates and initializes a window*/
1630 PWINDOW_OBJECT FASTCALL IntCreateWindow(CREATESTRUCTW* Cs,
1631 PLARGE_STRING WindowName,
1632 PCLS Class,
1633 PWINDOW_OBJECT ParentWindow,
1634 PWINDOW_OBJECT OwnerWindow)
1635 {
1636 PWND Wnd = NULL;
1637 PWINDOW_OBJECT Window;
1638 HWND hWnd;
1639 PTHREADINFO pti = NULL;
1640 PMENU_OBJECT SystemMenu;
1641 BOOL MenuChanged;
1642 BOOL bUnicodeWindow;
1643
1644 pti = PsGetCurrentThreadWin32Thread();
1645
1646 /* Automatically add WS_EX_WINDOWEDGE */
1647 if ((Cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1648 ((!(Cs->dwExStyle & WS_EX_STATICEDGE)) &&
1649 (Cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1650 Cs->dwExStyle |= WS_EX_WINDOWEDGE;
1651 else
1652 Cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1653
1654 /* Is it a unicode window? */
1655 bUnicodeWindow =!(Cs->dwExStyle & WS_EX_SETANSICREATOR);
1656 Cs->dwExStyle &= ~WS_EX_SETANSICREATOR;
1657
1658 /* Allocate the new window */
1659 Window = (PWINDOW_OBJECT) UserCreateObject( gHandleTable,
1660 pti->rpdesk,
1661 (PHANDLE)&hWnd,
1662 otWindow,
1663 sizeof(WINDOW_OBJECT));
1664 if (!Window)
1665 {
1666 goto AllocError;
1667 }
1668
1669 Wnd = DesktopHeapAlloc(pti->rpdesk, sizeof(WND) + Class->cbwndExtra);
1670
1671 if (!Wnd)
1672 {
1673 goto AllocError;
1674 }
1675
1676 RtlZeroMemory(Wnd, sizeof(WND) + Class->cbwndExtra);
1677
1678 DPRINT("Created object with handle %X\n", hWnd);
1679
1680 if (NULL == pti->rpdesk->DesktopWindow)
1681 {
1682 /* If there is no desktop window yet, we must be creating it */
1683 pti->rpdesk->DesktopWindow = hWnd;
1684 pti->rpdesk->pDeskInfo->spwnd = Wnd;
1685 }
1686
1687 /*
1688 * Fill out the structure describing it.
1689 */
1690 Window->Wnd = Wnd;
1691 Window->pti = pti;
1692 Window->hSelf = hWnd;
1693 Window->spwndParent = ParentWindow;
1694 Window->spwndOwner = OwnerWindow;
1695
1696 Wnd->head.h = hWnd;
1697 Wnd->head.pti = pti;
1698 Wnd->head.rpdesk = pti->rpdesk;
1699 Wnd->fnid = 0;
1700 Wnd->hWndLastActive = hWnd;
1701 Wnd->state2 |= WNDS2_WIN40COMPAT;
1702 Wnd->pcls = Class;
1703 Wnd->hModule = Cs->hInstance;
1704 Wnd->style = Cs->style & ~WS_VISIBLE;
1705 Wnd->ExStyle = Cs->dwExStyle;
1706 Wnd->cbwndExtra = Wnd->pcls->cbwndExtra;
1707 Wnd->spwndOwner = OwnerWindow ? OwnerWindow->Wnd : NULL;
1708 Wnd->spwndParent = ParentWindow ? ParentWindow->Wnd : NULL;
1709
1710 IntReferenceMessageQueue(Window->pti->MessageQueue);
1711 if (Wnd->spwndParent != NULL && Cs->hwndParent != 0)
1712 {
1713 Wnd->HideFocus = Wnd->spwndParent->HideFocus;
1714 Wnd->HideAccel = Wnd->spwndParent->HideAccel;
1715 }
1716
1717 if (Wnd->pcls->CSF_flags & CSF_SERVERSIDEPROC)
1718 Wnd->state |= WNDS_SERVERSIDEWINDOWPROC;
1719
1720 /* BugBoy Comments: Comment below say that System classes are always created
1721 as UNICODE. In windows, creating a window with the ANSI version of CreateWindow
1722 sets the window to ansi as verified by testing with IsUnicodeWindow API.
1723
1724 No where can I see in code or through testing does the window change back
1725 to ANSI after being created as UNICODE in ROS. I didnt do more testing to
1726 see what problems this would cause.*/
1727
1728 // Set WndProc from Class.
1729 Wnd->lpfnWndProc = Wnd->pcls->lpfnWndProc;
1730
1731 // GetWindowProc, test for non server side default classes and set WndProc.
1732 if ( Wnd->pcls->fnid <= FNID_GHOST && Wnd->pcls->fnid >= FNID_BUTTON )
1733 {
1734 if (bUnicodeWindow)
1735 {
1736 if (GETPFNCLIENTA(Wnd->pcls->fnid) == Wnd->lpfnWndProc)
1737 Wnd->lpfnWndProc = GETPFNCLIENTW(Wnd->pcls->fnid);
1738 }
1739 else
1740 {
1741 if (GETPFNCLIENTW(Wnd->pcls->fnid) == Wnd->lpfnWndProc)
1742 Wnd->lpfnWndProc = GETPFNCLIENTA(Wnd->pcls->fnid);
1743 }
1744 }
1745
1746 // If not an Unicode caller, set Ansi creator bit.
1747 if (!bUnicodeWindow) Wnd->state |= WNDS_ANSICREATOR;
1748
1749 // Clone Class Ansi/Unicode proc type.
1750 if (Wnd->pcls->CSF_flags & CSF_ANSIPROC)
1751 {
1752 Wnd->state |= WNDS_ANSIWINDOWPROC;
1753 Wnd->Unicode = FALSE;
1754 }
1755 else
1756 { /*
1757 It seems there can be both an Ansi creator and Unicode Class Window
1758 WndProc, unless the following overriding conditions occur:
1759 */
1760 if ( !bUnicodeWindow &&
1761 ( Class->atomClassName == gpsi->atomSysClass[ICLS_BUTTON] ||
1762 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOBOX] ||
1763 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOLBOX] ||
1764 Class->atomClassName == gpsi->atomSysClass[ICLS_DIALOG] ||
1765 Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT] ||
1766 Class->atomClassName == gpsi->atomSysClass[ICLS_IME] ||
1767 Class->atomClassName == gpsi->atomSysClass[ICLS_LISTBOX] ||
1768 Class->atomClassName == gpsi->atomSysClass[ICLS_MDICLIENT] ||
1769 Class->atomClassName == gpsi->atomSysClass[ICLS_STATIC] ) )
1770 { // Override Class and set the window Ansi WndProc.
1771 Wnd->state |= WNDS_ANSIWINDOWPROC;
1772 Wnd->Unicode = FALSE;
1773 }
1774 else
1775 { // Set the window Unicode WndProc.
1776 Wnd->state &= ~WNDS_ANSIWINDOWPROC;
1777 Wnd->Unicode = TRUE;
1778 }
1779 }
1780
1781 /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx,
1782 then my testing shows that windows (2k and XP) creates a CallProc for it immediately
1783 Dont understand why it does this. */
1784 if (Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT])
1785 {
1786 PCALLPROCDATA CallProc;
1787 //CallProc = CreateCallProc(NULL, Wnd->lpfnWndProc, bUnicodeWindow, Wnd->ti->ppi);
1788 CallProc = CreateCallProc(NULL, Wnd->lpfnWndProc, Wnd->Unicode , Wnd->head.pti->ppi);
1789
1790 if (!CallProc)
1791 {
1792 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1793 DPRINT1("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %x\n",hWnd);
1794 }
1795 else
1796 {
1797 UserAddCallProcToClass(Wnd->pcls, CallProc);
1798 }
1799 }
1800
1801 InitializeListHead(&Wnd->PropListHead);
1802
1803 if ( WindowName->Buffer != NULL && WindowName->Length > 0 )
1804 {
1805 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
1806 WindowName->Length + sizeof(UNICODE_NULL));
1807 if (Wnd->strName.Buffer == NULL)
1808 {
1809 goto AllocError;
1810 }
1811
1812 RtlCopyMemory(Wnd->strName.Buffer, WindowName->Buffer, WindowName->Length);
1813 Wnd->strName.Buffer[WindowName->Length / sizeof(WCHAR)] = L'\0';
1814 Wnd->strName.Length = WindowName->Length;
1815 }
1816
1817 /* Correct the window style. */
1818 if ((Wnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1819 {
1820 Wnd->style |= WS_CLIPSIBLINGS;
1821 if (!(Wnd->style & WS_POPUP))
1822 {
1823 Wnd->style |= WS_CAPTION;
1824 Window->state |= WINDOWOBJECT_NEED_SIZE;
1825 }
1826 }
1827
1828 if ((Wnd->ExStyle & WS_EX_DLGMODALFRAME) ||
1829 (Wnd->style & (WS_DLGFRAME | WS_THICKFRAME)))
1830 Wnd->ExStyle |= WS_EX_WINDOWEDGE;
1831 else
1832 Wnd->ExStyle &= ~WS_EX_WINDOWEDGE;
1833
1834 /* create system menu */
1835 if((Cs->style & WS_SYSMENU) )//&& (dwStyle & WS_CAPTION) == WS_CAPTION)
1836 {
1837 SystemMenu = IntGetSystemMenu(Window, TRUE, TRUE);
1838 if(SystemMenu)
1839 {
1840 Window->SystemMenu = SystemMenu->MenuInfo.Self;
1841 IntReleaseMenuObject(SystemMenu);
1842 }
1843 }
1844
1845 /* Set the window menu */
1846 if ((Cs->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1847 {
1848 if (Cs->hMenu)
1849 IntSetMenu(Window, Cs->hMenu, &MenuChanged);
1850 else if (Wnd->pcls->lpszMenuName) // Take it from the parent.
1851 {
1852 UNICODE_STRING MenuName;
1853 HMENU hMenu;
1854
1855 if (IS_INTRESOURCE(Wnd->pcls->lpszMenuName))
1856 {
1857 MenuName.Length = 0;
1858 MenuName.MaximumLength = 0;
1859 MenuName.Buffer = Wnd->pcls->lpszMenuName;
1860 }
1861 else
1862 {
1863 RtlInitUnicodeString( &MenuName, Wnd->pcls->lpszMenuName);
1864 }
1865 hMenu = co_IntCallLoadMenu( Wnd->pcls->hModule, &MenuName);
1866 if (hMenu) IntSetMenu(Window, hMenu, &MenuChanged);
1867 }
1868 }
1869 else // Not a child
1870 Wnd->IDMenu = (UINT) Cs->hMenu;
1871
1872 /* Insert the window into the thread's window list. */
1873 InsertTailList (&pti->WindowListHead, &Window->ThreadListEntry);
1874
1875 /* Handle "CS_CLASSDC", it is tested first. */
1876 if ( (Wnd->pcls->style & CS_CLASSDC) && !(Wnd->pcls->pdce) )
1877 { /* One DCE per class to have CLASS. */
1878 Wnd->pcls->pdce = DceAllocDCE( Window, DCE_CLASS_DC );
1879 }
1880 else if ( Wnd->pcls->style & CS_OWNDC)
1881 { /* Allocate a DCE for this window. */
1882 DceAllocDCE(Window, DCE_WINDOW_DC);
1883 }
1884
1885 return Window;
1886
1887 AllocError:
1888
1889 if(Window)
1890 UserDereferenceObject(Window);
1891
1892 if(Wnd)
1893 DesktopHeapFree(Wnd->head.rpdesk, Wnd);
1894
1895 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1896 return NULL;
1897 }
1898
1899 /*
1900 * @implemented
1901 */
1902 PWND FASTCALL
1903 co_UserCreateWindowEx(CREATESTRUCTW* Cs,
1904 PUNICODE_STRING ClassName,
1905 PLARGE_STRING WindowName)
1906 {
1907 PWINDOW_OBJECT Window = NULL, ParentWindow = NULL, OwnerWindow;
1908 HWND hWnd, hWndParent, hWndOwner;
1909 DWORD dwStyle;
1910 PWINSTATION_OBJECT WinSta;
1911 PWND Wnd = NULL;
1912 PCLS Class = NULL;
1913 SIZE Size;
1914 POINT MaxPos;
1915 CBT_CREATEWNDW CbtCreate;
1916 LRESULT Result;
1917 USER_REFERENCE_ENTRY ParentRef, Ref;
1918 PTHREADINFO pti;
1919 DWORD dwShowMode = SW_SHOW;
1920 DECLARE_RETURN(PWND);
1921
1922 /* Get the current window station and reference it */
1923 pti = GetW32ThreadInfo();
1924 if (pti == NULL || pti->rpdesk == NULL)
1925 {
1926 DPRINT1("Thread is not attached to a desktop! Cannot create window!\n");
1927 return NULL; //There is nothing to cleanup
1928 }
1929 WinSta = pti->rpdesk->rpwinstaParent;
1930 ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0);
1931
1932 /* Get the class and reference it*/
1933 Class = IntGetAndReferenceClass(ClassName, Cs->hInstance);
1934 if(!Class)
1935 {
1936 DPRINT1("Failed to find class %wZ\n", ClassName);
1937 RETURN(NULL);
1938 }
1939
1940 /* Now find the parent and the owner window */
1941 hWndParent = IntGetDesktopWindow();
1942 hWndOwner = NULL;
1943
1944 if (Cs->hwndParent == HWND_MESSAGE)
1945 {
1946 Cs->hwndParent = hWndParent = IntGetMessageWindow();
1947 }
1948 else if (Cs->hwndParent)
1949 {
1950 if ((Cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1951 hWndOwner = Cs->hwndParent;
1952 else
1953 hWndParent = Cs->hwndParent;
1954 }
1955 else if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1956 {
1957 DPRINT1("Cannot create a child window without a parrent!\n");
1958 SetLastWin32Error(ERROR_TLW_WITH_WSCHILD);
1959 RETURN(NULL); /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1960 }
1961
1962 ParentWindow = hWndParent ? UserGetWindowObject(hWndParent): NULL;
1963 OwnerWindow = hWndOwner ? UserGetWindowObject(hWndOwner): NULL;
1964
1965 /* FIXME: is this correct?*/
1966 if(OwnerWindow)
1967 OwnerWindow = UserGetAncestor(OwnerWindow, GA_ROOT);
1968
1969 /* Fix the position and the size of the window */
1970 if (ParentWindow)
1971 {
1972 UserRefObjectCo(ParentWindow, &ParentRef);
1973 IntFixWindowCoordinates(Cs, ParentWindow, &dwShowMode);
1974 }
1975
1976 /* Allocate and initialize the new window */
1977 Window = IntCreateWindow(Cs,
1978 WindowName,
1979 Class,
1980 ParentWindow,
1981 OwnerWindow);
1982 if(!Window)
1983 {
1984 DPRINT1("IntCreateWindow failed!\n");
1985 RETURN(0);
1986 }
1987
1988 Wnd = Window->Wnd;
1989 hWnd = Window->hSelf;
1990
1991 UserRefObjectCo(Window, &Ref);
1992 ObDereferenceObject(WinSta);
1993
1994 /* Call the WH_CBT hook */
1995 dwStyle = Cs->style;
1996 Cs->style = Wnd->style; /* HCBT_CREATEWND needs the real window style */
1997 CbtCreate.lpcs = Cs;
1998 CbtCreate.hwndInsertAfter = HWND_TOP;
1999 if (ISITHOOKED(WH_CBT))
2000 {
2001 if (co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) &CbtCreate))
2002 {
2003 DPRINT1("HCBT_CREATEWND hook failed!\n");
2004 RETURN( (PWND) NULL);
2005 }
2006 }
2007 Cs->style = dwStyle; /* NCCREATE and WM_NCCALCSIZE need the original values*/
2008
2009 /* Send the WM_GETMINMAXINFO message*/
2010 Size.cx = Cs->cx;
2011 Size.cy = Cs->cy;
2012
2013 if ((dwStyle & WS_THICKFRAME) || !(dwStyle & (WS_POPUP | WS_CHILD)))
2014 {
2015 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
2016
2017 co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack, &MaxTrack);
2018 if (Size.cx > MaxTrack.x) Size.cx = MaxTrack.x;
2019 if (Size.cy > MaxTrack.y) Size.cy = MaxTrack.y;
2020 if (Size.cx < MinTrack.x) Size.cx = MinTrack.x;
2021 if (Size.cy < MinTrack.y) Size.cy = MinTrack.y;
2022 }
2023
2024 Wnd->rcWindow.left = Cs->x;
2025 Wnd->rcWindow.top = Cs->y;
2026 Wnd->rcWindow.right = Cs->x + Size.cx;
2027 Wnd->rcWindow.bottom = Cs->y + Size.cy;
2028 if (0 != (Wnd->style & WS_CHILD) && ParentWindow)
2029 {
2030 RECTL_vOffsetRect(&Wnd->rcWindow,
2031 ParentWindow->Wnd->rcClient.left,
2032 ParentWindow->Wnd->rcClient.top);
2033 }
2034 Wnd->rcClient = Wnd->rcWindow;
2035
2036
2037 /* Link the window*/
2038 if (NULL != ParentWindow)
2039 {
2040 /* link the window into the parent's child list */
2041 if ((dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
2042 {
2043 PWINDOW_OBJECT PrevSibling;
2044
2045 PrevSibling = ParentWindow->spwndChild;
2046
2047 if(PrevSibling)
2048 {
2049 while (PrevSibling->spwndNext)
2050 PrevSibling = PrevSibling->spwndNext;
2051 }
2052
2053 /* link window as bottom sibling */
2054 IntLinkWindow(Window, ParentWindow, PrevSibling /*prev sibling*/);
2055 }
2056 else
2057 {
2058 /* link window as top sibling (but after topmost siblings) */
2059 PWINDOW_OBJECT InsertAfter, Sibling;
2060 if (!(Cs->dwExStyle & WS_EX_TOPMOST))
2061 {
2062 InsertAfter = NULL;
2063 Sibling = ParentWindow->spwndChild;
2064 while (Sibling && (Sibling->Wnd->ExStyle & WS_EX_TOPMOST))
2065 {
2066 InsertAfter = Sibling;
2067 Sibling = Sibling->spwndNext;
2068 }
2069 }
2070 else
2071 {
2072 InsertAfter = NULL;
2073 }
2074
2075 IntLinkWindow(Window, ParentWindow, InsertAfter /* prev sibling */);
2076 }
2077 }
2078
2079 /* Send the NCCREATE message */
2080 Result = co_IntSendMessage(Window->hSelf, WM_NCCREATE, 0, (LPARAM) Cs);
2081 if (!Result)
2082 {
2083 DPRINT1("co_UserCreateWindowEx(): NCCREATE message failed\n");
2084 RETURN((PWND)0);
2085 }
2086
2087 /* Send the WM_NCCALCSIZE message */
2088 MaxPos.x = Window->Wnd->rcWindow.left;
2089 MaxPos.y = Window->Wnd->rcWindow.top;
2090
2091 Result = co_WinPosGetNonClientSize(Window, &Wnd->rcWindow, &Wnd->rcClient);
2092
2093 RECTL_vOffsetRect(&Wnd->rcWindow, MaxPos.x - Wnd->rcWindow.left,
2094 MaxPos.y - Wnd->rcWindow.top);
2095
2096
2097 /* Send the WM_CREATE message. */
2098 Result = co_IntSendMessage(Window->hSelf, WM_CREATE, 0, (LPARAM) Cs);
2099 if (Result == (LRESULT)-1)
2100 {
2101 DPRINT1("co_UserCreateWindowEx(): WM_CREATE message failed\n");
2102 IntUnlinkWindow(Window);
2103 RETURN((PWND)0);
2104 }
2105
2106 /* Send the EVENT_OBJECT_CREATE event*/
2107 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window->Wnd, OBJID_WINDOW, 0);
2108
2109 /* By setting the flag below it can be examined to determine if the window
2110 was created successfully and a valid pwnd was passed back to caller since
2111 from here the function has to succeed. */
2112 Window->Wnd->state2 |= WNDS2_WMCREATEMSGPROCESSED;
2113
2114 /* Send the WM_SIZE and WM_MOVE messages. */
2115 if (!(Window->state & WINDOWOBJECT_NEED_SIZE))
2116 {
2117 co_WinPosSendSizeMove(Window);
2118 }
2119
2120 /* Show or maybe minimize or maximize the window. */
2121 if (Wnd->style & (WS_MINIMIZE | WS_MAXIMIZE))
2122 {
2123 RECTL NewPos;
2124 UINT16 SwFlag;
2125
2126 SwFlag = (Wnd->style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
2127
2128 co_WinPosMinMaximize(Window, SwFlag, &NewPos);
2129
2130 SwFlag = ((Wnd->style & WS_CHILD) || UserGetActiveWindow()) ?
2131 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED :
2132 SWP_NOZORDER | SWP_FRAMECHANGED;
2133
2134 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
2135 NewPos.right, NewPos.bottom, SwFlag);
2136 }
2137
2138 /* Send the WM_PARENTNOTIFY message */
2139 if ((Wnd->style & WS_CHILD) &&
2140 (!(Wnd->ExStyle & WS_EX_NOPARENTNOTIFY)) && ParentWindow)
2141 {
2142 co_IntSendMessage(ParentWindow->hSelf,
2143 WM_PARENTNOTIFY,
2144 MAKEWPARAM(WM_CREATE, Wnd->IDMenu),
2145 (LPARAM)Window->hSelf);
2146 }
2147
2148 /* Notify the shell that a new window was created */
2149 if ((!hWndParent) && (!hWndOwner))
2150 {
2151 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (LPARAM)hWnd);
2152 }
2153
2154 /* Initialize and show the window's scrollbars */
2155 if (Wnd->style & WS_VSCROLL)
2156 {
2157 co_UserShowScrollBar(Window, SB_VERT, TRUE);
2158 }
2159 if (Wnd->style & WS_HSCROLL)
2160 {
2161 co_UserShowScrollBar(Window, SB_HORZ, TRUE);
2162 }
2163
2164 /* Show the new window */
2165 if (Cs->style & WS_VISIBLE)
2166 {
2167 if (Wnd->style & WS_MAXIMIZE)
2168 dwShowMode = SW_SHOW;
2169 else if (Wnd->style & WS_MINIMIZE)
2170 dwShowMode = SW_SHOWMINIMIZED;
2171
2172 co_WinPosShowWindow(Window, dwShowMode);
2173
2174 if (Wnd->ExStyle & WS_EX_MDICHILD)
2175 {
2176 co_IntSendMessage(ParentWindow->hSelf, WM_MDIREFRESHMENU, 0, 0);
2177 /* ShowWindow won't activate child windows */
2178 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2179 }
2180 }
2181
2182 DPRINT("co_UserCreateWindowEx(): Created window %X\n", hWnd);
2183 RETURN( Wnd);
2184
2185 CLEANUP:
2186 if (!_ret_)
2187 {
2188 /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */
2189 if (Window)
2190 co_UserDestroyWindow(Window);
2191 else if (Class)
2192 IntDereferenceClass(Class, pti->pDeskInfo, pti->ppi);
2193 }
2194
2195 if (Window)
2196 {
2197 UserDerefObjectCo(Window);
2198 UserDereferenceObject(Window);
2199 }
2200 if (ParentWindow) UserDerefObjectCo(ParentWindow);
2201
2202 END_CLEANUP;
2203 }
2204
2205 NTSTATUS
2206 NTAPI
2207 ProbeAndCaptureLargeString(
2208 OUT PLARGE_STRING plstrSafe,
2209 IN PLARGE_STRING plstrUnsafe)
2210 {
2211 LARGE_STRING lstrTemp;
2212 PVOID pvBuffer = NULL;
2213
2214 _SEH2_TRY
2215 {
2216 /* Probe and copy the string */
2217 ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
2218 lstrTemp = *plstrUnsafe;
2219 }
2220 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2221 {
2222 /* Fail */
2223 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2224 }
2225 _SEH2_END
2226
2227 if (lstrTemp.Length != 0)
2228 {
2229 /* Allocate a buffer from paged pool */
2230 pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
2231 if (!pvBuffer)
2232 {
2233 return STATUS_NO_MEMORY;
2234 }
2235
2236 _SEH2_TRY
2237 {
2238 /* Probe and copy the buffer */
2239 ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
2240 RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
2241 }
2242 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2243 {
2244 /* Cleanup and fail */
2245 ExFreePool(pvBuffer);
2246 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2247 }
2248 _SEH2_END
2249 }
2250
2251 /* Set the output string */
2252 plstrSafe->Buffer = pvBuffer;
2253 plstrSafe->Length = lstrTemp.Length;
2254 plstrSafe->MaximumLength = lstrTemp.Length;
2255
2256 return STATUS_SUCCESS;
2257 }
2258
2259 /**
2260 * \todo Allow passing plstrClassName as ANSI.
2261 */
2262 HWND
2263 NTAPI
2264 NtUserCreateWindowEx(
2265 DWORD dwExStyle,
2266 PLARGE_STRING plstrClassName,
2267 PLARGE_STRING plstrClsVersion,
2268 PLARGE_STRING plstrWindowName,
2269 DWORD dwStyle,
2270 int x,
2271 int y,
2272 int nWidth,
2273 int nHeight,
2274 HWND hWndParent,
2275 HMENU hMenu,
2276 HINSTANCE hInstance,
2277 LPVOID lpParam,
2278 DWORD dwFlags,
2279 PVOID acbiBuffer)
2280 {
2281 NTSTATUS Status;
2282 LARGE_STRING lstrWindowName;
2283 LARGE_STRING lstrClassName;
2284 UNICODE_STRING ustrClassName;
2285 CREATESTRUCTW Cs;
2286 HWND hwnd = NULL;
2287 PWND pwnd;
2288
2289 lstrWindowName.Buffer = NULL;
2290 lstrClassName.Buffer = NULL;
2291
2292 /* Check if we got a Window name */
2293 if (plstrWindowName)
2294 {
2295 /* Copy the string to kernel mode */
2296 Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
2297 if (!NT_SUCCESS(Status))
2298 {
2299 DPRINT1("NtUserCreateWindowEx: failed to capture plstrWindowName\n");
2300 SetLastNtError(Status);
2301 return NULL;
2302 }
2303 plstrWindowName = &lstrWindowName;
2304 }
2305
2306 /* Check if the class is an atom */
2307 if (IS_ATOM(plstrClassName))
2308 {
2309 /* It is, pass the atom in the UNICODE_STRING */
2310 ustrClassName.Buffer = (PVOID)plstrClassName;
2311 ustrClassName.Length = 0;
2312 ustrClassName.MaximumLength = 0;
2313 }
2314 else
2315 {
2316 /* It's not, capture the class name */
2317 Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
2318 if (!NT_SUCCESS(Status))
2319 {
2320 DPRINT1("NtUserCreateWindowEx: failed to capture plstrClassName\n");
2321 /* Set last error, cleanup and return */
2322 SetLastNtError(Status);
2323 goto cleanup;
2324 }
2325
2326 /* We pass it on as a UNICODE_STRING */
2327 ustrClassName.Buffer = lstrClassName.Buffer;
2328 ustrClassName.Length = lstrClassName.Length;
2329 ustrClassName.MaximumLength = lstrClassName.MaximumLength;
2330 }
2331
2332 /* Fill the CREATESTRUCTW */
2333 /* we will keep here the original parameters */
2334 Cs.style = dwStyle;
2335 Cs.lpCreateParams = lpParam;
2336 Cs.hInstance = hInstance;
2337 Cs.hMenu = hMenu;
2338 Cs.hwndParent = hWndParent;
2339 Cs.cx = nWidth;
2340 Cs.cy = nHeight;
2341 Cs.x = x;
2342 Cs.y = y;
2343 // Cs.lpszName = (LPCWSTR) WindowName->Buffer;
2344 // Cs.lpszClass = (LPCWSTR) ClassName->Buffer;
2345 Cs.lpszName = (LPCWSTR) plstrWindowName;
2346 Cs.lpszClass = (LPCWSTR) &ustrClassName;
2347 Cs.dwExStyle = dwExStyle;
2348
2349 UserEnterExclusive();
2350
2351 /* Call the internal function */
2352 pwnd = co_UserCreateWindowEx(&Cs, &ustrClassName, plstrWindowName);
2353
2354 if(!pwnd)
2355 {
2356 DPRINT1("co_UserCreateWindowEx failed!\n");
2357 }
2358 hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
2359
2360 UserLeave();
2361
2362 cleanup:
2363 if (lstrWindowName.Buffer)
2364 {
2365 ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
2366 }
2367 if (lstrClassName.Buffer)
2368 {
2369 ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
2370 }
2371
2372 return hwnd;
2373 }
2374
2375 /*
2376 * @unimplemented
2377 */
2378 HDWP APIENTRY
2379 NtUserDeferWindowPos(HDWP WinPosInfo,
2380 HWND Wnd,
2381 HWND WndInsertAfter,
2382 int x,
2383 int y,
2384 int cx,
2385 int cy,
2386 UINT Flags)
2387 {
2388 UNIMPLEMENTED
2389
2390 return 0;
2391 }
2392
2393
2394 BOOLEAN FASTCALL co_UserDestroyWindow(PWINDOW_OBJECT Window)
2395 {
2396 BOOLEAN isChild;
2397 PWND Wnd;
2398 HWND hWnd;
2399 PTHREADINFO ti;
2400 MSG msg;
2401
2402 ASSERT_REFS_CO(Window); // FIXME: temp hack?
2403
2404 hWnd = Window->hSelf;
2405
2406 Wnd = Window->Wnd;
2407
2408 if (!Wnd) return TRUE; // FIXME: Need to finish object rewrite or lock the thread when killing the window!
2409
2410 DPRINT("co_UserDestroyWindow \n");
2411
2412 /* Check for owner thread */
2413 if ( (Window->pti->pEThread != PsGetCurrentThread()) ||
2414 Wnd->head.pti != PsGetCurrentThreadWin32Thread() )
2415 {
2416 SetLastWin32Error(ERROR_ACCESS_DENIED);
2417 return FALSE;
2418 }
2419
2420 /* If window was created successfully and it is hooked */
2421 if ((Wnd->state2 & WNDS2_WMCREATEMSGPROCESSED) && (ISITHOOKED(WH_CBT)))
2422 {
2423 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0)) return FALSE;
2424 }
2425
2426 /* Look whether the focus is within the tree of windows we will
2427 * be destroying.
2428 */
2429 if (!co_WinPosShowWindow(Window, SW_HIDE))
2430 {
2431 if (UserGetActiveWindow() == Window->hSelf)
2432 {
2433 co_WinPosActivateOtherWindow(Window);
2434 }
2435 }
2436
2437 if (Window->pti->MessageQueue->ActiveWindow == Window->hSelf)
2438 Window->pti->MessageQueue->ActiveWindow = NULL;
2439 if (Window->pti->MessageQueue->FocusWindow == Window->hSelf)
2440 Window->pti->MessageQueue->FocusWindow = NULL;
2441 if (Window->pti->MessageQueue->CaptureWindow == Window->hSelf)
2442 Window->pti->MessageQueue->CaptureWindow = NULL;
2443
2444 /*
2445 * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
2446 */
2447
2448 ti = PsGetCurrentThreadWin32Thread();
2449
2450 if ((ti != NULL) & (ti->pDeskInfo != NULL))
2451 {
2452 if (ti->pDeskInfo->hShellWindow == hWnd)
2453 {
2454 DPRINT1("Destroying the ShellWindow!\n");
2455 ti->pDeskInfo->hShellWindow = NULL;
2456 }
2457 }
2458
2459 IntDereferenceMessageQueue(Window->pti->MessageQueue);
2460
2461 IntEngWindowChanged(Window, WOC_DELETE);
2462 isChild = (0 != (Wnd->style & WS_CHILD));
2463
2464 #if 0 /* FIXME */
2465
2466 if (isChild)
2467 {
2468 if (! USER_IsExitingThread(GetCurrentThreadId()))
2469 {
2470 send_parent_notify(hwnd, WM_DESTROY);
2471 }
2472 }
2473 else if (NULL != GetWindow(Wnd, GW_OWNER))
2474 {
2475 co_HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
2476 /* FIXME: clean up palette - see "Internals" p.352 */
2477 }
2478 #endif
2479
2480 if (!IntIsWindow(Window->hSelf))
2481 {
2482 return TRUE;
2483 }
2484
2485 /* Recursively destroy owned windows */
2486 if (! isChild)
2487 {
2488 for (;;)
2489 {
2490 BOOL GotOne = FALSE;
2491 HWND *Children;
2492 HWND *ChildHandle;
2493 PWINDOW_OBJECT Child, Desktop;
2494
2495 Desktop = IntIsDesktopWindow(Window) ? Window :
2496 UserGetWindowObject(IntGetDesktopWindow());
2497 Children = IntWinListChildren(Desktop);
2498
2499 if (Children)
2500 {
2501 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
2502 {
2503 Child = UserGetWindowObject(*ChildHandle);
2504 if (Child == NULL)
2505 continue;
2506 if (Child->spwndOwner != Window)
2507 {
2508 continue;
2509 }
2510
2511 if (IntWndBelongsToThread(Child, PsGetCurrentThreadWin32Thread()))
2512 {
2513 USER_REFERENCE_ENTRY ChildRef;
2514 UserRefObjectCo(Child, &ChildRef);//temp hack?
2515 co_UserDestroyWindow(Child);
2516 UserDerefObjectCo(Child);//temp hack?
2517
2518 GotOne = TRUE;
2519 continue;
2520 }
2521
2522 if (Child->spwndOwner != NULL)
2523 {
2524 Child->spwndOwner = NULL;
2525 Child->Wnd->spwndOwner = NULL;
2526 }
2527
2528 }
2529 ExFreePool(Children);
2530 }
2531 if (! GotOne)
2532 {
2533 break;
2534 }
2535 }
2536 }
2537
2538 /* Generate mouse move message for the next window */
2539 msg.message = WM_MOUSEMOVE;
2540 msg.wParam = IntGetSysCursorInfo()->ButtonsDown;
2541 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2542 msg.pt = gpsi->ptCursor;
2543 MsqInsertSystemMessage(&msg);
2544
2545 if (!IntIsWindow(Window->hSelf))
2546 {
2547 return TRUE;
2548 }
2549
2550 /* Destroy the window storage */
2551 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
2552
2553 return TRUE;
2554 }
2555
2556
2557 /*
2558 * @implemented
2559 */
2560 BOOLEAN APIENTRY
2561 NtUserDestroyWindow(HWND Wnd)
2562 {
2563 PWINDOW_OBJECT Window;
2564 DECLARE_RETURN(BOOLEAN);
2565 BOOLEAN ret;
2566 USER_REFERENCE_ENTRY Ref;
2567
2568 DPRINT("Enter NtUserDestroyWindow\n");
2569 UserEnterExclusive();
2570
2571 if (!(Window = UserGetWindowObject(Wnd)))
2572 {
2573 RETURN(FALSE);
2574 }
2575
2576 UserRefObjectCo(Window, &Ref);//faxme: dunno if win should be reffed during destroy..
2577 ret = co_UserDestroyWindow(Window);
2578 UserDerefObjectCo(Window);//faxme: dunno if win should be reffed during destroy..
2579
2580 RETURN(ret);
2581
2582 CLEANUP:
2583 DPRINT("Leave NtUserDestroyWindow, ret=%i\n",_ret_);
2584 UserLeave();
2585 END_CLEANUP;
2586 }
2587
2588
2589
2590 /*
2591 * @unimplemented
2592 */
2593 DWORD
2594 APIENTRY
2595 NtUserDrawMenuBarTemp(
2596 HWND hWnd,
2597 HDC hDC,
2598 PRECT hRect,
2599 HMENU hMenu,
2600 HFONT hFont)
2601 {
2602 /* we'll use this function just for caching the menu bar */
2603 UNIMPLEMENTED
2604 return 0;
2605 }
2606
2607
2608 /*
2609 * @unimplemented
2610 */
2611 DWORD APIENTRY
2612 NtUserEndDeferWindowPosEx(DWORD Unknown0,
2613 DWORD Unknown1)
2614 {
2615 UNIMPLEMENTED
2616
2617 return 0;
2618 }
2619
2620
2621 /*
2622 * FillWindow: Called from User; Dialog, Edit and ListBox procs during a WM_ERASEBKGND.
2623 */
2624 /*
2625 * @unimplemented
2626 */
2627 BOOL APIENTRY
2628 NtUserFillWindow(HWND hWndPaint,
2629 HWND hWndPaint1,
2630 HDC hDC,
2631 HBRUSH hBrush)
2632 {
2633 UNIMPLEMENTED
2634
2635 return 0;
2636 }
2637
2638
2639 static HWND FASTCALL
2640 IntFindWindow(PWINDOW_OBJECT Parent,
2641 PWINDOW_OBJECT ChildAfter,
2642 RTL_ATOM ClassAtom,
2643 PUNICODE_STRING WindowName)
2644 {
2645 BOOL CheckWindowName;
2646 HWND *List, *phWnd;
2647 HWND Ret = NULL;
2648 UNICODE_STRING CurrentWindowName;
2649
2650 ASSERT(Parent);
2651
2652 CheckWindowName = WindowName->Length != 0;
2653
2654 if((List = IntWinListChildren(Parent)))
2655 {
2656 phWnd = List;
2657 if(ChildAfter)
2658 {
2659 /* skip handles before and including ChildAfter */
2660 while(*phWnd && (*(phWnd++) != ChildAfter->hSelf))
2661 ;
2662 }
2663
2664 /* search children */
2665 while(*phWnd)
2666 {
2667 PWINDOW_OBJECT Child;
2668 if(!(Child = UserGetWindowObject(*(phWnd++))))
2669 {
2670 continue;
2671 }
2672
2673 /* Do not send WM_GETTEXT messages in the kernel mode version!
2674 The user mode version however calls GetWindowText() which will
2675 send WM_GETTEXT messages to windows belonging to its processes */
2676 if (!ClassAtom || Child->Wnd->pcls->atomClassName == ClassAtom)
2677 {
2678 // HACK: use UNICODE_STRING instead of LARGE_STRING
2679 CurrentWindowName.Buffer = Child->Wnd->strName.Buffer;
2680 CurrentWindowName.Length = Child->Wnd->strName.Length;
2681 CurrentWindowName.MaximumLength = Child->Wnd->strName.MaximumLength;
2682 if(!CheckWindowName ||
2683 (Child->Wnd->strName.Length < 0xFFFF &&
2684 !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
2685 {
2686 Ret = Child->hSelf;
2687 break;
2688 }
2689 }
2690 }
2691 ExFreePool(List);
2692 }
2693
2694 return Ret;
2695 }
2696
2697 /*
2698 * FUNCTION:
2699 * Searches a window's children for a window with the specified
2700 * class and name
2701 * ARGUMENTS:
2702 * hwndParent = The window whose childs are to be searched.
2703 * NULL = desktop
2704 * HWND_MESSAGE = message-only windows
2705 *
2706 * hwndChildAfter = Search starts after this child window.
2707 * NULL = start from beginning
2708 *
2709 * ucClassName = Class name to search for
2710 * Reguired parameter.
2711 *
2712 * ucWindowName = Window name
2713 * ->Buffer == NULL = don't care
2714 *
2715 * RETURNS:
2716 * The HWND of the window if it was found, otherwise NULL
2717 */
2718 /*
2719 * @implemented
2720 */
2721 HWND APIENTRY
2722 NtUserFindWindowEx(HWND hwndParent,
2723 HWND hwndChildAfter,
2724 PUNICODE_STRING ucClassName,
2725 PUNICODE_STRING ucWindowName,
2726 DWORD dwUnknown)
2727 {
2728 PWINDOW_OBJECT Parent, ChildAfter;
2729 UNICODE_STRING ClassName = {0}, WindowName = {0};
2730 HWND Desktop, Ret = NULL;
2731 RTL_ATOM ClassAtom = (RTL_ATOM)0;
2732 DECLARE_RETURN(HWND);
2733
2734 DPRINT("Enter NtUserFindWindowEx\n");
2735 UserEnterShared();
2736
2737 if (ucClassName != NULL || ucWindowName != NULL)
2738 {
2739 _SEH2_TRY
2740 {
2741 if (ucClassName != NULL)
2742 {
2743 ClassName = ProbeForReadUnicodeString(ucClassName);
2744 if (ClassName.Length != 0)
2745 {
2746 ProbeForRead(ClassName.Buffer,
2747 ClassName.Length,
2748 sizeof(WCHAR));
2749 }
2750 else if (!IS_ATOM(ClassName.Buffer))
2751 {
2752 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2753 _SEH2_LEAVE;
2754 }
2755
2756 if (!IntGetAtomFromStringOrAtom(&ClassName,
2757 &ClassAtom))
2758 {
2759 _SEH2_LEAVE;
2760 }
2761 }
2762
2763 if (ucWindowName != NULL)
2764 {
2765 WindowName = ProbeForReadUnicodeString(ucWindowName);
2766 if (WindowName.Length != 0)
2767 {
2768 ProbeForRead(WindowName.Buffer,
2769 WindowName.Length,
2770 sizeof(WCHAR));
2771 }
2772 }
2773 }
2774 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2775 {
2776 SetLastNtError(_SEH2_GetExceptionCode());
2777 _SEH2_YIELD(RETURN(NULL));
2778 }
2779 _SEH2_END;
2780
2781 if (ucClassName != NULL)
2782 {
2783 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
2784 !IS_ATOM(ClassName.Buffer))
2785 {
2786 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2787 RETURN(NULL);
2788 }
2789 else if (ClassAtom == (RTL_ATOM)0)
2790 {
2791 /* LastError code was set by IntGetAtomFromStringOrAtom */
2792 RETURN(NULL);
2793 }
2794 }
2795 }
2796
2797 Desktop = IntGetCurrentThreadDesktopWindow();
2798
2799 if(hwndParent == NULL)
2800 hwndParent = Desktop;
2801 else if(hwndParent == HWND_MESSAGE)
2802 {
2803 hwndParent = IntGetMessageWindow();
2804 }
2805
2806 if(!(Parent = UserGetWindowObject(hwndParent)))
2807 {
2808 RETURN( NULL);
2809 }
2810
2811 ChildAfter = NULL;
2812 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
2813 {
2814 RETURN( NULL);
2815 }
2816
2817 _SEH2_TRY
2818 {
2819 if(Parent->hSelf == Desktop)
2820 {
2821 HWND *List, *phWnd;
2822 PWINDOW_OBJECT TopLevelWindow;
2823 BOOLEAN CheckWindowName;
2824 BOOLEAN WindowMatches;
2825 BOOLEAN ClassMatches;
2826
2827 /* windows searches through all top-level windows if the parent is the desktop
2828 window */
2829
2830 if((List = IntWinListChildren(Parent)))
2831 {
2832 phWnd = List;
2833
2834 if(ChildAfter)
2835 {
2836 /* skip handles before and including ChildAfter */
2837 while(*phWnd && (*(phWnd++) != ChildAfter->hSelf))
2838 ;
2839 }
2840
2841 CheckWindowName = WindowName.Length != 0;
2842
2843 /* search children */
2844 while(*phWnd)
2845 {
2846 UNICODE_STRING ustr;
2847
2848 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
2849 {
2850 continue;
2851 }
2852
2853 /* Do not send WM_GETTEXT messages in the kernel mode version!
2854 The user mode version however calls GetWindowText() which will
2855 send WM_GETTEXT messages to windows belonging to its processes */
2856 ustr.Buffer = TopLevelWindow->Wnd->strName.Buffer;
2857 ustr.Length = TopLevelWindow->Wnd->strName.Length;
2858 ustr.MaximumLength = TopLevelWindow->Wnd->strName.MaximumLength;
2859 WindowMatches = !CheckWindowName ||
2860 (TopLevelWindow->Wnd->strName.Length < 0xFFFF &&
2861 !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
2862 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
2863 ClassAtom == TopLevelWindow->Wnd->pcls->atomClassName;
2864
2865 if (WindowMatches && ClassMatches)
2866 {
2867 Ret = TopLevelWindow->hSelf;
2868 break;
2869 }
2870
2871 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
2872 {
2873 /* window returns the handle of the top-level window, in case it found
2874 the child window */
2875 Ret = TopLevelWindow->hSelf;
2876 break;
2877 }
2878
2879 }
2880 ExFreePool(List);
2881 }
2882 }
2883 else
2884 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
2885
2886 #if 0
2887
2888 if(Ret == NULL && hwndParent == NULL && hwndChildAfter == NULL)
2889 {
2890 /* FIXME - if both hwndParent and hwndChildAfter are NULL, we also should
2891 search the message-only windows. Should this also be done if
2892 Parent is the desktop window??? */
2893 PWINDOW_OBJECT MsgWindows;
2894
2895 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
2896 {
2897 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
2898 }
2899 }
2900 #endif
2901 }
2902 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2903 {
2904 SetLastNtError(_SEH2_GetExceptionCode());
2905 Ret = NULL;
2906 }
2907 _SEH2_END;
2908
2909 RETURN( Ret);
2910
2911 CLEANUP:
2912 DPRINT("Leave NtUserFindWindowEx, ret %i\n",_ret_);
2913 UserLeave();
2914 END_CLEANUP;
2915 }
2916
2917
2918 /*
2919 * @unimplemented
2920 */
2921 BOOL APIENTRY
2922 NtUserFlashWindowEx(IN PFLASHWINFO pfwi)
2923 {
2924 UNIMPLEMENTED
2925
2926 return 0;
2927 }
2928
2929
2930 /*
2931 * @implemented
2932 */
2933 PWINDOW_OBJECT FASTCALL UserGetAncestor(PWINDOW_OBJECT Wnd, UINT Type)
2934 {
2935 PWINDOW_OBJECT WndAncestor, Parent;
2936
2937 if (Wnd->hSelf == IntGetDesktopWindow())
2938 {
2939 return NULL;
2940 }
2941
2942 switch (Type)
2943 {
2944 case GA_PARENT:
2945 {
2946 WndAncestor = Wnd->spwndParent;
2947 break;
2948 }
2949
2950 case GA_ROOT:
2951 {
2952 WndAncestor = Wnd;
2953 Parent = NULL;
2954
2955 for(;;)
2956 {
2957 if(!(Parent = WndAncestor->spwndParent))
2958 {
2959 break;
2960 }
2961 if(IntIsDesktopWindow(Parent))
2962 {
2963 break;
2964 }
2965
2966 WndAncestor = Parent;
2967 }
2968 break;
2969 }
2970
2971 case GA_ROOTOWNER:
2972 {
2973 WndAncestor = Wnd;
2974
2975 for (;;)
2976 {
2977 PWINDOW_OBJECT Parent;
2978
2979 Parent = IntGetParent(WndAncestor);
2980
2981 if (!Parent)
2982 {
2983 break;
2984 }
2985
2986 WndAncestor = Parent;
2987 }
2988 break;
2989 }
2990
2991 default:
2992 {
2993 return NULL;
2994 }
2995 }
2996
2997 return WndAncestor;
2998 }
2999
3000 /*
3001 * @implemented
3002 */
3003 HWND APIENTRY
3004 NtUserGetAncestor(HWND hWnd, UINT Type)
3005 {
3006 PWINDOW_OBJECT Window, Ancestor;
3007 DECLARE_RETURN(HWND);
3008
3009 DPRINT("Enter NtUserGetAncestor\n");
3010 UserEnterExclusive();
3011
3012 if (!(Window = UserGetWindowObject(hWnd)))
3013 {
3014 RETURN(NULL);
3015 }
3016
3017 Ancestor = UserGetAncestor(Window, Type);
3018 /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3019
3020 RETURN(Ancestor ? Ancestor->hSelf : NULL);
3021
3022 CLEANUP:
3023 DPRINT("Leave NtUserGetAncestor, ret=%i\n",_ret_);
3024 UserLeave();
3025 END_CLEANUP;
3026 }
3027
3028
3029 BOOL
3030 APIENTRY
3031 NtUserGetComboBoxInfo(
3032 HWND hWnd,
3033 PCOMBOBOXINFO pcbi)
3034 {
3035 PWINDOW_OBJECT Wnd;
3036 DECLARE_RETURN(BOOL);
3037
3038 DPRINT("Enter NtUserGetComboBoxInfo\n");
3039 UserEnterShared();
3040
3041 if (!(Wnd = UserGetWindowObject(hWnd)))
3042 {
3043 RETURN( FALSE );
3044 }
3045 _SEH2_TRY
3046 {
3047 if(pcbi)
3048 {
3049 ProbeForWrite(pcbi,
3050 sizeof(COMBOBOXINFO),
3051 1);
3052 }
3053 }
3054 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3055 {
3056 SetLastNtError(_SEH2_GetExceptionCode());
3057 _SEH2_YIELD(RETURN(FALSE));
3058 }
3059 _SEH2_END;
3060
3061 // Pass the user pointer, it was already probed.
3062 RETURN( (BOOL) co_IntSendMessage( Wnd->hSelf, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
3063
3064 CLEANUP:
3065 DPRINT("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
3066 UserLeave();
3067 END_CLEANUP;
3068 }
3069
3070
3071 /*
3072 * @implemented
3073 */
3074 DWORD APIENTRY
3075 NtUserGetInternalWindowPos( HWND hWnd,
3076 LPRECT rectWnd,
3077 LPPOINT ptIcon)
3078 {
3079 PWINDOW_OBJECT Window;
3080 DWORD Ret = 0;
3081 BOOL Hit = FALSE;
3082 WINDOWPLACEMENT wndpl;
3083
3084 UserEnterShared();
3085
3086 if (!(Window = UserGetWindowObject(hWnd)) || !Window->Wnd)
3087 {
3088 Hit = FALSE;
3089 goto Exit;
3090 }
3091
3092 _SEH2_TRY
3093 {
3094 if(rectWnd)
3095 {
3096 ProbeForWrite(rectWnd,
3097 sizeof(RECT),
3098 1);
3099 }
3100 if(ptIcon)
3101 {
3102 ProbeForWrite(ptIcon,
3103 sizeof(POINT),
3104 1);
3105 }
3106
3107 }
3108 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3109 {
3110 SetLastNtError(_SEH2_GetExceptionCode());
3111 Hit = TRUE;
3112 }
3113 _SEH2_END;
3114
3115 wndpl.length = sizeof(WINDOWPLACEMENT);
3116
3117 if (IntGetWindowPlacement(Window, &wndpl) && !Hit)
3118 {
3119 _SEH2_TRY
3120 {
3121 if (rectWnd)
3122 {
3123 RtlCopyMemory(rectWnd, &wndpl.rcNormalPosition , sizeof(RECT));
3124 }
3125 if (ptIcon)
3126 {
3127 RtlCopyMemory(ptIcon, &wndpl.ptMinPosition, sizeof(POINT));
3128 }
3129
3130 }
3131 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3132 {
3133 SetLastNtError(_SEH2_GetExceptionCode());
3134 Hit = TRUE;
3135 }
3136 _SEH2_END;
3137
3138 if (!Hit) Ret = wndpl.showCmd;
3139 }
3140 Exit:
3141 UserLeave();
3142 return Ret;
3143 }
3144
3145 DWORD
3146 APIENTRY
3147 NtUserGetListBoxInfo(
3148 HWND hWnd)
3149 {
3150 PWINDOW_OBJECT Wnd;
3151 DECLARE_RETURN(DWORD);
3152
3153 DPRINT("Enter NtUserGetListBoxInfo\n");
3154 UserEnterShared();
3155
3156 if (!(Wnd = UserGetWindowObject(hWnd)))
3157 {
3158 RETURN( 0 );
3159 }
3160
3161 RETURN( (DWORD) co_IntSendMessage( Wnd->hSelf, LB_GETLISTBOXINFO, 0, 0 ));
3162
3163 CLEANUP:
3164 DPRINT("Leave NtUserGetListBoxInfo, ret=%i\n",_ret_);
3165 UserLeave();
3166 END_CLEANUP;
3167 }
3168
3169
3170 HWND FASTCALL
3171 co_UserSetParent(HWND hWndChild, HWND hWndNewParent)
3172 {
3173 PWINDOW_OBJECT Wnd = NULL, WndParent = NULL, WndOldParent;
3174 HWND hWndOldParent = NULL;
3175 USER_REFERENCE_ENTRY Ref, ParentRef;
3176
3177 if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
3178 {
3179 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3180 return( NULL);
3181 }
3182
3183 if (hWndChild == IntGetDesktopWindow())
3184 {
3185 SetLastWin32Error(ERROR_ACCESS_DENIED);
3186 return( NULL);
3187 }
3188
3189 if (hWndNewParent)
3190 {
3191 if (!(WndParent = UserGetWindowObject(hWndNewParent)))
3192 {
3193 return( NULL);
3194 }
3195 }
3196 else
3197 {
3198 if (!(WndParent = UserGetWindowObject(IntGetDesktopWindow())))
3199 {
3200 return( NULL);
3201 }
3202 }
3203
3204 if (!(Wnd = UserGetWindowObject(hWndChild)))
3205 {
3206 return( NULL);
3207 }
3208
3209 UserRefObjectCo(Wnd, &Ref);
3210 UserRefObjectCo(WndParent, &ParentRef);
3211
3212 WndOldParent = co_IntSetParent(Wnd, WndParent);
3213
3214 UserDerefObjectCo(WndParent);
3215 UserDerefObjectCo(Wnd);
3216
3217 if (WndOldParent)
3218 {
3219 hWndOldParent = WndOldParent->hSelf;
3220 UserDereferenceObject(WndOldParent);
3221 }
3222
3223 return( hWndOldParent);
3224 }
3225
3226 /*
3227 * NtUserSetParent
3228 *
3229 * The NtUserSetParent function changes the parent window of the specified
3230 * child window.
3231 *
3232 * Remarks
3233 * The new parent window and the child window must belong to the same
3234 * application. If the window identified by the hWndChild parameter is
3235 * visible, the system performs the appropriate redrawing and repainting.
3236 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3237 * or WS_POPUP window styles of the window whose parent is being changed.
3238 *
3239 * Status
3240 * @implemented
3241 */
3242
3243 HWND APIENTRY
3244 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
3245 {
3246 DECLARE_RETURN(HWND);
3247
3248 DPRINT("Enter NtUserSetParent\n");
3249 UserEnterExclusive();
3250
3251 /*
3252 Check Parent first from user space, set it here.
3253 */
3254 if (!hWndNewParent)
3255 {
3256 hWndNewParent = IntGetDesktopWindow();
3257 }
3258 else if (hWndNewParent == HWND_MESSAGE)
3259 {
3260 hWndNewParent = IntGetMessageWindow();
3261 }
3262
3263 RETURN( co_UserSetParent(hWndChild, hWndNewParent));
3264
3265 CLEANUP:
3266 DPRINT("Leave NtUserSetParent, ret=%i\n",_ret_);
3267 UserLeave();
3268 END_CLEANUP;
3269 }
3270
3271 /*
3272 * UserGetShellWindow
3273 *
3274 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3275 *
3276 * Status
3277 * @implemented
3278 */
3279 HWND FASTCALL UserGetShellWindow(VOID)
3280 {
3281 PWINSTATION_OBJECT WinStaObject;
3282 HWND Ret;
3283
3284 NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3285 KernelMode,
3286 0,
3287 &WinStaObject);
3288
3289 if (!NT_SUCCESS(Status))
3290 {
3291 SetLastNtError(Status);
3292 return( (HWND)0);
3293 }
3294
3295 Ret = (HWND)WinStaObject->ShellWindow;
3296
3297 ObDereferenceObject(WinStaObject);
3298 return( Ret);
3299 }
3300
3301 /*
3302 * NtUserSetShellWindowEx
3303 *
3304 * This is undocumented function to set global shell window. The global
3305 * shell window has special handling of window position.
3306 *
3307 * Status
3308 * @implemented
3309 */
3310 BOOL APIENTRY
3311 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
3312 {
3313 PWINSTATION_OBJECT WinStaObject;
3314 PWINDOW_OBJECT WndShell, WndListView;
3315 DECLARE_RETURN(BOOL);
3316 USER_REFERENCE_ENTRY Ref;
3317 NTSTATUS Status;
3318 PTHREADINFO ti;
3319
3320 DPRINT("Enter NtUserSetShellWindowEx\n");
3321 UserEnterExclusive();
3322
3323 if (!(WndShell = UserGetWindowObject(hwndShell)))
3324 {
3325 RETURN(FALSE);
3326 }
3327
3328 if(!(WndListView = UserGetWindowObject(hwndListView)))
3329 {
3330 RETURN(FALSE);
3331 }
3332
3333 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3334 KernelMode,
3335 0,
3336 &WinStaObject);
3337
3338 if (!NT_SUCCESS(Status))
3339 {
3340 SetLastNtError(Status);
3341 RETURN( FALSE);
3342 }
3343
3344 /*
3345 * Test if we are permitted to change the shell window.
3346 */
3347 if (WinStaObject->ShellWindow)
3348 {
3349 ObDereferenceObject(WinStaObject);
3350 RETURN( FALSE);
3351 }
3352
3353 /*
3354 * Move shell window into background.
3355 */
3356 if (hwndListView && hwndListView != hwndShell)
3357 {
3358 /*
3359 * Disabled for now to get Explorer working.
3360 * -- Filip, 01/nov/2003
3361 */
3362 #if 0
3363 co_WinPosSetWindowPos(hwndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3364 #endif
3365
3366 if (WndListView->Wnd->ExStyle & WS_EX_TOPMOST)
3367 {
3368 ObDereferenceObject(WinStaObject);
3369 RETURN( FALSE);
3370 }
3371 }
3372
3373 if (WndShell->Wnd->ExStyle & WS_EX_TOPMOST)
3374 {
3375 ObDereferenceObject(WinStaObject);
3376 RETURN( FALSE);
3377 }
3378
3379 UserRefObjectCo(WndShell, &Ref);
3380 co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3381
3382 WinStaObject->ShellWindow = hwndShell;
3383 WinStaObject->ShellListView = hwndListView;
3384
3385 ti = GetW32ThreadInfo();
3386 if (ti->pDeskInfo) ti->pDeskInfo->hShellWindow = hwndShell;
3387
3388 UserDerefObjectCo(WndShell);
3389
3390 ObDereferenceObject(WinStaObject);
3391 RETURN( TRUE);
3392
3393 CLEANUP:
3394 DPRINT("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_);
3395 UserLeave();
3396 END_CLEANUP;
3397 }
3398
3399 /*
3400 * NtUserGetSystemMenu
3401 *
3402 * The NtUserGetSystemMenu function allows the application to access the
3403 * window menu (also known as the system menu or the control menu) for
3404 * copying and modifying.
3405 *
3406 * Parameters
3407 * hWnd
3408 * Handle to the window that will own a copy of the window menu.
3409 * bRevert
3410 * Specifies the action to be taken. If this parameter is FALSE,
3411 * NtUserGetSystemMenu returns a handle to the copy of the window menu
3412 * currently in use. The copy is initially identical to the window menu
3413 * but it can be modified.
3414 * If this parameter is TRUE, GetSystemMenu resets the window menu back
3415 * to the default state. The previous window menu, if any, is destroyed.
3416 *
3417 * Return Value
3418 * If the bRevert parameter is FALSE, the return value is a handle to a
3419 * copy of the window menu. If the bRevert parameter is TRUE, the return
3420 * value is NULL.
3421 *
3422 * Status
3423 * @implemented
3424 */
3425
3426 HMENU APIENTRY
3427 NtUserGetSystemMenu(HWND hWnd, BOOL bRevert)
3428 {
3429 PWINDOW_OBJECT Window;
3430 PMENU_OBJECT Menu;
3431 DECLARE_RETURN(HMENU);
3432
3433 DPRINT("Enter NtUserGetSystemMenu\n");
3434 UserEnterShared();
3435
3436 if (!(Window = UserGetWindowObject(hWnd)))
3437 {
3438 RETURN(NULL);
3439 }
3440
3441 if (!(Menu = IntGetSystemMenu(Window, bRevert, FALSE)))
3442 {
3443 RETURN(NULL);
3444 }
3445
3446 RETURN(Menu->MenuInfo.Self);
3447
3448 CLEANUP:
3449 DPRINT("Leave NtUserGetSystemMenu, ret=%i\n",_ret_);
3450 UserLeave();
3451 END_CLEANUP;
3452 }
3453
3454 /*
3455 * NtUserSetSystemMenu
3456 *
3457 * Status
3458 * @implemented
3459 */
3460
3461 BOOL APIENTRY
3462 NtUserSetSystemMenu(HWND hWnd, HMENU hMenu)
3463 {
3464 BOOL Result = FALSE;
3465 PWINDOW_OBJECT Window;
3466 PMENU_OBJECT Menu;
3467 DECLARE_RETURN(BOOL);
3468
3469 DPRINT("Enter NtUserSetSystemMenu\n");
3470 UserEnterExclusive();
3471
3472 if (!(Window = UserGetWindowObject(hWnd)))
3473 {
3474 RETURN( FALSE);
3475 }
3476
3477 if (hMenu)
3478 {
3479 /*
3480 * Assign new menu handle.
3481 */
3482 if (!(Menu = UserGetMenuObject(hMenu)))
3483 {
3484 RETURN( FALSE);
3485 }
3486
3487 Result = IntSetSystemMenu(Window, Menu);
3488 }
3489
3490 RETURN( Result);
3491
3492 CLEANUP:
3493 DPRINT("Leave NtUserSetSystemMenu, ret=%i\n",_ret_);
3494 UserLeave();
3495 END_CLEANUP;
3496 }
3497
3498 LONG FASTCALL
3499 co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3500 {
3501 PWINDOW_OBJECT Window, Parent;
3502 PWND Wnd;
3503 PWINSTATION_OBJECT WindowStation;
3504 LONG OldValue;
3505 STYLESTRUCT Style;
3506
3507 if (hWnd == IntGetDesktopWindow())
3508 {
3509 SetLastWin32Error(STATUS_ACCESS_DENIED);
3510 return( 0);
3511 }
3512
3513 if (!(Window = UserGetWindowObject(hWnd)))
3514 {
3515 return( 0);
3516 }
3517
3518 Wnd = Window->Wnd;
3519
3520 if (!Wnd) return 0; // No go on zero.
3521
3522 if ((INT)Index >= 0)
3523 {
3524 if ((Index + sizeof(LONG)) > Wnd->cbwndExtra)
3525 {
3526 SetLastWin32Error(ERROR_INVALID_INDEX);
3527 return( 0);
3528 }
3529
3530 OldValue = *((LONG *)((PCHAR)(Wnd + 1) + Index));
3531 /*
3532 if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW)
3533 {
3534 OldValue = (LONG)IntSetWindowProc( Wnd,
3535 (WNDPROC)NewValue,
3536 Ansi);
3537 if (!OldValue) return 0;
3538 }
3539 */
3540 *((LONG *)((PCHAR)(Wnd + 1) + Index)) = NewValue;
3541 }
3542 else
3543 {
3544 switch (Index)
3545 {
3546 case GWL_EXSTYLE:
3547 OldValue = (LONG) Wnd->ExStyle;
3548 Style.styleOld = OldValue;
3549 Style.styleNew = NewValue;
3550
3551 /*
3552 * Remove extended window style bit WS_EX_TOPMOST for shell windows.
3553 */
3554 WindowStation = Window->pti->rpdesk->rpwinstaParent;
3555 if(WindowStation)
3556 {
3557 if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
3558 Style.styleNew &= ~WS_EX_TOPMOST;
3559 }
3560
3561 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
3562 Wnd->ExStyle = (DWORD)Style.styleNew;
3563 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
3564 break;
3565
3566 case GWL_STYLE:
3567 OldValue = (LONG) Wnd->style;
3568 Style.styleOld = OldValue;
3569 Style.styleNew = NewValue;
3570 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
3571 Wnd->style = (DWORD)Style.styleNew;
3572 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
3573 break;
3574
3575 case GWL_WNDPROC:
3576 {
3577 if ( Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process() ||
3578 Wnd->fnid & FNID_FREED)
3579 {
3580 SetLastWin32Error(ERROR_ACCESS_DENIED);
3581 return( 0);
3582 }
3583 OldValue = (LONG)IntSetWindowProc(Wnd,
3584 (WNDPROC)NewValue,
3585 Ansi);
3586 break;
3587 }
3588
3589 case GWL_HINSTANCE:
3590 OldValue = (LONG) Wnd->hModule;
3591 Wnd->hModule = (HINSTANCE) NewValue;
3592 break;
3593
3594 case GWL_HWNDPARENT:
3595 Parent = Window->spwndParent;
3596 if (Parent && (Parent->hSelf == IntGetDesktopWindow()))
3597 OldValue = (LONG) IntSetOwner(Window->hSelf, (HWND) NewValue);
3598 else
3599 OldValue = (LONG) co_UserSetParent(Window->hSelf, (HWND) NewValue);
3600 break;
3601
3602 case GWL_ID:
3603 OldValue = (LONG) Wnd->IDMenu;
3604 Wnd->IDMenu = (UINT) NewValue;
3605 break;
3606
3607 case GWL_USERDATA:
3608 OldValue = Wnd->dwUserData;
3609 Wnd->dwUserData = NewValue;
3610 break;
3611
3612 default:
3613 DPRINT1("NtUserSetWindowLong(): Unsupported index %d\n", Index);
3614 SetLastWin32Error(ERROR_INVALID_INDEX);
3615 OldValue = 0;
3616 break;
3617 }
3618 }
3619
3620 return( OldValue);
3621 }
3622
3623 /*
3624 * NtUserSetWindowLong
3625 *
3626 * The NtUserSetWindowLong function changes an attribute of the specified
3627 * window. The function also sets the 32-bit (long) value at the specified
3628 * offset into the extra window memory.
3629 *
3630 * Status
3631 * @implemented
3632 */
3633
3634 LONG APIENTRY
3635 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3636 {
3637 DECLARE_RETURN(LONG);
3638
3639 DPRINT("Enter NtUserSetWindowLong\n");
3640 UserEnterExclusive();
3641
3642 RETURN( co_UserSetWindowLong(hWnd, Index, NewValue, Ansi));
3643
3644 CLEANUP:
3645 DPRINT("Leave NtUserSetWindowLong, ret=%i\n",_ret_);
3646 UserLeave();
3647 END_CLEANUP;
3648 }
3649
3650 /*
3651 * NtUserSetWindowWord
3652 *
3653 * Legacy function similar to NtUserSetWindowLong.
3654 *
3655 * Status
3656 * @implemented
3657 */
3658
3659 WORD APIENTRY
3660 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue)
3661 {
3662 PWINDOW_OBJECT Window;
3663 WORD OldValue;
3664 DECLARE_RETURN(WORD);
3665
3666 DPRINT("Enter NtUserSetWindowWord\n");
3667 UserEnterExclusive();
3668
3669 if (!(Window = UserGetWindowObject(hWnd)))
3670 {
3671 RETURN( 0);
3672 }
3673
3674 switch (Index)
3675 {
3676 case GWL_ID:
3677 case GWL_HINSTANCE:
3678 case GWL_HWNDPARENT:
3679 RETURN( co_UserSetWindowLong(Window->hSelf, Index, (UINT)NewValue, TRUE));
3680 default:
3681 if (Index < 0)
3682 {
3683 SetLastWin32Error(ERROR_INVALID_INDEX);
3684 RETURN( 0);
3685 }
3686 }
3687
3688 if (Index > Window->Wnd->cbwndExtra - sizeof(WORD))
3689 {
3690 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3691 RETURN( 0);
3692 }
3693
3694 OldValue = *((WORD *)((PCHAR)(Window->Wnd + 1) + Index));
3695 *((WORD *)((PCHAR)(Window->Wnd + 1) + Index)) = NewValue;
3696
3697 RETURN( OldValue);
3698
3699 CLEANUP:
3700 DPRINT("Leave NtUserSetWindowWord, ret=%i\n",_ret_);
3701 UserLeave();
3702 END_CLEANUP;
3703 }
3704
3705 /*
3706 * @implemented
3707 */
3708 BOOL APIENTRY
3709 NtUserGetWindowPlacement(HWND hWnd,
3710 WINDOWPLACEMENT *lpwndpl)
3711 {
3712 PWINDOW_OBJECT Window;
3713 PWND Wnd;
3714 POINT Size;
3715 WINDOWPLACEMENT Safepl;
3716 NTSTATUS Status;
3717 DECLARE_RETURN(BOOL);
3718
3719 DPRINT("Enter NtUserGetWindowPlacement\n");
3720 UserEnterShared();
3721
3722 if (!(Window = UserGetWindowObject(hWnd)))
3723 {
3724 RETURN( FALSE);
3725 }
3726 Wnd = Window->Wnd;
3727
3728 Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
3729 if(!NT_SUCCESS(Status))
3730 {
3731 SetLastNtError(Status);
3732 RETURN( FALSE);
3733 }
3734 if(Safepl.length != sizeof(WINDOWPLACEMENT))
3735 {
3736 RETURN( FALSE);
3737 }
3738
3739 Safepl.flags = 0;
3740 if (0 == (Wnd->style & WS_VISIBLE))
3741 {
3742 Safepl.showCmd = SW_HIDE;
3743 }
3744 else if ((0 != (Window->state & WINDOWOBJECT_RESTOREMAX) ||
3745 0 != (Wnd->style & WS_MAXIMIZE)) &&
3746 0 == (Wnd->style & WS_MINIMIZE))
3747 {
3748 Safepl.showCmd = SW_SHOWMAXIMIZED;
3749 }
3750 else if (0 != (Wnd->style & WS_MINIMIZE))
3751 {
3752 Safepl.showCmd = SW_SHOWMINIMIZED;
3753 }
3754 else if (0 != (Wnd->style & WS_VISIBLE))
3755 {
3756 Safepl.showCmd = SW_SHOWNORMAL;
3757 }
3758
3759 Size.x = Wnd->rcWindow.left;
3760 Size.y = Wnd->rcWindow.top;
3761 WinPosInitInternalPos(Window, &Size,
3762 &Wnd->rcWindow);
3763
3764 Safepl.rcNormalPosition = Wnd->InternalPos.NormalRect;
3765 Safepl.ptMinPosition = Wnd->InternalPos.IconPos;
3766 Safepl.ptMaxPosition = Wnd->InternalPos.MaxPos;
3767
3768 Status = MmCopyToCaller(lpwndpl, &Safepl, sizeof(WINDOWPLACEMENT));
3769 if(!NT_SUCCESS(Status))
3770 {
3771 SetLastNtError(Status);
3772 RETURN( FALSE);
3773 }
3774
3775 RETURN( TRUE);
3776
3777 CLEANUP:
3778 DPRINT("Leave NtUserGetWindowPlacement, ret=%i\n",_ret_);
3779 UserLeave();
3780 END_CLEANUP;
3781 }
3782
3783
3784 /*
3785 * @unimplemented
3786 */
3787 BOOL APIENTRY
3788 NtUserLockWindowUpdate(HWND hWnd)
3789 {
3790 UNIMPLEMENTED
3791
3792 return 0;
3793 }
3794
3795
3796 /*
3797 * @implemented
3798 */
3799 BOOL APIENTRY
3800 NtUserMoveWindow(
3801 HWND hWnd,
3802 int X,
3803 int Y,
3804 int nWidth,
3805 int nHeight,
3806 BOOL bRepaint)
3807 {
3808 return NtUserSetWindowPos(hWnd, 0, X, Y, nWidth, nHeight,
3809 (bRepaint ? SWP_NOZORDER | SWP_NOACTIVATE :
3810 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW));
3811 }
3812
3813 /*
3814 QueryWindow based on KJK::Hyperion and James Tabor.
3815
3816 0 = QWUniqueProcessId
3817 1 = QWUniqueThreadId
3818 2 = QWActiveWindow
3819 3 = QWFocusWindow
3820 4 = QWIsHung Implements IsHungAppWindow found
3821 by KJK::Hyperion.
3822
3823 9 = QWKillWindow When I called this with hWnd ==
3824 DesktopWindow, it shutdown the system
3825 and rebooted.
3826 */
3827 /*
3828 * @implemented
3829 */
3830 DWORD APIENTRY
3831 NtUserQueryWindow(HWND hWnd, DWORD Index)
3832 {
3833 PWINDOW_OBJECT Window;
3834 PWND pWnd;
3835 DWORD Result;
3836 DECLARE_RETURN(UINT);
3837
3838 DPRINT("Enter NtUserQueryWindow\n");
3839 UserEnterShared();
3840
3841 if (!(Window = UserGetWindowObject(hWnd)) || !Window->Wnd)
3842 {
3843 RETURN( 0);
3844 }
3845
3846 pWnd = Window->Wnd;
3847
3848 switch(Index)
3849 {
3850 case QUERY_WINDOW_UNIQUE_PROCESS_ID:
3851 Result = (DWORD)IntGetWndProcessId(Window);
3852 break;
3853
3854 case QUERY_WINDOW_UNIQUE_THREAD_ID:
3855 Result = (DWORD)IntGetWndThreadId(Window);
3856 break;
3857
3858 case QUERY_WINDOW_ACTIVE:
3859 Result = (DWORD)UserGetActiveWindow();
3860 break;
3861
3862 case QUERY_WINDOW_FOCUS:
3863 Result = (DWORD)IntGetFocusWindow();
3864 break;
3865
3866 case QUERY_WINDOW_ISHUNG:
3867 Result = (DWORD)MsqIsHung(Window->pti->MessageQueue);
3868 break;
3869
3870 case QUERY_WINDOW_REAL_ID:
3871 Result = (DWORD)pWnd->head.pti->pEThread->Cid.UniqueProcess;
3872
3873 default:
3874 Result = (DWORD)NULL;
3875 break;
3876 }
3877
3878 RETURN( Result);
3879
3880 CLEANUP:
3881 DPRINT("Leave NtUserQueryWindow, ret=%i\n",_ret_);
3882 UserLeave();
3883 END_CLEANUP;
3884 }
3885
3886
3887 /*
3888 * @unimplemented
3889 */
3890 DWORD APIENTRY
3891 NtUserRealChildWindowFromPoint(DWORD Unknown0,
3892 DWORD Unknown1,
3893 DWORD Unknown2)
3894 {
3895 UNIMPLEMENTED
3896
3897 return 0;
3898 }
3899
3900
3901 /*
3902 * @implemented
3903 */
3904 UINT APIENTRY
3905 NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe)
3906 {
3907 UNICODE_STRING SafeMessageName;
3908 NTSTATUS Status;
3909 UINT Ret;
3910 DECLARE_RETURN(UINT);
3911
3912 DPRINT("Enter NtUserRegisterWindowMessage\n");
3913 UserEnterExclusive();
3914
3915 if(MessageNameUnsafe == NULL)
3916 {
3917 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3918 RETURN( 0);
3919 }
3920
3921 Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe);
3922 if(!NT_SUCCESS(Status))
3923 {
3924 SetLastNtError(Status);
3925 RETURN( 0);
3926 }
3927
3928 Ret = (UINT)IntAddAtom(SafeMessageName.Buffer);
3929 if (SafeMessageName.Buffer)
3930 ExFreePoolWithTag(SafeMessageName.Buffer, TAG_STRING);
3931 RETURN( Ret);
3932
3933 CLEANUP:
3934 DPRINT("Leave NtUserRegisterWindowMessage, ret=%i\n",_ret_);
3935 UserLeave();
3936 END_CLEANUP;
3937 }
3938
3939
3940 /*
3941 * @unimplemented
3942 */
3943 DWORD APIENTRY
3944 NtUserSetImeOwnerWindow(DWORD Unknown0,
3945 DWORD Unknown1)
3946 {
3947 UNIMPLEMENTED
3948
3949 return 0;
3950 }
3951
3952
3953 /*
3954 * @unimplemented
3955 */
3956 DWORD APIENTRY
3957 NtUserSetInternalWindowPos(
3958 HWND hwnd,
3959 UINT showCmd,
3960 LPRECT rect,
3961 LPPOINT pt)
3962 {
3963 UNIMPLEMENTED
3964
3965 return 0;
3966
3967 }
3968
3969
3970 /*
3971 * @unimplemented
3972 */
3973 BOOL APIENTRY
3974 NtUserSetLayeredWindowAttributes(HWND hwnd,
3975 COLORREF crKey,
3976 BYTE bAlpha,
3977 DWORD dwFlags)
3978 {
3979 UNIMPLEMENTED;
3980 return FALSE;
3981 }
3982
3983
3984 /*
3985 * @unimplemented
3986 */
3987 BOOL APIENTRY
3988 NtUserSetLogonNotifyWindow(HWND hWnd)
3989 {
3990 UNIMPLEMENTED
3991
3992 return 0;
3993 }
3994
3995
3996 /*
3997 * @implemented
3998 */
3999 BOOL APIENTRY
4000 NtUserSetMenu(
4001 HWND hWnd,
4002 HMENU Menu,
4003 BOOL Repaint)
4004 {
4005 PWINDOW_OBJECT Window;
4006 BOOL Changed;
4007 DECLARE_RETURN(BOOL);
4008
4009 DPRINT("Enter NtUserSetMenu\n");
4010 UserEnterExclusive();
4011
4012 if (!(Window = UserGetWindowObject(hWnd)))
4013 {
4014 RETURN( FALSE);
4015 }
4016
4017 if (! IntSetMenu(Window, Menu, &Changed))
4018 {
4019 RETURN( FALSE);
4020 }
4021
4022 if (Changed && Repaint)
4023 {
4024 USER_REFERENCE_ENTRY Ref;
4025
4026 UserRefObjectCo(Window, &Ref);
4027 co_WinPosSetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4028 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
4029
4030 UserDerefObjectCo(Window);
4031 }
4032
4033 RETURN( TRUE);
4034
4035 CLEANUP:
4036 DPRINT("Leave NtUserSetMenu, ret=%i\n",_ret_);
4037 UserLeave();
4038 END_CLEANUP;
4039 }
4040
4041
4042 /*
4043 * @implemented
4044 */
4045 BOOL APIENTRY
4046 NtUserSetWindowFNID(HWND hWnd,
4047 WORD fnID)
4048 {
4049 PWINDOW_OBJECT Window;
4050 PWND Wnd;
4051 DECLARE_RETURN(BOOL);
4052
4053 DPRINT("Enter NtUserSetWindowFNID\n");
4054 UserEnterExclusive();
4055
4056 if (!(Window = UserGetWindowObject(hWnd)))
4057 {
4058 RETURN( FALSE);
4059 }
4060 Wnd = Window->Wnd;
4061
4062 if (Wnd->pcls)
4063 { // From user land we only set these.
4064 if ((fnID != FNID_DESTROY) || ((fnID < FNID_BUTTON) && (fnID > FNID_IME)) )
4065 {
4066 RETURN( FALSE);
4067 }
4068 else
4069 Wnd->pcls->fnid |= fnID;
4070 }
4071 RETURN( TRUE);
4072
4073 CLEANUP:
4074 DPRINT("Leave NtUserSetWindowFNID\n");
4075 UserLeave();
4076 END_CLEANUP;
4077 }
4078
4079
4080 /*
4081 * @implemented
4082 */
4083 BOOL APIENTRY
4084 NtUserSetWindowPlacement(HWND hWnd,
4085 WINDOWPLACEMENT *lpwndpl)
4086 {
4087 PWINDOW_OBJECT Window;
4088 PWND Wnd;
4089 WINDOWPLACEMENT Safepl;
4090 NTSTATUS Status;
4091 DECLARE_RETURN(BOOL);
4092 USER_REFERENCE_ENTRY Ref;
4093
4094 DPRINT("Enter NtUserSetWindowPlacement\n");
4095 UserEnterExclusive();
4096
4097 if (!(Window = UserGetWindowObject(hWnd)))
4098 {
4099 RETURN( FALSE);
4100 }
4101 Wnd = Window->Wnd;
4102
4103 Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
4104 if(!NT_SUCCESS(Status))
4105 {
4106 SetLastNtError(Status);
4107 RETURN( FALSE);
4108 }
4109 if(Safepl.length != sizeof(WINDOWPLACEMENT))
4110 {
4111 RETURN( FALSE);
4112 }
4113
4114 UserRefObjectCo(Window, &Ref);
4115
4116 if ((Wnd->style & (WS_MAXIMIZE | WS_MINIMIZE)) == 0)
4117 {
4118 co_WinPosSetWindowPos(Window, NULL,
4119 Safepl.rcNormalPosition.left, Safepl.rcNormalPosition.top,
4120 Safepl.rcNormalPosition.right - Safepl.rcNormalPosition.left,
4121 Safepl.rcNormalPosition.bottom - Safepl.rcNormalPosition.top,
4122 SWP_NOZORDER | SWP_NOACTIVATE);
4123 }
4124
4125 /* FIXME - change window status */
4126 co_WinPosShowWindow(Window, Safepl.showCmd);
4127
4128 Wnd->InternalPosInitialized = TRUE;
4129 Wnd->InternalPos.NormalRect = Safepl.rcNormalPosition;
4130 Wnd->InternalPos.IconPos = Safepl.ptMinPosition;
4131 Wnd->InternalPos.MaxPos = Safepl.ptMaxPosition;
4132
4133 UserDerefObjectCo(Window);
4134 RETURN(TRUE);
4135
4136 CLEANUP:
4137 DPRINT("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
4138 UserLeave();
4139 END_CLEANUP;
4140 }
4141
4142
4143 /*
4144 * @implemented
4145 */
4146 BOOL APIENTRY
4147 NtUserSetWindowPos(
4148 HWND hWnd,
4149 HWND hWndInsertAfter,
4150 int X,
4151 int Y,
4152 int cx,
4153 int cy,
4154 UINT uFlags)
4155 {
4156 DECLARE_RETURN(BOOL);
4157 PWINDOW_OBJECT Window;
4158 BOOL ret;
4159 USER_REFERENCE_ENTRY Ref;
4160
4161 DPRINT("Enter NtUserSetWindowPos\n");
4162 UserEnterExclusive();
4163
4164 if (!(Window = UserGetWindowObject(hWnd)))
4165 {
4166 RETURN(FALSE);
4167 }
4168
4169 /* First make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
4170 if (!(uFlags & SWP_NOMOVE))
4171 {
4172 if (X < -32768) X = -32768;
4173 else if (X > 32767) X = 32767;
4174 if (Y < -32768) Y = -32768;
4175 else if (Y > 32767) Y = 32767;
4176 }
4177 if (!(uFlags & SWP_NOSIZE))
4178 {
4179 if (cx < 0) cx = 0;
4180 else if (cx > 32767) cx = 32767;
4181 if (cy < 0) cy = 0;
4182 else if (cy > 32767) cy = 32767;
4183 }
4184
4185 UserRefObjectCo(Window, &Ref);
4186 ret = co_WinPosSetWindowPos(Window, hWndInsertAfter, X, Y, cx, cy, uFlags);
4187 UserDerefObjectCo(Window);
4188
4189 RETURN(ret);
4190
4191 CLEANUP:
4192 DPRINT("Leave NtUserSetWindowPos, ret=%i\n",_ret_);
4193 UserLeave();
4194 END_CLEANUP;
4195 }
4196
4197
4198 INT FASTCALL
4199 IntGetWindowRgn(PWINDOW_OBJECT Window, HRGN hRgn)
4200 {
4201 INT Ret;
4202 HRGN VisRgn;
4203 ROSRGNDATA *pRgn;
4204 PWND Wnd;
4205
4206 if(!Window)
4207 {
4208 return ERROR;
4209 }
4210 if(!hRgn)
4211 {
4212 return ERROR;
4213 }
4214
4215 Wnd = Window->Wnd;
4216
4217 /* Create a new window region using the window rectangle */
4218 VisRgn = IntSysCreateRectRgnIndirect(&Window->Wnd->rcWindow);
4219 NtGdiOffsetRgn(VisRgn, -Window->Wnd->rcWindow.left, -Window->Wnd->rcWindow.top);
4220 /* if there's a region assigned to the window, combine them both */
4221 if(Window->hrgnClip && !(Wnd->style & WS_MINIMIZE))
4222 NtGdiCombineRgn(VisRgn, VisRgn, Window->hrgnClip, RGN_AND);
4223 /* Copy the region into hRgn */
4224 NtGdiCombineRgn(hRgn, VisRgn, NULL, RGN_COPY);
4225
4226 if((pRgn = RGNOBJAPI_Lock(hRgn, NULL)))
4227 {
4228 Ret = pRgn->rdh.iType;
4229 RGNOBJAPI_Unlock(pRgn);
4230 }
4231 else
4232 Ret = ERROR;
4233
4234 REGION_FreeRgnByHandle(VisRgn);
4235
4236 return Ret;
4237 }
4238
4239 INT FASTCALL
4240 IntGetWindowRgnBox(PWINDOW_OBJECT Window, RECTL *Rect)
4241 {
4242 INT Ret;
4243 HRGN VisRgn;
4244 ROSRGNDATA *pRgn;
4245 PWND Wnd;
4246
4247 if(!Window)
4248 {
4249 return ERROR;
4250 }
4251 if(!Rect)
4252 {
4253 return ERROR;
4254 }
4255
4256 Wnd = Window->Wnd;
4257
4258 /* Create a new window region using the window rectangle */
4259 VisRgn = IntSysCreateRectRgnIndirect(&Window->Wnd->rcWindow);
4260 NtGdiOffsetRgn(VisRgn, -Window->Wnd->rcWindow.left, -Window->Wnd->rcWindow.top);
4261 /* if there's a region assigned to the window, combine them both */
4262 if(Window->hrgnClip && !(Wnd->style & WS_MINIMIZE))
4263 NtGdiCombineRgn(VisRgn, VisRgn, Window->hrgnClip, RGN_AND);
4264
4265 if((pRgn = RGNOBJAPI_Lock(VisRgn, NULL)))
4266 {
4267 Ret = pRgn->rdh.iType;
4268 *Rect = pRgn->rdh.rcBound;
4269 RGNOBJAPI_Unlock(pRgn);
4270 }
4271 else
4272 Ret = ERROR;
4273
4274 REGION_FreeRgnByHandle(VisRgn);
4275
4276 return Ret;
4277 }
4278
4279
4280 /*
4281 * @implemented
4282 */
4283 INT APIENTRY
4284 NtUserSetWindowRgn(
4285 HWND hWnd,
4286 HRGN hRgn,
4287 BOOL bRedraw)
4288 {
4289 HRGN hrgnCopy;
4290 PWINDOW_OBJECT Window;
4291 DECLARE_RETURN(INT);
4292
4293 DPRINT("Enter NtUserSetWindowRgn\n");
4294 UserEnterExclusive();
4295
4296 if (!(Window = UserGetWindowObject(hWnd)))
4297 {
4298 RETURN( 0);
4299 }
4300
4301 if (hRgn) // The region will be deleted in user32.
4302 {
4303 if (GDIOBJ_ValidateHandle(hRgn, GDI_OBJECT_TYPE_REGION))
4304 {
4305 hrgnCopy = IntSysCreateRectRgn(0, 0, 0, 0);
4306 NtGdiCombineRgn(hrgnCopy, hRgn, 0, RGN_COPY);
4307 }
4308 else
4309 RETURN( 0);
4310 }
4311 else
4312 hrgnCopy = (HRGN) 1;
4313
4314 if (Window->hrgnClip)
4315 {
4316 /* Delete no longer needed region handle */
4317 GreDeleteObject(Window->hrgnClip);
4318 }
4319 Window->hrgnClip = hrgnCopy;
4320
4321 /* FIXME - send WM_WINDOWPOSCHANGING and WM_WINDOWPOSCHANGED messages to the window */
4322
4323 if(bRedraw)
4324 {
4325 USER_REFERENCE_ENTRY Ref;
4326 UserRefObjectCo(Window, &Ref);
4327 co_UserRedrawWindow(Window, NULL, NULL, RDW_INVALIDATE);
4328 UserDerefObjectCo(Window);
4329 }
4330
4331 RETURN( (INT)hRgn);
4332
4333 CLEANUP:
4334 DPRINT("Leave NtUserSetWindowRgn, ret=%i\n",_ret_);
4335 UserLeave();
4336 END_CLEANUP;
4337 }
4338
4339
4340 /*
4341 * @implemented
4342 */
4343 BOOL APIENTRY
4344 NtUserShowWindow(HWND hWnd, LONG nCmdShow)
4345 {
4346 PWINDOW_OBJECT Window;
4347 BOOL ret;
4348 DECLARE_RETURN(BOOL);
4349 USER_REFERENCE_ENTRY Ref;
4350
4351 DPRINT("Enter NtUserShowWindow\n");
4352 UserEnterExclusive();
4353
4354 if (!(Window = UserGetWindowObject(hWnd)))
4355 {
4356 RETURN(FALSE);
4357 }
4358
4359 UserRefObjectCo(Window, &Ref);
4360 ret = co_WinPosShowWindow(Window, nCmdShow);
4361 UserDerefObjectCo(Window);
4362
4363 RETURN(ret);
4364
4365 CLEANUP:
4366 DPRINT("Leave NtUserShowWindow, ret=%i\n",_ret_);
4367 UserLeave();
4368 END_CLEANUP;
4369 }
4370
4371
4372 /*
4373 * @unimplemented
4374 */
4375 BOOL APIENTRY
4376 NtUserShowWindowAsync(HWND hWnd, LONG nCmdShow)
4377 {
4378 #if 0
4379 UNIMPLEMENTED
4380 return 0;
4381 #else
4382 return NtUserShowWindow(hWnd, nCmdShow);
4383 #endif
4384 }
4385
4386
4387 /*
4388 * @unimplemented
4389 */
4390 BOOL
4391 APIENTRY
4392 NtUserUpdateLayeredWindow(
4393 HWND hwnd,
4394 HDC hdcDst,
4395 POINT *pptDst,
4396 SIZE *psize,
4397 HDC hdcSrc,
4398 POINT *pptSrc,
4399 COLORREF crKey,
4400 BLENDFUNCTION *pblend,
4401 DWORD dwFlags,
4402 RECT *prcDirty)
4403 {
4404 UNIMPLEMENTED
4405
4406 return 0;
4407 }
4408
4409 /*
4410 * @unimplemented
4411 */
4412 HWND APIENTRY
4413 NtUserWindowFromPhysicalPoint(POINT Point)
4414 {
4415 UNIMPLEMENTED
4416
4417 return NULL;
4418 }
4419
4420 /*
4421 * @implemented
4422 */
4423 HWND APIENTRY
4424 NtUserWindowFromPoint(LONG X, LONG Y)
4425 {
4426 POINT pt;
4427 HWND Ret;
4428 PWINDOW_OBJECT DesktopWindow = NULL, Window = NULL;
4429 DECLARE_RETURN(HWND);
4430 USER_REFERENCE_ENTRY Ref;
4431
4432 DPRINT("Enter NtUserWindowFromPoint\n");
4433 UserEnterExclusive();
4434
4435 if ((DesktopWindow = UserGetWindowObject(IntGetDesktopWindow())))
4436 {
4437 PTHREADINFO pti;
4438
4439 pt.x = X;
4440 pt.y = Y;
4441
4442 //hmm... threads live on desktops thus we have a reference on the desktop and indirectly the desktop window
4443 //its possible this referencing is useless, thou it shouldnt hurt...
4444 UserRefObjectCo(DesktopWindow, &Ref);
4445
4446 pti = PsGetCurrentThreadWin32Thread();
4447 co_WinPosWindowFromPoint(DesktopWindow, pti->MessageQueue, &pt, &Window);
4448
4449 if(Window)
4450 {
4451 Ret = Window->hSelf;
4452
4453 RETURN( Ret);
4454 }
4455 }
4456
4457 RETURN( NULL);
4458
4459 CLEANUP:
4460 if (Window) UserDereferenceObject(Window);
4461 if (DesktopWindow) UserDerefObjectCo(DesktopWindow);
4462
4463 DPRINT("Leave NtUserWindowFromPoint, ret=%i\n",_ret_);
4464 UserLeave();
4465 END_CLEANUP;
4466
4467 }
4468
4469
4470 /*
4471 * NtUserDefSetText
4472 *
4473 * Undocumented function that is called from DefWindowProc to set
4474 * window text.
4475 *
4476 * Status
4477 * @implemented
4478 */
4479 BOOL APIENTRY
4480 NtUserDefSetText(HWND hWnd, PLARGE_STRING WindowText)
4481 {
4482 PWINDOW_OBJECT Window;
4483 PWND Wnd;
4484 LARGE_STRING SafeText;
4485 UNICODE_STRING UnicodeString;
4486 BOOL Ret = TRUE;
4487
4488 DPRINT("Enter NtUserDefSetText\n");
4489
4490 if (WindowText != NULL)
4491 {
4492 _SEH2_TRY
4493 {
4494 SafeText = ProbeForReadLargeString(WindowText);
4495 }
4496 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4497 {
4498 Ret = FALSE;
4499 SetLastNtError(_SEH2_GetExceptionCode());
4500 }
4501 _SEH2_END;
4502
4503 if (!Ret)
4504 return FALSE;
4505 }
4506 else
4507 return TRUE;
4508
4509 UserEnterExclusive();
4510
4511 if(!(Window = UserGetWindowObject(hWnd)) || !Window->Wnd)
4512 {
4513 UserLeave();
4514 return FALSE;
4515 }
4516 Wnd = Window->Wnd;
4517
4518 // ReactOS uses Unicode and not mixed. Up/Down converting will take time.
4519 // Brought to you by: The Wine Project! Dysfunctional Thought Processes!
4520 // Now we know what the bAnsi is for.
4521 RtlInitUnicodeString(&UnicodeString, NULL);
4522 if (SafeText.Buffer)
4523 {
4524 _SEH2_TRY
4525 {
4526 if (SafeText.bAnsi)
4527 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(CHAR));
4528 else
4529 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(WCHAR));
4530 Ret = RtlLargeStringToUnicodeString(&UnicodeString, &SafeText);
4531 }
4532 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4533 {
4534 Ret = FALSE;
4535 SetLastNtError(_SEH2_GetExceptionCode());
4536 }
4537 _SEH2_END;
4538 if (!Ret) goto Exit;
4539 }
4540
4541 if (UnicodeString.Length != 0)
4542 {
4543 if (Wnd->strName.MaximumLength > 0 &&
4544 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
4545 {
4546 ASSERT(Wnd->strName.Buffer != NULL);
4547
4548 Wnd->strName.Length = UnicodeString.Length;
4549 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4550 RtlCopyMemory(Wnd->strName.Buffer,
4551 UnicodeString.Buffer,
4552 UnicodeString.Length);
4553 }
4554 else
4555 {
4556 PWCHAR buf;
4557 Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4558 buf = Wnd->strName.Buffer;
4559 Wnd->strName.Buffer = NULL;
4560 if (buf != NULL)
4561 {
4562 DesktopHeapFree(Wnd->head.rpdesk, buf);
4563 }
4564
4565 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
4566 UnicodeString.Length + sizeof(UNICODE_NULL));
4567 if (Wnd->strName.Buffer != NULL)
4568 {
4569 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4570 RtlCopyMemory(Wnd->strName.Buffer,
4571 UnicodeString.Buffer,
4572 UnicodeString.Length);
4573 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4574 Wnd->strName.Length = UnicodeString.Length;
4575 }
4576 else
4577 {
4578 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
4579 Ret = FALSE;
4580 goto Exit;
4581 }
4582 }
4583 }
4584 else
4585 {
4586 Wnd->strName.Length = 0;
4587 if (Wnd->strName.Buffer != NULL)
4588 Wnd->strName.Buffer[0] = L'\0';
4589 }
4590
4591 // HAX! FIXME! Windows does not do this in here!
4592 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4593 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4594 /* Send shell notifications */
4595 if (!Window->spwndOwner && !IntGetParent(Window))
4596 {
4597 co_IntShellHookNotify(HSHELL_REDRAW, (LPARAM) hWnd);
4598 }
4599
4600 Ret = TRUE;
4601 Exit:
4602 if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
4603 DPRINT("Leave NtUserDefSetText, ret=%i\n", Ret);
4604 UserLeave();
4605 return Ret;
4606 }
4607
4608 /*
4609 * NtUserInternalGetWindowText
4610 *
4611 * Status
4612 * @implemented
4613 */
4614
4615 INT APIENTRY
4616 NtUserInternalGetWindowText(HWND hWnd, LPWSTR lpString, INT nMaxCount)
4617 {
4618 PWINDOW_OBJECT Window;
4619 PWND Wnd;
4620 NTSTATUS Status;
4621 INT Result;
4622 DECLARE_RETURN(INT);
4623
4624 DPRINT("Enter NtUserInternalGetWindowText\n");
4625 UserEnterShared();
4626
4627 if(lpString && (nMaxCount <= 1))
4628 {
4629 SetLastWin32Error(ERROR_INVALID_PARAMETER);
4630 RETURN( 0);
4631 }
4632
4633 if(!(Window = UserGetWindowObject(hWnd)))
4634 {
4635 RETURN( 0);
4636 }
4637 Wnd = Window->Wnd;
4638
4639 Result = Wnd->strName.Length / sizeof(WCHAR);
4640 if(lpString)
4641 {
4642 const WCHAR Terminator = L'\0';
4643 INT Copy;
4644 WCHAR *Buffer = (WCHAR*)lpString;
4645
4646 Copy = min(nMaxCount - 1, Result);
4647 if(Copy > 0)
4648 {
4649 Status = MmCopyToCaller(Buffer, Wnd->strName.Buffer, Copy * sizeof(WCHAR));
4650 if(!NT_SUCCESS(Status))
4651 {
4652 SetLastNtError(Status);
4653 RETURN( 0);
4654 }
4655 Buffer += Copy;
4656 }
4657
4658 Status = MmCopyToCaller(Buffer, &Terminator, sizeof(WCHAR));
4659 if(!NT_SUCCESS(Status))
4660 {
4661 SetLastNtError(Status);
4662 RETURN( 0);
4663 }
4664
4665 Result = Copy;
4666 }
4667
4668 RETURN( Result);
4669
4670 CLEANUP:
4671 DPRINT("Leave NtUserInternalGetWindowText, ret=%i\n",_ret_);
4672 UserLeave();
4673 END_CLEANUP;
4674 }
4675
4676
4677 BOOL
4678 FASTCALL
4679 IntShowOwnedPopups(PWINDOW_OBJECT OwnerWnd, BOOL fShow )
4680 {
4681 int count = 0;
4682 PWINDOW_OBJECT pWnd;
4683 HWND *win_array;
4684
4685 // ASSERT(OwnerWnd);
4686
4687 win_array = IntWinListChildren(UserGetWindowObject(IntGetDesktopWindow()));
4688
4689 if (!win_array)
4690 return TRUE;
4691
4692 while (win_array[count])
4693 count++;
4694 while (--count >= 0)
4695 {
4696 if (!(pWnd = UserGetWindowObject( win_array[count] )))
4697 continue;
4698 if (pWnd->spwndOwner != OwnerWnd)
4699 continue;
4700
4701 if (fShow)
4702 {
4703 if (pWnd->Wnd->state & WNDS_HIDDENPOPUP)
4704 {
4705 /* In Windows, ShowOwnedPopups(TRUE) generates
4706 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
4707 * regardless of the state of the owner
4708 */
4709 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
4710 continue;
4711 }
4712 }
4713 else
4714 {
4715 if (pWnd->Wnd->style & WS_VISIBLE)
4716 {
4717 /* In Windows, ShowOwnedPopups(FALSE) generates
4718 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
4719 * regardless of the state of the owner
4720 */
4721 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
4722 continue;
4723 }
4724 }
4725
4726 }
4727 ExFreePool( win_array );
4728 return TRUE;
4729 }
4730
4731 /*
4732 * NtUserValidateHandleSecure
4733 *
4734 * Status
4735 * @implemented
4736 */
4737
4738 BOOL
4739 APIENTRY
4740 NtUserValidateHandleSecure(
4741 HANDLE handle,
4742 BOOL Restricted)
4743 {
4744 if(!Restricted)
4745 {
4746 UINT uType;
4747 {
4748 PUSER_HANDLE_ENTRY entry;
4749 if (!(entry = handle_to_entry(gHandleTable, handle )))
4750 {
4751 SetLastWin32Error(ERROR_INVALID_HANDLE);
4752 return FALSE;
4753 }
4754 uType = entry->type;
4755 }
4756 switch (uType)
4757 {
4758 case otWindow:
4759 {
4760 PWINDOW_OBJECT Window;
4761 if ((Window = UserGetWindowObject((HWND) handle))) return TRUE;
4762 return FALSE;
4763 }
4764 case otMenu:
4765 {
4766 PMENU_OBJECT Menu;
4767 if ((Menu = UserGetMenuObject((HMENU) handle))) return TRUE;
4768 return FALSE;
4769 }
4770 case otAccel:
4771 {
4772 PACCELERATOR_TABLE Accel;
4773 if ((Accel = UserGetAccelObject((HACCEL) handle))) return TRUE;
4774 return FALSE;
4775 }
4776 case otCursorIcon:
4777 {
4778 PCURICON_OBJECT Cursor;
4779 if ((Cursor = UserGetCurIconObject((HCURSOR) handle))) return TRUE;
4780 return FALSE;
4781 }
4782 case otHook:
4783 {
4784 PHOOK Hook;
4785 if ((Hook = IntGetHookObject((HHOOK) handle))) return TRUE;
4786 return FALSE;
4787 }
4788 case otMonitor:
4789 {
4790 PMONITOR Monitor;
4791 if ((Monitor = UserGetMonitorObject((HMONITOR) handle))) return TRUE;
4792 return FALSE;
4793 }
4794 case otCallProc:
4795 {
4796 WNDPROC_INFO Proc;
4797 return UserGetCallProcInfo( handle, &Proc );
4798 }
4799 default:
4800 SetLastWin32Error(ERROR_INVALID_HANDLE);
4801 }
4802 }
4803 else
4804 { /* Is handle entry restricted? */
4805 UNIMPLEMENTED
4806 }
4807 return FALSE;
4808 }
4809
4810
4811 /* EOF */