* Sync up to trunk head (r64921).
[reactos.git] / win32ss / user / ntuser / window.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Windows
5 * FILE: subsystems/win32/win32k/ntuser/window.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserWnd);
11
12 INT gNestedWindowLimit = 50;
13
14 /* HELPER FUNCTIONS ***********************************************************/
15
16 BOOL FASTCALL UserUpdateUiState(PWND Wnd, WPARAM wParam)
17 {
18 WORD Action = LOWORD(wParam);
19 WORD Flags = HIWORD(wParam);
20
21 if (Flags & ~(UISF_HIDEFOCUS | UISF_HIDEACCEL | UISF_ACTIVE))
22 {
23 EngSetLastError(ERROR_INVALID_PARAMETER);
24 return FALSE;
25 }
26
27 switch (Action)
28 {
29 case UIS_INITIALIZE:
30 EngSetLastError(ERROR_INVALID_PARAMETER);
31 return FALSE;
32
33 case UIS_SET:
34 if (Flags & UISF_HIDEFOCUS)
35 Wnd->HideFocus = TRUE;
36 if (Flags & UISF_HIDEACCEL)
37 Wnd->HideAccel = TRUE;
38 break;
39
40 case UIS_CLEAR:
41 if (Flags & UISF_HIDEFOCUS)
42 Wnd->HideFocus = FALSE;
43 if (Flags & UISF_HIDEACCEL)
44 Wnd->HideAccel = FALSE;
45 break;
46 }
47
48 return TRUE;
49 }
50
51 PWND FASTCALL IntGetWindowObject(HWND hWnd)
52 {
53 PWND Window;
54
55 if (!hWnd) return NULL;
56
57 Window = UserGetWindowObject(hWnd);
58 if (Window)
59 Window->head.cLockObj++;
60
61 return Window;
62 }
63
64 PWND FASTCALL VerifyWnd(PWND pWnd)
65 {
66 HWND hWnd;
67 UINT State, State2;
68
69 if (!pWnd) return NULL;
70
71 _SEH2_TRY
72 {
73 hWnd = UserHMGetHandle(pWnd);
74 State = pWnd->state;
75 State2 = pWnd->state2;
76 }
77 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
78 {
79 _SEH2_YIELD(return NULL);
80 }
81 _SEH2_END
82
83 if ( UserObjectInDestroy(hWnd) ||
84 State & WNDS_DESTROYED ||
85 State2 & WNDS2_INDESTROY )
86 return NULL;
87
88 return pWnd;
89 }
90
91 PWND FASTCALL ValidateHwndNoErr(HWND hWnd)
92 {
93 if (hWnd) return (PWND)UserGetObjectNoErr(gHandleTable, hWnd, TYPE_WINDOW);
94 return NULL;
95 }
96
97 /* Temp HACK */
98 PWND FASTCALL UserGetWindowObject(HWND hWnd)
99 {
100 PWND Window;
101
102 if (!hWnd)
103 {
104 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
105 return NULL;
106 }
107
108 Window = (PWND)UserGetObject(gHandleTable, hWnd, TYPE_WINDOW);
109 if (!Window || 0 != (Window->state & WNDS_DESTROYED))
110 {
111 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
112 return NULL;
113 }
114
115 return Window;
116 }
117
118 ULONG FASTCALL
119 IntSetStyle( PWND pwnd, ULONG set_bits, ULONG clear_bits )
120 {
121 ULONG styleOld, styleNew;
122 styleOld = pwnd->style;
123 styleNew = (pwnd->style | set_bits) & ~clear_bits;
124 if (styleNew == styleOld) return styleNew;
125 pwnd->style = styleNew;
126 if ((styleOld ^ styleNew) & WS_VISIBLE) // State Change.
127 {
128 if (styleOld & WS_VISIBLE) pwnd->head.pti->cVisWindows--;
129 if (styleNew & WS_VISIBLE) pwnd->head.pti->cVisWindows++;
130 DceResetActiveDCEs( pwnd );
131 }
132 return styleOld;
133 }
134
135 /*
136 * IntIsWindow
137 *
138 * The function determines whether the specified window handle identifies
139 * an existing window.
140 *
141 * Parameters
142 * hWnd
143 * Handle to the window to test.
144 *
145 * Return Value
146 * If the window handle identifies an existing window, the return value
147 * is TRUE. If the window handle does not identify an existing window,
148 * the return value is FALSE.
149 */
150
151 BOOL FASTCALL
152 IntIsWindow(HWND hWnd)
153 {
154 PWND Window;
155
156 if (!(Window = UserGetWindowObject(hWnd)))
157 {
158 return FALSE;
159 }
160
161 return TRUE;
162 }
163
164 BOOL FASTCALL
165 IntIsWindowVisible(PWND Wnd)
166 {
167 PWND Temp = Wnd;
168 for (;;)
169 {
170 if (!Temp) return TRUE;
171 if (!(Temp->style & WS_VISIBLE)) break;
172 if (Temp->style & WS_MINIMIZE && Temp != Wnd) break;
173 if (Temp->fnid == FNID_DESKTOP) return TRUE;
174 Temp = Temp->spwndParent;
175 }
176 return FALSE;
177 }
178
179 PWND FASTCALL
180 IntGetParent(PWND Wnd)
181 {
182 if (Wnd->style & WS_POPUP)
183 {
184 return Wnd->spwndOwner;
185 }
186 else if (Wnd->style & WS_CHILD)
187 {
188 return Wnd->spwndParent;
189 }
190
191 return NULL;
192 }
193
194 BOOL
195 FASTCALL
196 IntEnableWindow( HWND hWnd, BOOL bEnable )
197 {
198 BOOL Update;
199 PWND pWnd;
200 UINT bIsDisabled;
201
202 if(!(pWnd = UserGetWindowObject(hWnd)))
203 {
204 return FALSE;
205 }
206
207 /* check if updating is needed */
208 bIsDisabled = !!(pWnd->style & WS_DISABLED);
209 Update = bIsDisabled;
210
211 if (bEnable)
212 {
213 IntSetStyle( pWnd, 0, WS_DISABLED );
214 }
215 else
216 {
217 Update = !bIsDisabled;
218
219 co_IntSendMessage( hWnd, WM_CANCELMODE, 0, 0);
220
221 /* Remove keyboard focus from that window if it had focus */
222 if (hWnd == IntGetThreadFocusWindow())
223 {
224 TRACE("IntEnableWindow SF NULL\n");
225 co_UserSetFocus(NULL);
226 }
227 IntSetStyle( pWnd, WS_DISABLED, 0 );
228 }
229
230 if (Update)
231 {
232 IntNotifyWinEvent(EVENT_OBJECT_STATECHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, 0);
233 co_IntSendMessage(hWnd, WM_ENABLE, (LPARAM)bEnable, 0);
234 }
235 // Return nonzero if it was disabled, or zero if it wasn't:
236 return bIsDisabled;
237 }
238
239 /*
240 * IntWinListChildren
241 *
242 * Compile a list of all child window handles from given window.
243 *
244 * Remarks
245 * This function is similar to Wine WIN_ListChildren. The caller
246 * must free the returned list with ExFreePool.
247 */
248
249 HWND* FASTCALL
250 IntWinListChildren(PWND Window)
251 {
252 PWND Child;
253 HWND *List;
254 UINT Index, NumChildren = 0;
255
256 if (!Window) return NULL;
257
258 for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
259 ++NumChildren;
260
261 List = ExAllocatePoolWithTag(PagedPool, (NumChildren + 1) * sizeof(HWND), USERTAG_WINDOWLIST);
262 if(!List)
263 {
264 ERR("Failed to allocate memory for children array\n");
265 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
266 return NULL;
267 }
268 for (Child = Window->spwndChild, Index = 0;
269 Child != NULL;
270 Child = Child->spwndNext, ++Index)
271 List[Index] = Child->head.h;
272 List[Index] = NULL;
273
274 return List;
275 }
276
277 PWND FASTCALL
278 IntGetNonChildAncestor(PWND pWnd)
279 {
280 while(pWnd && (pWnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
281 pWnd = pWnd->spwndParent;
282 return pWnd;
283 }
284
285 BOOL FASTCALL
286 IntIsTopLevelWindow(PWND pWnd)
287 {
288 if ( pWnd->spwndParent &&
289 pWnd->spwndParent == co_GetDesktopWindow(pWnd) ) return TRUE;
290 return FALSE;
291 }
292
293 BOOL FASTCALL
294 IntValidateOwnerDepth(PWND Wnd, PWND Owner)
295 {
296 INT Depth = 1;
297 for (;;)
298 {
299 if ( !Owner ) return gNestedWindowLimit >= Depth;
300 if (Owner == Wnd) break;
301 Owner = Owner->spwndOwner;
302 Depth++;
303 }
304 return FALSE;
305 }
306
307 HWND FASTCALL
308 IntGetWindow(HWND hWnd,
309 UINT uCmd)
310 {
311 PWND Wnd, FoundWnd;
312 HWND Ret = NULL;
313
314 Wnd = ValidateHwndNoErr(hWnd);
315 if (!Wnd)
316 return NULL;
317
318 FoundWnd = NULL;
319 switch (uCmd)
320 {
321 case GW_OWNER:
322 if (Wnd->spwndOwner != NULL)
323 FoundWnd = Wnd->spwndOwner;
324 break;
325
326 case GW_HWNDFIRST:
327 if(Wnd->spwndParent != NULL)
328 {
329 FoundWnd = Wnd->spwndParent;
330 if (FoundWnd->spwndChild != NULL)
331 FoundWnd = FoundWnd->spwndChild;
332 }
333 break;
334 case GW_HWNDNEXT:
335 if (Wnd->spwndNext != NULL)
336 FoundWnd = Wnd->spwndNext;
337 break;
338
339 case GW_HWNDPREV:
340 if (Wnd->spwndPrev != NULL)
341 FoundWnd = Wnd->spwndPrev;
342 break;
343
344 case GW_CHILD:
345 if (Wnd->spwndChild != NULL)
346 FoundWnd = Wnd->spwndChild;
347 break;
348
349 case GW_HWNDLAST:
350 FoundWnd = Wnd;
351 while ( FoundWnd->spwndNext != NULL)
352 FoundWnd = FoundWnd->spwndNext;
353 break;
354
355 default:
356 Wnd = NULL;
357 break;
358 }
359
360 if (FoundWnd != NULL)
361 Ret = UserHMGetHandle(FoundWnd);
362 return Ret;
363 }
364
365 /***********************************************************************
366 * IntSendDestroyMsg
367 */
368 static void IntSendDestroyMsg(HWND hWnd)
369 {
370
371 PWND Window;
372 #if 0 /* FIXME */
373
374 GUITHREADINFO info;
375
376 if (GetGUIThreadInfo(GetCurrentThreadId(), &info))
377 {
378 if (hWnd == info.hwndCaret)
379 {
380 DestroyCaret();
381 }
382 }
383 #endif
384
385 Window = UserGetWindowObject(hWnd);
386 if (Window)
387 {
388 // USER_REFERENCE_ENTRY Ref;
389 // UserRefObjectCo(Window, &Ref);
390
391 if (!Window->spwndOwner && !IntGetParent(Window))
392 {
393 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM) hWnd, 0);
394 }
395
396 // UserDerefObjectCo(Window);
397 }
398
399 /* The window could already be destroyed here */
400
401 /*
402 * Send the WM_DESTROY to the window.
403 */
404
405 co_IntSendMessage(hWnd, WM_DESTROY, 0, 0);
406
407 /*
408 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
409 * make sure that the window still exists when we come back.
410 */
411 #if 0 /* FIXME */
412
413 if (IsWindow(Wnd))
414 {
415 HWND* pWndArray;
416 int i;
417
418 if (!(pWndArray = WIN_ListChildren( hwnd )))
419 return;
420
421 /* start from the end (FIXME: is this needed?) */
422 for (i = 0; pWndArray[i]; i++)
423 ;
424
425 while (--i >= 0)
426 {
427 if (IsWindow( pWndArray[i] ))
428 WIN_SendDestroyMsg( pWndArray[i] );
429 }
430 HeapFree(GetProcessHeap(), 0, pWndArray);
431 }
432 else
433 {
434 TRACE("destroyed itself while in WM_DESTROY!\n");
435 }
436 #endif
437 }
438
439 static VOID
440 UserFreeWindowInfo(PTHREADINFO ti, PWND Wnd)
441 {
442 PCLIENTINFO ClientInfo = GetWin32ClientInfo();
443
444 if (!Wnd) return;
445
446 if (ClientInfo->CallbackWnd.pWnd == DesktopHeapAddressToUser(Wnd))
447 {
448 ClientInfo->CallbackWnd.hWnd = NULL;
449 ClientInfo->CallbackWnd.pWnd = NULL;
450 }
451
452 if (Wnd->strName.Buffer != NULL)
453 {
454 Wnd->strName.Length = 0;
455 Wnd->strName.MaximumLength = 0;
456 DesktopHeapFree(Wnd->head.rpdesk,
457 Wnd->strName.Buffer);
458 Wnd->strName.Buffer = NULL;
459 }
460
461 // DesktopHeapFree(Wnd->head.rpdesk, Wnd);
462 // WindowObject->hWnd = NULL;
463 }
464
465 /***********************************************************************
466 * IntDestroyWindow
467 *
468 * Destroy storage associated to a window. "Internals" p.358
469 *
470 * This is the "functional" DestroyWindows function ei. all stuff
471 * done in CreateWindow is undone here and not in DestroyWindow:-P
472
473 */
474 static LRESULT co_UserFreeWindow(PWND Window,
475 PPROCESSINFO ProcessData,
476 PTHREADINFO ThreadData,
477 BOOLEAN SendMessages)
478 {
479 HWND *Children;
480 HWND *ChildHandle;
481 PWND Child;
482 PMENU Menu;
483 BOOLEAN BelongsToThreadData;
484
485 ASSERT(Window);
486
487 if(Window->state2 & WNDS2_INDESTROY)
488 {
489 TRACE("Tried to call IntDestroyWindow() twice\n");
490 return 0;
491 }
492 Window->state2 |= WNDS2_INDESTROY;
493 Window->style &= ~WS_VISIBLE;
494 Window->head.pti->cVisWindows--;
495
496 IntNotifyWinEvent(EVENT_OBJECT_DESTROY, Window, OBJID_WINDOW, CHILDID_SELF, 0);
497
498 /* remove the window already at this point from the thread window list so we
499 don't get into trouble when destroying the thread windows while we're still
500 in IntDestroyWindow() */
501 RemoveEntryList(&Window->ThreadListEntry);
502
503 BelongsToThreadData = IntWndBelongsToThread(Window, ThreadData);
504
505 IntDeRegisterShellHookWindow(Window->head.h);
506
507 if(SendMessages)
508 {
509 /* Send destroy messages */
510 IntSendDestroyMsg(Window->head.h);
511 }
512
513 /* free child windows */
514 Children = IntWinListChildren(Window);
515 if (Children)
516 {
517 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
518 {
519 if ((Child = IntGetWindowObject(*ChildHandle)))
520 {
521 if(!IntWndBelongsToThread(Child, ThreadData))
522 {
523 /* send WM_DESTROY messages to windows not belonging to the same thread */
524 IntSendDestroyMsg(Child->head.h);
525 }
526 else
527 co_UserFreeWindow(Child, ProcessData, ThreadData, SendMessages);
528
529 UserDereferenceObject(Child);
530 }
531 }
532 ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
533 }
534
535 if(SendMessages)
536 {
537 /*
538 * Clear the update region to make sure no WM_PAINT messages will be
539 * generated for this window while processing the WM_NCDESTROY.
540 */
541 co_UserRedrawWindow(Window, NULL, 0,
542 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE |
543 RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
544 if(BelongsToThreadData)
545 co_IntSendMessage(Window->head.h, WM_NCDESTROY, 0, 0);
546 }
547
548 DestroyTimersForWindow(ThreadData, Window);
549
550 /* Unregister hot keys */
551 UnregisterWindowHotKeys (Window);
552
553 /* flush the message queue */
554 MsqRemoveWindowMessagesFromQueue(Window);
555
556 /* from now on no messages can be sent to this window anymore */
557 Window->state |= WNDS_DESTROYED;
558 Window->fnid |= FNID_FREED;
559
560 /* don't remove the WINDOWSTATUS_DESTROYING bit */
561
562 /* reset shell window handles */
563 if(ThreadData->rpdesk)
564 {
565 if (Window->head.h == ThreadData->rpdesk->rpwinstaParent->ShellWindow)
566 ThreadData->rpdesk->rpwinstaParent->ShellWindow = NULL;
567
568 if (Window->head.h == ThreadData->rpdesk->rpwinstaParent->ShellListView)
569 ThreadData->rpdesk->rpwinstaParent->ShellListView = NULL;
570 }
571
572 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
573
574 #if 0 /* FIXME */
575
576 WinPosCheckInternalPos(Window->head.h);
577 if (Window->head.h == GetCapture())
578 {
579 ReleaseCapture();
580 }
581
582 /* free resources associated with the window */
583 TIMER_RemoveWindowTimers(Window->head.h);
584 #endif
585
586 if ( ((Window->style & (WS_CHILD|WS_POPUP)) != WS_CHILD) &&
587 Window->IDMenu &&
588 (Menu = UserGetMenuObject((HMENU)Window->IDMenu)))
589 {
590 IntDestroyMenuObject(Menu, TRUE);
591 Window->IDMenu = 0;
592 }
593
594 if(Window->SystemMenu
595 && (Menu = UserGetMenuObject(Window->SystemMenu)))
596 {
597 IntDestroyMenuObject(Menu, TRUE);
598 Window->SystemMenu = (HMENU)0;
599 }
600
601 DceFreeWindowDCE(Window); /* Always do this to catch orphaned DCs */
602 #if 0 /* FIXME */
603
604 WINPROC_FreeProc(Window->winproc, WIN_PROC_WINDOW);
605 CLASS_RemoveWindow(Window->Class);
606 #endif
607
608 IntUnlinkWindow(Window);
609
610 if (Window->PropListItems)
611 {
612 IntRemoveWindowProp(Window);
613 TRACE("Window->PropListItems %d\n",Window->PropListItems);
614 ASSERT(Window->PropListItems==0);
615 }
616
617 UserReferenceObject(Window);
618 UserDeleteObject(Window->head.h, TYPE_WINDOW);
619
620 IntDestroyScrollBars(Window);
621
622 /* dereference the class */
623 IntDereferenceClass(Window->pcls,
624 Window->head.pti->pDeskInfo,
625 Window->head.pti->ppi);
626 Window->pcls = NULL;
627
628 if(Window->hrgnClip)
629 {
630 IntGdiSetRegionOwner(Window->hrgnClip, GDI_OBJ_HMGR_POWNED);
631 GreDeleteObject(Window->hrgnClip);
632 Window->hrgnClip = NULL;
633 }
634 Window->head.pti->cWindows--;
635
636 // ASSERT(Window != NULL);
637 UserFreeWindowInfo(Window->head.pti, Window);
638
639 UserDereferenceObject(Window);
640
641 UserClipboardFreeWindow(Window);
642
643 return 0;
644 }
645
646 //
647 // Same as User32:IntGetWndProc.
648 //
649 WNDPROC FASTCALL
650 IntGetWindowProc(PWND pWnd,
651 BOOL Ansi)
652 {
653 INT i;
654 PCLS Class;
655 WNDPROC gcpd, Ret = 0;
656
657 ASSERT(UserIsEnteredExclusive() == TRUE);
658
659 Class = pWnd->pcls;
660
661 if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
662 {
663 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
664 {
665 if (GETPFNSERVER(i) == pWnd->lpfnWndProc)
666 {
667 if (Ansi)
668 Ret = GETPFNCLIENTA(i);
669 else
670 Ret = GETPFNCLIENTW(i);
671 }
672 }
673 return Ret;
674 }
675
676 if (Class->fnid == FNID_EDIT)
677 Ret = pWnd->lpfnWndProc;
678 else
679 {
680 Ret = pWnd->lpfnWndProc;
681
682 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
683 {
684 if (Ansi)
685 {
686 if (GETPFNCLIENTW(Class->fnid) == pWnd->lpfnWndProc)
687 Ret = GETPFNCLIENTA(Class->fnid);
688 }
689 else
690 {
691 if (GETPFNCLIENTA(Class->fnid) == pWnd->lpfnWndProc)
692 Ret = GETPFNCLIENTW(Class->fnid);
693 }
694 }
695 if ( Ret != pWnd->lpfnWndProc)
696 return Ret;
697 }
698 if ( Ansi == !!(pWnd->state & WNDS_ANSIWINDOWPROC) )
699 return Ret;
700
701 gcpd = (WNDPROC)UserGetCPD(
702 pWnd,
703 (Ansi ? UserGetCPDA2U : UserGetCPDU2A )|UserGetCPDWindow,
704 (ULONG_PTR)Ret);
705
706 return (gcpd ? gcpd : Ret);
707 }
708
709 static WNDPROC
710 IntSetWindowProc(PWND pWnd,
711 WNDPROC NewWndProc,
712 BOOL Ansi)
713 {
714 INT i;
715 PCALLPROCDATA CallProc;
716 PCLS Class;
717 WNDPROC Ret, chWndProc = NULL;
718
719 // Retrieve previous window proc.
720 Ret = IntGetWindowProc(pWnd, Ansi);
721
722 Class = pWnd->pcls;
723
724 if (IsCallProcHandle(NewWndProc))
725 {
726 CallProc = UserGetObject(gHandleTable, NewWndProc, TYPE_CALLPROC);
727 if (CallProc)
728 { // Reset new WndProc.
729 NewWndProc = CallProc->pfnClientPrevious;
730 // Reset Ansi from CallProc handle. This is expected with wine "deftest".
731 Ansi = !!(CallProc->wType & UserGetCPDU2A);
732 }
733 }
734 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
735 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
736 {
737 if (GETPFNCLIENTW(i) == NewWndProc)
738 {
739 chWndProc = GETPFNSERVER(i);
740 break;
741 }
742 if (GETPFNCLIENTA(i) == NewWndProc)
743 {
744 chWndProc = GETPFNSERVER(i);
745 break;
746 }
747 }
748 // If match, set/reset to Server Side and clear ansi.
749 if (chWndProc)
750 {
751 pWnd->lpfnWndProc = chWndProc;
752 pWnd->Unicode = TRUE;
753 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
754 pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
755 }
756 else
757 {
758 pWnd->Unicode = !Ansi;
759 // Handle the state change in here.
760 if (Ansi)
761 pWnd->state |= WNDS_ANSIWINDOWPROC;
762 else
763 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
764
765 if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
766 pWnd->state &= ~WNDS_SERVERSIDEWINDOWPROC;
767
768 if (!NewWndProc) NewWndProc = pWnd->lpfnWndProc;
769
770 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
771 {
772 if (Ansi)
773 {
774 if (GETPFNCLIENTW(Class->fnid) == NewWndProc)
775 chWndProc = GETPFNCLIENTA(Class->fnid);
776 }
777 else
778 {
779 if (GETPFNCLIENTA(Class->fnid) == NewWndProc)
780 chWndProc = GETPFNCLIENTW(Class->fnid);
781 }
782 }
783 // Now set the new window proc.
784 pWnd->lpfnWndProc = (chWndProc ? chWndProc : NewWndProc);
785 }
786 return Ret;
787 }
788
789 static BOOL FASTCALL
790 IntSetMenu(
791 PWND Wnd,
792 HMENU Menu,
793 BOOL *Changed)
794 {
795 PMENU OldMenu, NewMenu = NULL;
796
797 if ((Wnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
798 {
799 ERR("SetMenu: Invalid handle 0x%p!\n",UserHMGetHandle(Wnd));
800 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
801 return FALSE;
802 }
803
804 *Changed = (Wnd->IDMenu != (UINT) Menu);
805 if (! *Changed)
806 {
807 return TRUE;
808 }
809
810 if (Wnd->IDMenu)
811 {
812 OldMenu = IntGetMenuObject((HMENU) Wnd->IDMenu);
813 ASSERT(NULL == OldMenu || OldMenu->hWnd == Wnd->head.h);
814 }
815 else
816 {
817 OldMenu = NULL;
818 }
819
820 if (NULL != Menu)
821 {
822 NewMenu = IntGetMenuObject(Menu);
823 if (NULL == NewMenu)
824 {
825 if (NULL != OldMenu)
826 {
827 IntReleaseMenuObject(OldMenu);
828 }
829 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
830 return FALSE;
831 }
832 if (NULL != NewMenu->hWnd)
833 {
834 /* Can't use the same menu for two windows */
835 if (NULL != OldMenu)
836 {
837 IntReleaseMenuObject(OldMenu);
838 }
839 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
840 return FALSE;
841 }
842
843 }
844
845 Wnd->IDMenu = (UINT) Menu;
846 if (NULL != NewMenu)
847 {
848 NewMenu->hWnd = Wnd->head.h;
849 IntReleaseMenuObject(NewMenu);
850 }
851 if (NULL != OldMenu)
852 {
853 OldMenu->hWnd = NULL;
854 IntReleaseMenuObject(OldMenu);
855 }
856
857 return TRUE;
858 }
859
860
861 /* INTERNAL ******************************************************************/
862
863
864 BOOL FASTCALL
865 IntIsChildWindow(PWND Parent, PWND BaseWindow)
866 {
867 PWND Window;
868
869 Window = BaseWindow;
870 while (Window && ((Window->style & (WS_POPUP|WS_CHILD)) == WS_CHILD))
871 {
872 if (Window == Parent)
873 {
874 return(TRUE);
875 }
876
877 Window = Window->spwndParent;
878 }
879
880 return(FALSE);
881 }
882
883 /*
884 Link the window into siblings list
885 children and parent are kept in place.
886 */
887 VOID FASTCALL
888 IntLinkWindow(
889 PWND Wnd,
890 PWND WndInsertAfter /* set to NULL if top sibling */
891 )
892 {
893 if ((Wnd->spwndPrev = WndInsertAfter))
894 {
895 /* link after WndInsertAfter */
896 if ((Wnd->spwndNext = WndInsertAfter->spwndNext))
897 Wnd->spwndNext->spwndPrev = Wnd;
898
899 Wnd->spwndPrev->spwndNext = Wnd;
900 }
901 else
902 {
903 /* link at top */
904 if ((Wnd->spwndNext = Wnd->spwndParent->spwndChild))
905 Wnd->spwndNext->spwndPrev = Wnd;
906
907 Wnd->spwndParent->spwndChild = Wnd;
908 }
909 }
910
911 /*
912 Note: Wnd->spwndParent can be null if it is the desktop.
913 */
914 VOID FASTCALL IntLinkHwnd(PWND Wnd, HWND hWndPrev)
915 {
916 if (hWndPrev == HWND_NOTOPMOST)
917 {
918 if (!(Wnd->ExStyle & WS_EX_TOPMOST) &&
919 (Wnd->ExStyle2 & WS_EX2_LINKED)) return; /* nothing to do */
920 Wnd->ExStyle &= ~WS_EX_TOPMOST;
921 hWndPrev = HWND_TOP; /* fallback to the HWND_TOP case */
922 }
923
924 IntUnlinkWindow(Wnd); /* unlink it from the previous location */
925
926 if (hWndPrev == HWND_BOTTOM)
927 {
928 /* Link in the bottom of the list */
929 PWND WndInsertAfter;
930
931 WndInsertAfter = Wnd->spwndParent->spwndChild;
932 while( WndInsertAfter && WndInsertAfter->spwndNext)
933 WndInsertAfter = WndInsertAfter->spwndNext;
934
935 IntLinkWindow(Wnd, WndInsertAfter);
936 Wnd->ExStyle &= ~WS_EX_TOPMOST;
937 }
938 else if (hWndPrev == HWND_TOPMOST)
939 {
940 /* Link in the top of the list */
941 IntLinkWindow(Wnd, NULL);
942
943 Wnd->ExStyle |= WS_EX_TOPMOST;
944 }
945 else if (hWndPrev == HWND_TOP)
946 {
947 /* Link it after the last topmost window */
948 PWND WndInsertBefore;
949
950 WndInsertBefore = Wnd->spwndParent->spwndChild;
951
952 if (!(Wnd->ExStyle & WS_EX_TOPMOST)) /* put it above the first non-topmost window */
953 {
954 while (WndInsertBefore != NULL && WndInsertBefore->spwndNext != NULL)
955 {
956 if (!(WndInsertBefore->ExStyle & WS_EX_TOPMOST)) break;
957 if (WndInsertBefore == Wnd->spwndOwner) /* keep it above owner */
958 {
959 Wnd->ExStyle |= WS_EX_TOPMOST;
960 break;
961 }
962 WndInsertBefore = WndInsertBefore->spwndNext;
963 }
964 }
965
966 IntLinkWindow(Wnd, WndInsertBefore ? WndInsertBefore->spwndPrev : NULL);
967 }
968 else
969 {
970 /* Link it after hWndPrev */
971 PWND WndInsertAfter;
972
973 WndInsertAfter = UserGetWindowObject(hWndPrev);
974 /* Are we called with an erroneous handle */
975 if(WndInsertAfter == NULL)
976 {
977 /* Link in a default position */
978 IntLinkHwnd(Wnd, HWND_TOP);
979 return;
980 }
981
982 IntLinkWindow(Wnd, WndInsertAfter);
983
984 /* Fix the WS_EX_TOPMOST flag */
985 if (!(WndInsertAfter->ExStyle & WS_EX_TOPMOST))
986 {
987 Wnd->ExStyle &= ~WS_EX_TOPMOST;
988 }
989 else
990 {
991 if(WndInsertAfter->spwndNext &&
992 WndInsertAfter->spwndNext->ExStyle & WS_EX_TOPMOST)
993 {
994 Wnd->ExStyle |= WS_EX_TOPMOST;
995 }
996 }
997 }
998 Wnd->ExStyle2 |= WS_EX2_LINKED;
999 }
1000
1001 VOID FASTCALL
1002 IntProcessOwnerSwap(PWND Wnd, PWND WndNewOwner, PWND WndOldOwner)
1003 {
1004 if (WndOldOwner)
1005 {
1006 if (Wnd->head.pti != WndOldOwner->head.pti)
1007 {
1008 if (!WndNewOwner ||
1009 Wnd->head.pti == WndNewOwner->head.pti ||
1010 WndOldOwner->head.pti != WndNewOwner->head.pti )
1011 {
1012 //ERR("ProcessOwnerSwap Old out.\n");
1013 UserAttachThreadInput(Wnd->head.pti, WndOldOwner->head.pti, FALSE);
1014 }
1015 }
1016 }
1017 if (WndNewOwner)
1018 {
1019 if (Wnd->head.pti != WndNewOwner->head.pti)
1020 {
1021 if (!WndOldOwner ||
1022 WndOldOwner->head.pti != WndNewOwner->head.pti )
1023 {
1024 //ERR("ProcessOwnerSwap New in.\n");
1025 UserAttachThreadInput(Wnd->head.pti, WndNewOwner->head.pti, TRUE);
1026 }
1027 }
1028 }
1029 // FIXME: System Tray checks.
1030 }
1031
1032 HWND FASTCALL
1033 IntSetOwner(HWND hWnd, HWND hWndNewOwner)
1034 {
1035 PWND Wnd, WndOldOwner, WndNewOwner;
1036 HWND ret;
1037
1038 Wnd = IntGetWindowObject(hWnd);
1039 if(!Wnd)
1040 return NULL;
1041
1042 WndOldOwner = Wnd->spwndOwner;
1043
1044 ret = WndOldOwner ? UserHMGetHandle(WndOldOwner) : 0;
1045 WndNewOwner = UserGetWindowObject(hWndNewOwner);
1046
1047 if (!WndNewOwner && hWndNewOwner)
1048 {
1049 EngSetLastError(ERROR_INVALID_PARAMETER);
1050 ret = NULL;
1051 goto Error;
1052 }
1053
1054 /* if parent belongs to a different thread and the window isn't */
1055 /* top-level, attach the two threads */
1056 IntProcessOwnerSwap(Wnd, WndNewOwner, WndOldOwner);
1057
1058 if (IntValidateOwnerDepth(Wnd, WndNewOwner))
1059 {
1060 if (WndNewOwner)
1061 {
1062 Wnd->spwndOwner= WndNewOwner;
1063 }
1064 else
1065 {
1066 Wnd->spwndOwner = NULL;
1067 }
1068 }
1069 else
1070 {
1071 IntProcessOwnerSwap(Wnd, WndOldOwner, WndNewOwner);
1072 EngSetLastError(ERROR_INVALID_PARAMETER);
1073 ret = NULL;
1074 }
1075 Error:
1076 UserDereferenceObject(Wnd);
1077 return ret;
1078 }
1079
1080 PWND FASTCALL
1081 co_IntSetParent(PWND Wnd, PWND WndNewParent)
1082 {
1083 PWND WndOldParent, pWndExam;
1084 BOOL WasVisible;
1085 POINT pt;
1086 int swFlags = SWP_NOSIZE|SWP_NOZORDER;
1087
1088 ASSERT(Wnd);
1089 ASSERT(WndNewParent);
1090 ASSERT_REFS_CO(Wnd);
1091 ASSERT_REFS_CO(WndNewParent);
1092
1093 if (Wnd == Wnd->head.rpdesk->spwndMessage)
1094 {
1095 EngSetLastError(ERROR_ACCESS_DENIED);
1096 return( NULL);
1097 }
1098
1099 /* Some applications try to set a child as a parent */
1100 if (IntIsChildWindow(Wnd, WndNewParent))
1101 {
1102 TRACE("IntSetParent try to set a child as a parent.\n");
1103 EngSetLastError( ERROR_INVALID_PARAMETER );
1104 return NULL;
1105 }
1106
1107 pWndExam = WndNewParent; // Load parent Window to examine.
1108 // Now test for set parent to parent hit.
1109 while (pWndExam)
1110 {
1111 if (Wnd == pWndExam)
1112 {
1113 TRACE("IntSetParent Failed Test for set parent to parent!\n");
1114 EngSetLastError(ERROR_INVALID_PARAMETER);
1115 return NULL;
1116 }
1117 pWndExam = pWndExam->spwndParent;
1118 }
1119
1120 /*
1121 * Windows hides the window first, then shows it again
1122 * including the WM_SHOWWINDOW messages and all
1123 */
1124 WasVisible = co_WinPosShowWindow(Wnd, SW_HIDE);
1125
1126 /* Window must belong to current process */
1127 if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
1128 {
1129 ERR("IntSetParent Window must belong to current process!\n");
1130 return NULL;
1131 }
1132
1133 WndOldParent = Wnd->spwndParent;
1134
1135 if ( WndOldParent &&
1136 WndOldParent->ExStyle & WS_EX_LAYOUTRTL)
1137 pt.x = Wnd->rcWindow.right;
1138 else
1139 pt.x = Wnd->rcWindow.left;
1140 pt.y = Wnd->rcWindow.top;
1141
1142 IntScreenToClient(WndOldParent, &pt);
1143
1144 if (WndOldParent) UserReferenceObject(WndOldParent); /* Caller must deref */
1145
1146 if (WndNewParent != WndOldParent)
1147 {
1148 /* Unlink the window from the siblings list */
1149 IntUnlinkWindow(Wnd);
1150 Wnd->ExStyle2 &= ~WS_EX2_LINKED;
1151
1152 /* Set the new parent */
1153 Wnd->spwndParent = WndNewParent;
1154
1155 if ( Wnd->style & WS_CHILD &&
1156 Wnd->spwndOwner &&
1157 Wnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
1158 {
1159 ERR("SetParent Top Most from Pop up!\n");
1160 Wnd->ExStyle |= WS_EX_TOPMOST;
1161 }
1162
1163 /* Link the window with its new siblings */
1164 IntLinkHwnd( Wnd,
1165 ((0 == (Wnd->ExStyle & WS_EX_TOPMOST) &&
1166 WndNewParent == UserGetDesktopWindow() ) ? HWND_TOP : HWND_TOPMOST ) );
1167
1168 }
1169
1170 if ( WndNewParent == co_GetDesktopWindow(Wnd) &&
1171 !(Wnd->style & WS_CLIPSIBLINGS) )
1172 {
1173 Wnd->style |= WS_CLIPSIBLINGS;
1174 DceResetActiveDCEs(Wnd);
1175 }
1176
1177 /* if parent belongs to a different thread and the window isn't */
1178 /* top-level, attach the two threads */
1179 if ((Wnd->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1180 {
1181 if ( Wnd->spwndParent != co_GetDesktopWindow(Wnd))
1182 {
1183 if (Wnd->head.pti != WndOldParent->head.pti)
1184 {
1185 //ERR("SetParent Old out.\n");
1186 UserAttachThreadInput(Wnd->head.pti, WndOldParent->head.pti, FALSE);
1187 }
1188 }
1189 if ( WndNewParent != co_GetDesktopWindow(Wnd))
1190 {
1191 if (Wnd->head.pti != WndNewParent->head.pti)
1192 {
1193 //ERR("SetParent New in.\n");
1194 UserAttachThreadInput(Wnd->head.pti, WndNewParent->head.pti, TRUE);
1195 }
1196 }
1197 }
1198
1199 if (WndOldParent == UserGetMessageWindow() || WndNewParent == UserGetMessageWindow())
1200 swFlags |= SWP_NOACTIVATE;
1201
1202 IntNotifyWinEvent(EVENT_OBJECT_PARENTCHANGE, Wnd ,OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1203 /*
1204 * SetParent additionally needs to make hwnd the top window
1205 * in the z-order and send the expected WM_WINDOWPOSCHANGING and
1206 * WM_WINDOWPOSCHANGED notification messages.
1207 */
1208 //ERR("IntSetParent SetWindowPos 1\n");
1209 co_WinPosSetWindowPos( Wnd,
1210 (0 == (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOP : HWND_TOPMOST),
1211 pt.x, pt.y, 0, 0, swFlags);
1212 //ERR("IntSetParent SetWindowPos 2 X %d Y %d\n",pt.x, pt.y);
1213 if (WasVisible) co_WinPosShowWindow(Wnd, SW_SHOWNORMAL);
1214
1215 return WndOldParent;
1216 }
1217
1218 HWND FASTCALL
1219 co_UserSetParent(HWND hWndChild, HWND hWndNewParent)
1220 {
1221 PWND Wnd = NULL, WndParent = NULL, WndOldParent;
1222 HWND hWndOldParent = NULL;
1223 USER_REFERENCE_ENTRY Ref, ParentRef;
1224
1225 if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
1226 {
1227 EngSetLastError(ERROR_INVALID_PARAMETER);
1228 return( NULL);
1229 }
1230
1231 if (hWndChild == IntGetDesktopWindow())
1232 {
1233 ERR("UserSetParent Access Denied!\n");
1234 EngSetLastError(ERROR_ACCESS_DENIED);
1235 return( NULL);
1236 }
1237
1238 if (hWndNewParent)
1239 {
1240 if (!(WndParent = UserGetWindowObject(hWndNewParent)))
1241 {
1242 ERR("UserSetParent Bad New Parent!\n");
1243 return( NULL);
1244 }
1245 }
1246 else
1247 {
1248 if (!(WndParent = UserGetWindowObject(IntGetDesktopWindow())))
1249 {
1250 return( NULL);
1251 }
1252 }
1253
1254 if (!(Wnd = UserGetWindowObject(hWndChild)))
1255 {
1256 ERR("UserSetParent Bad Child!\n");
1257 return( NULL);
1258 }
1259
1260 UserRefObjectCo(Wnd, &Ref);
1261 UserRefObjectCo(WndParent, &ParentRef);
1262 //ERR("Enter co_IntSetParent\n");
1263 WndOldParent = co_IntSetParent(Wnd, WndParent);
1264 //ERR("Leave co_IntSetParent\n");
1265 UserDerefObjectCo(WndParent);
1266 UserDerefObjectCo(Wnd);
1267
1268 if (WndOldParent)
1269 {
1270 hWndOldParent = WndOldParent->head.h;
1271 UserDereferenceObject(WndOldParent);
1272 }
1273
1274 return( hWndOldParent);
1275 }
1276
1277 /* Unlink the window from siblings. children and parent are kept in place. */
1278 VOID FASTCALL
1279 IntUnlinkWindow(PWND Wnd)
1280 {
1281 if (Wnd->spwndNext)
1282 Wnd->spwndNext->spwndPrev = Wnd->spwndPrev;
1283
1284 if (Wnd->spwndPrev)
1285 Wnd->spwndPrev->spwndNext = Wnd->spwndNext;
1286
1287 if (Wnd->spwndParent && Wnd->spwndParent->spwndChild == Wnd)
1288 Wnd->spwndParent->spwndChild = Wnd->spwndNext;
1289
1290 Wnd->spwndPrev = Wnd->spwndNext = NULL;
1291 }
1292
1293 /* FUNCTIONS *****************************************************************/
1294
1295 /*
1296 * As best as I can figure, this function is used by EnumWindows,
1297 * EnumChildWindows, EnumDesktopWindows, & EnumThreadWindows.
1298 *
1299 * It's supposed to build a list of HWNDs to return to the caller.
1300 * We can figure out what kind of list by what parameters are
1301 * passed to us.
1302 */
1303 /*
1304 * @implemented
1305 */
1306 NTSTATUS
1307 APIENTRY
1308 NtUserBuildHwndList(
1309 HDESK hDesktop,
1310 HWND hwndParent,
1311 BOOLEAN bChildren,
1312 ULONG dwThreadId,
1313 ULONG lParam,
1314 HWND* pWnd,
1315 ULONG* pBufSize)
1316 {
1317 NTSTATUS Status;
1318 ULONG dwCount = 0;
1319
1320 if (pBufSize == 0)
1321 return ERROR_INVALID_PARAMETER;
1322
1323 if (hwndParent || !dwThreadId)
1324 {
1325 PDESKTOP Desktop;
1326 PWND Parent, Window;
1327
1328 if(!hwndParent)
1329 {
1330 if(hDesktop == NULL && !(Desktop = IntGetActiveDesktop()))
1331 {
1332 return ERROR_INVALID_HANDLE;
1333 }
1334
1335 if(hDesktop)
1336 {
1337 Status = IntValidateDesktopHandle(hDesktop,
1338 UserMode,
1339 0,
1340 &Desktop);
1341 if(!NT_SUCCESS(Status))
1342 {
1343 return ERROR_INVALID_HANDLE;
1344 }
1345 }
1346 hwndParent = Desktop->DesktopWindow;
1347 }
1348 else
1349 {
1350 hDesktop = 0;
1351 }
1352
1353 if((Parent = UserGetWindowObject(hwndParent)) &&
1354 (Window = Parent->spwndChild))
1355 {
1356 BOOL bGoDown = TRUE;
1357
1358 Status = STATUS_SUCCESS;
1359 while(TRUE)
1360 {
1361 if (bGoDown)
1362 {
1363 if(dwCount++ < *pBufSize && pWnd)
1364 {
1365 _SEH2_TRY
1366 {
1367 ProbeForWrite(pWnd, sizeof(HWND), 1);
1368 *pWnd = Window->head.h;
1369 pWnd++;
1370 }
1371 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1372 {
1373 Status = _SEH2_GetExceptionCode();
1374 }
1375 _SEH2_END
1376 if(!NT_SUCCESS(Status))
1377 {
1378 SetLastNtError(Status);
1379 break;
1380 }
1381 }
1382 if (Window->spwndChild && bChildren)
1383 {
1384 Window = Window->spwndChild;
1385 continue;
1386 }
1387 bGoDown = FALSE;
1388 }
1389 if (Window->spwndNext)
1390 {
1391 Window = Window->spwndNext;
1392 bGoDown = TRUE;
1393 continue;
1394 }
1395 Window = Window->spwndParent;
1396 if (Window == Parent)
1397 {
1398 break;
1399 }
1400 }
1401 }
1402
1403 if(hDesktop)
1404 {
1405 ObDereferenceObject(Desktop);
1406 }
1407 }
1408 else // Build EnumThreadWindows list!
1409 {
1410 PETHREAD Thread;
1411 PTHREADINFO W32Thread;
1412 PLIST_ENTRY Current;
1413 PWND Window;
1414
1415 Status = PsLookupThreadByThreadId((HANDLE)dwThreadId, &Thread);
1416 if (!NT_SUCCESS(Status))
1417 {
1418 ERR("Thread Id is not valid!\n");
1419 return ERROR_INVALID_PARAMETER;
1420 }
1421 if (!(W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread))
1422 {
1423 ObDereferenceObject(Thread);
1424 ERR("Thread is not initialized!\n");
1425 return ERROR_INVALID_PARAMETER;
1426 }
1427
1428 Current = W32Thread->WindowListHead.Flink;
1429 while (Current != &(W32Thread->WindowListHead))
1430 {
1431 Window = CONTAINING_RECORD(Current, WND, ThreadListEntry);
1432 ASSERT(Window);
1433
1434 if (dwCount < *pBufSize && pWnd)
1435 {
1436 _SEH2_TRY
1437 {
1438 ProbeForWrite(pWnd, sizeof(HWND), 1);
1439 *pWnd = Window->head.h;
1440 pWnd++;
1441 }
1442 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1443 {
1444 Status = _SEH2_GetExceptionCode();
1445 }
1446 _SEH2_END
1447 if (!NT_SUCCESS(Status))
1448 {
1449 ERR("Failure to build window list!\n");
1450 SetLastNtError(Status);
1451 break;
1452 }
1453 }
1454 dwCount++;
1455 Current = Window->ThreadListEntry.Flink;
1456 }
1457
1458 ObDereferenceObject(Thread);
1459 }
1460
1461 *pBufSize = dwCount;
1462 return STATUS_SUCCESS;
1463 }
1464
1465 static void IntSendParentNotify( PWND pWindow, UINT msg )
1466 {
1467 if ( (pWindow->style & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
1468 !(pWindow->style & WS_EX_NOPARENTNOTIFY))
1469 {
1470 if (pWindow->spwndParent && pWindow->spwndParent != UserGetDesktopWindow())
1471 {
1472 USER_REFERENCE_ENTRY Ref;
1473 UserRefObjectCo(pWindow->spwndParent, &Ref);
1474 co_IntSendMessage( pWindow->spwndParent->head.h,
1475 WM_PARENTNOTIFY,
1476 MAKEWPARAM( msg, pWindow->IDMenu),
1477 (LPARAM)pWindow->head.h );
1478 UserDerefObjectCo(pWindow->spwndParent);
1479 }
1480 }
1481 }
1482
1483 void FASTCALL
1484 IntFixWindowCoordinates(CREATESTRUCTW* Cs, PWND ParentWindow, DWORD* dwShowMode)
1485 {
1486 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1487
1488 /* default positioning for overlapped windows */
1489 if(!(Cs->style & (WS_POPUP | WS_CHILD)))
1490 {
1491 PMONITOR pMonitor;
1492 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
1493
1494 pMonitor = UserGetPrimaryMonitor();
1495
1496 /* Check if we don't have a monitor attached yet */
1497 if(pMonitor == NULL)
1498 {
1499 Cs->x = Cs->y = 0;
1500 Cs->cx = 800;
1501 Cs->cy = 600;
1502 return;
1503 }
1504
1505 ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
1506
1507 if (IS_DEFAULT(Cs->x))
1508 {
1509 if (!IS_DEFAULT(Cs->y)) *dwShowMode = Cs->y;
1510
1511 if(ProcessParams->WindowFlags & STARTF_USEPOSITION)
1512 {
1513 Cs->x = ProcessParams->StartingX;
1514 Cs->y = ProcessParams->StartingY;
1515 }
1516 else
1517 {
1518 Cs->x = pMonitor->cWndStack * (UserGetSystemMetrics(SM_CXSIZE) + UserGetSystemMetrics(SM_CXFRAME));
1519 Cs->y = pMonitor->cWndStack * (UserGetSystemMetrics(SM_CYSIZE) + UserGetSystemMetrics(SM_CYFRAME));
1520 if (Cs->x > ((pMonitor->rcWork.right - pMonitor->rcWork.left) / 4) ||
1521 Cs->y > ((pMonitor->rcWork.bottom - pMonitor->rcWork.top) / 4))
1522 {
1523 /* reset counter and position */
1524 Cs->x = 0;
1525 Cs->y = 0;
1526 pMonitor->cWndStack = 0;
1527 }
1528 pMonitor->cWndStack++;
1529 }
1530 }
1531
1532 if (IS_DEFAULT(Cs->cx))
1533 {
1534 if (ProcessParams->WindowFlags & STARTF_USEPOSITION)
1535 {
1536 Cs->cx = ProcessParams->CountX;
1537 Cs->cy = ProcessParams->CountY;
1538 }
1539 else
1540 {
1541 Cs->cx = (pMonitor->rcWork.right - pMonitor->rcWork.left) * 3 / 4;
1542 Cs->cy = (pMonitor->rcWork.bottom - pMonitor->rcWork.top) * 3 / 4;
1543 }
1544 }
1545 /* neither x nor cx are default. Check the y values .
1546 * In the trace we see Outlook and Outlook Express using
1547 * cy set to CW_USEDEFAULT when opening the address book.
1548 */
1549 else if (IS_DEFAULT(Cs->cy))
1550 {
1551 TRACE("Strange use of CW_USEDEFAULT in nHeight\n");
1552 Cs->cy = (pMonitor->rcWork.bottom - pMonitor->rcWork.top) * 3 / 4;
1553 }
1554 }
1555 else
1556 {
1557 /* if CW_USEDEFAULT is set for non-overlapped windows, both values are set to zero */
1558 if(IS_DEFAULT(Cs->x))
1559 {
1560 Cs->x = 0;
1561 Cs->y = 0;
1562 }
1563 if(IS_DEFAULT(Cs->cx))
1564 {
1565 Cs->cx = 0;
1566 Cs->cy = 0;
1567 }
1568 }
1569
1570 #undef IS_DEFAULT
1571 }
1572
1573 /* Allocates and initializes a window */
1574 PWND FASTCALL IntCreateWindow(CREATESTRUCTW* Cs,
1575 PLARGE_STRING WindowName,
1576 PCLS Class,
1577 PWND ParentWindow,
1578 PWND OwnerWindow,
1579 PVOID acbiBuffer,
1580 PDESKTOP pdeskCreated)
1581 {
1582 PWND pWnd = NULL;
1583 HWND hWnd;
1584 PTHREADINFO pti = NULL;
1585 BOOL MenuChanged;
1586 BOOL bUnicodeWindow;
1587
1588 pti = pdeskCreated ? gptiDesktopThread : GetW32ThreadInfo();
1589
1590 if (!(Cs->dwExStyle & WS_EX_LAYOUTRTL))
1591 { // Need both here for wine win.c test_CreateWindow.
1592 //if (Cs->hwndParent && ParentWindow)
1593 if (ParentWindow) // It breaks more tests..... WIP.
1594 {
1595 if ( (Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD &&
1596 ParentWindow->ExStyle & WS_EX_LAYOUTRTL &&
1597 !(ParentWindow->ExStyle & WS_EX_NOINHERITLAYOUT) )
1598 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1599 }
1600 else
1601 { /*
1602 * Note from MSDN <http://msdn.microsoft.com/en-us/library/aa913269.aspx>:
1603 *
1604 * Dialog boxes and message boxes do not inherit layout, so you must
1605 * set the layout explicitly.
1606 */
1607 if ( Class->fnid != FNID_DIALOG )
1608 {
1609 if (pti->ppi->dwLayout & LAYOUT_RTL)
1610 {
1611 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1612 }
1613 }
1614 }
1615 }
1616
1617 /* Automatically add WS_EX_WINDOWEDGE */
1618 if ((Cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1619 ((!(Cs->dwExStyle & WS_EX_STATICEDGE)) &&
1620 (Cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1621 Cs->dwExStyle |= WS_EX_WINDOWEDGE;
1622 else
1623 Cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1624
1625 /* Is it a unicode window? */
1626 bUnicodeWindow =!(Cs->dwExStyle & WS_EX_SETANSICREATOR);
1627 Cs->dwExStyle &= ~WS_EX_SETANSICREATOR;
1628
1629 /* Allocate the new window */
1630 pWnd = (PWND) UserCreateObject( gHandleTable,
1631 pdeskCreated ? pdeskCreated : pti->rpdesk,
1632 pti,
1633 (PHANDLE)&hWnd,
1634 TYPE_WINDOW,
1635 sizeof(WND) + Class->cbwndExtra);
1636
1637 if (!pWnd)
1638 {
1639 goto AllocError;
1640 }
1641
1642 TRACE("Created window object with handle %p\n", hWnd);
1643
1644 if (pdeskCreated && pdeskCreated->DesktopWindow == NULL )
1645 { /* HACK: Helper for win32csr/desktopbg.c */
1646 /* If there is no desktop window yet, we must be creating it */
1647 TRACE("CreateWindow setting desktop.\n");
1648 pdeskCreated->DesktopWindow = hWnd;
1649 pdeskCreated->pDeskInfo->spwnd = pWnd;
1650 }
1651
1652 /*
1653 * Fill out the structure describing it.
1654 */
1655 /* Remember, pWnd->head is setup in object.c ... */
1656 pWnd->spwndParent = ParentWindow;
1657 pWnd->spwndOwner = OwnerWindow;
1658 pWnd->fnid = 0;
1659 pWnd->spwndLastActive = pWnd;
1660 pWnd->state2 |= WNDS2_WIN40COMPAT; // FIXME!!!
1661 pWnd->pcls = Class;
1662 pWnd->hModule = Cs->hInstance;
1663 pWnd->style = Cs->style & ~WS_VISIBLE;
1664 pWnd->ExStyle = Cs->dwExStyle;
1665 pWnd->cbwndExtra = pWnd->pcls->cbwndExtra;
1666 pWnd->pActCtx = acbiBuffer;
1667 pWnd->InternalPos.MaxPos.x = pWnd->InternalPos.MaxPos.y = -1;
1668 pWnd->InternalPos.IconPos.x = pWnd->InternalPos.IconPos.y = -1;
1669
1670 if (pWnd->spwndParent != NULL && Cs->hwndParent != 0)
1671 {
1672 pWnd->HideFocus = pWnd->spwndParent->HideFocus;
1673 pWnd->HideAccel = pWnd->spwndParent->HideAccel;
1674 }
1675
1676 pWnd->head.pti->cWindows++;
1677 #ifdef NEW_CURSORICON
1678 if (Class->spicn && !Class->spicnSm)
1679 {
1680 HICON IconSmHandle = NULL;
1681 if((Class->spicn->CURSORF_flags & (CURSORF_LRSHARED | CURSORF_FROMRESOURCE))
1682 == (CURSORF_LRSHARED | CURSORF_FROMRESOURCE))
1683 {
1684 IconSmHandle = co_IntCopyImage(
1685 UserHMGetHandle(Class->spicn),
1686 IMAGE_ICON,
1687 UserGetSystemMetrics( SM_CXSMICON ),
1688 UserGetSystemMetrics( SM_CYSMICON ),
1689 LR_COPYFROMRESOURCE | LR_SHARED);
1690 }
1691 if (!IconSmHandle)
1692 {
1693 /* Retry without copying from resource */
1694 IconSmHandle = co_IntCopyImage(
1695 UserHMGetHandle(Class->spicn),
1696 IMAGE_ICON,
1697 UserGetSystemMetrics( SM_CXSMICON ),
1698 UserGetSystemMetrics( SM_CYSMICON ),
1699 LR_SHARED);
1700 }
1701
1702 if (IconSmHandle)
1703 {
1704 Class->spicnSm = UserGetCurIconObject(IconSmHandle);
1705 Class->CSF_flags |= CSF_CACHEDSMICON;
1706 }
1707 }
1708 #else
1709 if (Class->hIcon && !Class->hIconSm)
1710 {
1711 Class->hIconSmIntern = co_IntCopyImage( Class->hIcon, IMAGE_ICON,
1712 UserGetSystemMetrics( SM_CXSMICON ),
1713 UserGetSystemMetrics( SM_CYSMICON ), 0 );
1714 TRACE("IntCreateWindow hIconSmIntern %p\n",Class->hIconSmIntern);
1715 Class->CSF_flags |= CSF_CACHEDSMICON;
1716 }
1717 #endif
1718
1719 if (pWnd->pcls->CSF_flags & CSF_SERVERSIDEPROC)
1720 pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
1721
1722 /* BugBoy Comments: Comment below say that System classes are always created
1723 as UNICODE. In windows, creating a window with the ANSI version of CreateWindow
1724 sets the window to ansi as verified by testing with IsUnicodeWindow API.
1725
1726 No where can I see in code or through testing does the window change back
1727 to ANSI after being created as UNICODE in ROS. I didnt do more testing to
1728 see what problems this would cause. */
1729
1730 // Set WndProc from Class.
1731 pWnd->lpfnWndProc = pWnd->pcls->lpfnWndProc;
1732
1733 // GetWindowProc, test for non server side default classes and set WndProc.
1734 if ( pWnd->pcls->fnid <= FNID_GHOST && pWnd->pcls->fnid >= FNID_BUTTON )
1735 {
1736 if (bUnicodeWindow)
1737 {
1738 if (GETPFNCLIENTA(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1739 pWnd->lpfnWndProc = GETPFNCLIENTW(pWnd->pcls->fnid);
1740 }
1741 else
1742 {
1743 if (GETPFNCLIENTW(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1744 pWnd->lpfnWndProc = GETPFNCLIENTA(pWnd->pcls->fnid);
1745 }
1746 }
1747
1748 // If not an Unicode caller, set Ansi creator bit.
1749 if (!bUnicodeWindow) pWnd->state |= WNDS_ANSICREATOR;
1750
1751 // Clone Class Ansi/Unicode proc type.
1752 if (pWnd->pcls->CSF_flags & CSF_ANSIPROC)
1753 {
1754 pWnd->state |= WNDS_ANSIWINDOWPROC;
1755 pWnd->Unicode = FALSE;
1756 }
1757 else
1758 { /*
1759 * It seems there can be both an Ansi creator and Unicode Class Window
1760 * WndProc, unless the following overriding conditions occur:
1761 */
1762 if ( !bUnicodeWindow &&
1763 ( Class->atomClassName == gpsi->atomSysClass[ICLS_BUTTON] ||
1764 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOBOX] ||
1765 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOLBOX] ||
1766 Class->atomClassName == gpsi->atomSysClass[ICLS_DIALOG] ||
1767 Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT] ||
1768 Class->atomClassName == gpsi->atomSysClass[ICLS_IME] ||
1769 Class->atomClassName == gpsi->atomSysClass[ICLS_LISTBOX] ||
1770 Class->atomClassName == gpsi->atomSysClass[ICLS_MDICLIENT] ||
1771 Class->atomClassName == gpsi->atomSysClass[ICLS_STATIC] ) )
1772 { // Override Class and set the window Ansi WndProc.
1773 pWnd->state |= WNDS_ANSIWINDOWPROC;
1774 pWnd->Unicode = FALSE;
1775 }
1776 else
1777 { // Set the window Unicode WndProc.
1778 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
1779 pWnd->Unicode = TRUE;
1780 }
1781 }
1782
1783 /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx,
1784 then my testing shows that windows (2k and XP) creates a CallProc for it immediately
1785 Dont understand why it does this. */
1786 if (Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT])
1787 {
1788 PCALLPROCDATA CallProc;
1789 CallProc = CreateCallProc(pWnd->head.rpdesk, pWnd->lpfnWndProc, pWnd->Unicode , pWnd->head.pti->ppi);
1790
1791 if (!CallProc)
1792 {
1793 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1794 ERR("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %p\n", hWnd);
1795 }
1796 else
1797 {
1798 UserAddCallProcToClass(pWnd->pcls, CallProc);
1799 }
1800 }
1801
1802 InitializeListHead(&pWnd->PropListHead);
1803 pWnd->PropListItems = 0;
1804
1805 if ( WindowName->Buffer != NULL && WindowName->Length > 0 )
1806 {
1807 pWnd->strName.Buffer = DesktopHeapAlloc(pWnd->head.rpdesk,
1808 WindowName->Length + sizeof(UNICODE_NULL));
1809 if (pWnd->strName.Buffer == NULL)
1810 {
1811 goto AllocError;
1812 }
1813
1814 RtlCopyMemory(pWnd->strName.Buffer, WindowName->Buffer, WindowName->Length);
1815 pWnd->strName.Buffer[WindowName->Length / sizeof(WCHAR)] = L'\0';
1816 pWnd->strName.Length = WindowName->Length;
1817 pWnd->strName.MaximumLength = WindowName->Length + sizeof(UNICODE_NULL);
1818 }
1819
1820 /* Correct the window style. */
1821 if ((pWnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1822 {
1823 pWnd->style |= WS_CLIPSIBLINGS;
1824 if (!(pWnd->style & WS_POPUP))
1825 {
1826 pWnd->style |= WS_CAPTION;
1827 }
1828 }
1829
1830 /* WS_EX_WINDOWEDGE depends on some other styles */
1831 if (pWnd->ExStyle & WS_EX_DLGMODALFRAME)
1832 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1833 else if (pWnd->style & (WS_DLGFRAME | WS_THICKFRAME))
1834 {
1835 if (!((pWnd->ExStyle & WS_EX_STATICEDGE) &&
1836 (pWnd->style & (WS_CHILD | WS_POPUP))))
1837 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1838 }
1839 else
1840 pWnd->ExStyle &= ~WS_EX_WINDOWEDGE;
1841
1842 if (!(pWnd->style & (WS_CHILD | WS_POPUP)))
1843 pWnd->state |= WNDS_SENDSIZEMOVEMSGS;
1844
1845 /* Set the window menu */
1846 if ((Cs->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1847 {
1848 if (Cs->hMenu)
1849 {
1850 IntSetMenu(pWnd, Cs->hMenu, &MenuChanged);
1851 }
1852 else if (pWnd->pcls->lpszMenuName) // Take it from the parent.
1853 {
1854 UNICODE_STRING MenuName;
1855 HMENU hMenu;
1856
1857 if (IS_INTRESOURCE(pWnd->pcls->lpszMenuName))
1858 {
1859 MenuName.Length = 0;
1860 MenuName.MaximumLength = 0;
1861 MenuName.Buffer = pWnd->pcls->lpszMenuName;
1862 }
1863 else
1864 {
1865 RtlInitUnicodeString( &MenuName, pWnd->pcls->lpszMenuName);
1866 }
1867 hMenu = co_IntCallLoadMenu( pWnd->pcls->hModule, &MenuName);
1868 if (hMenu) IntSetMenu(pWnd, hMenu, &MenuChanged);
1869 }
1870 }
1871 else // Not a child
1872 pWnd->IDMenu = (UINT) Cs->hMenu;
1873
1874
1875 if ( ParentWindow &&
1876 ParentWindow != ParentWindow->head.rpdesk->spwndMessage &&
1877 ParentWindow != ParentWindow->head.rpdesk->pDeskInfo->spwnd )
1878 {
1879 PWND Owner = IntGetNonChildAncestor(ParentWindow);
1880
1881 if (!IntValidateOwnerDepth(pWnd, Owner))
1882 {
1883 EngSetLastError(ERROR_INVALID_PARAMETER);
1884 goto Error;
1885 }
1886 if ( pWnd->spwndOwner &&
1887 pWnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
1888 {
1889 pWnd->ExStyle |= WS_EX_TOPMOST;
1890 }
1891 if ( pWnd->spwndOwner &&
1892 Class->atomClassName != gpsi->atomSysClass[ICLS_IME] &&
1893 pti != pWnd->spwndOwner->head.pti)
1894 {
1895 //ERR("CreateWindow Owner in.\n");
1896 UserAttachThreadInput(pti, pWnd->spwndOwner->head.pti, TRUE);
1897 }
1898 }
1899
1900 /* Insert the window into the thread's window list. */
1901 InsertTailList (&pti->WindowListHead, &pWnd->ThreadListEntry);
1902
1903 /* Handle "CS_CLASSDC", it is tested first. */
1904 if ( (pWnd->pcls->style & CS_CLASSDC) && !(pWnd->pcls->pdce) )
1905 { /* One DCE per class to have CLASS. */
1906 pWnd->pcls->pdce = DceAllocDCE( pWnd, DCE_CLASS_DC );
1907 }
1908 else if ( pWnd->pcls->style & CS_OWNDC)
1909 { /* Allocate a DCE for this window. */
1910 DceAllocDCE(pWnd, DCE_WINDOW_DC);
1911 }
1912
1913 return pWnd;
1914
1915 AllocError:
1916 ERR("IntCreateWindow Allocation Error.\n");
1917 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1918 Error:
1919 if(pWnd)
1920 UserDereferenceObject(pWnd);
1921 return NULL;
1922 }
1923
1924 /*
1925 * @implemented
1926 */
1927 PWND FASTCALL
1928 co_UserCreateWindowEx(CREATESTRUCTW* Cs,
1929 PUNICODE_STRING ClassName,
1930 PLARGE_STRING WindowName,
1931 PVOID acbiBuffer)
1932 {
1933 ULONG style;
1934 PWND Window = NULL, ParentWindow = NULL, OwnerWindow;
1935 HWND hWnd, hWndParent, hWndOwner, hwndInsertAfter;
1936 PWINSTATION_OBJECT WinSta;
1937 PCLS Class = NULL;
1938 SIZE Size;
1939 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
1940 CBT_CREATEWNDW * pCbtCreate;
1941 LRESULT Result;
1942 USER_REFERENCE_ENTRY ParentRef, Ref;
1943 PTHREADINFO pti;
1944 DWORD dwShowMode = SW_SHOW;
1945 CREATESTRUCTW *pCsw = NULL;
1946 PVOID pszClass = NULL, pszName = NULL;
1947 PWND ret = NULL;
1948
1949 /* Get the current window station and reference it */
1950 pti = GetW32ThreadInfo();
1951 if (pti == NULL || pti->rpdesk == NULL)
1952 {
1953 ERR("Thread is not attached to a desktop! Cannot create window!\n");
1954 return NULL; // There is nothing to cleanup.
1955 }
1956 WinSta = pti->rpdesk->rpwinstaParent;
1957 ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0);
1958
1959 pCsw = NULL;
1960 pCbtCreate = NULL;
1961
1962 /* Get the class and reference it */
1963 Class = IntGetAndReferenceClass(ClassName, Cs->hInstance, FALSE);
1964 if(!Class)
1965 {
1966 ERR("Failed to find class %wZ\n", ClassName);
1967 goto cleanup;
1968 }
1969
1970 /* Now find the parent and the owner window */
1971 hWndParent = pti->rpdesk->pDeskInfo->spwnd->head.h;
1972 hWndOwner = NULL;
1973
1974 if (Cs->hwndParent == HWND_MESSAGE)
1975 {
1976 Cs->hwndParent = hWndParent = pti->rpdesk->spwndMessage->head.h;
1977 }
1978 else if (Cs->hwndParent)
1979 {
1980 if ((Cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1981 hWndOwner = Cs->hwndParent;
1982 else
1983 hWndParent = Cs->hwndParent;
1984 }
1985 else if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1986 {
1987 ERR("Cannot create a child window without a parrent!\n");
1988 EngSetLastError(ERROR_TLW_WITH_WSCHILD);
1989 goto cleanup; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1990 }
1991
1992 ParentWindow = hWndParent ? UserGetWindowObject(hWndParent): NULL;
1993 OwnerWindow = hWndOwner ? UserGetWindowObject(hWndOwner): NULL;
1994
1995 /* FIXME: Is this correct? */
1996 if(OwnerWindow)
1997 OwnerWindow = UserGetAncestor(OwnerWindow, GA_ROOT);
1998
1999 /* Fix the position and the size of the window */
2000 if (ParentWindow)
2001 {
2002 UserRefObjectCo(ParentWindow, &ParentRef);
2003 IntFixWindowCoordinates(Cs, ParentWindow, &dwShowMode);
2004 }
2005
2006 /* Allocate and initialize the new window */
2007 Window = IntCreateWindow(Cs,
2008 WindowName,
2009 Class,
2010 ParentWindow,
2011 OwnerWindow,
2012 acbiBuffer,
2013 NULL);
2014 if(!Window)
2015 {
2016 ERR("IntCreateWindow failed!\n");
2017 goto cleanup;
2018 }
2019
2020 hWnd = UserHMGetHandle(Window);
2021 hwndInsertAfter = HWND_TOP;
2022
2023 UserRefObjectCo(Window, &Ref);
2024 UserDereferenceObject(Window);
2025 ObDereferenceObject(WinSta);
2026
2027 //// Check for a hook to eliminate overhead. ////
2028 if ( ISITHOOKED(WH_CBT) || (pti->rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_CBT)) )
2029 {
2030 // Allocate the calling structures Justin Case this goes Global.
2031 pCsw = ExAllocatePoolWithTag(NonPagedPool, sizeof(CREATESTRUCTW), TAG_HOOK);
2032 pCbtCreate = ExAllocatePoolWithTag(NonPagedPool, sizeof(CBT_CREATEWNDW), TAG_HOOK);
2033 if (!pCsw || !pCbtCreate)
2034 {
2035 ERR("UserHeapAlloc() failed!\n");
2036 goto cleanup;
2037 }
2038
2039 /* Fill the new CREATESTRUCTW */
2040 RtlCopyMemory(pCsw, Cs, sizeof(CREATESTRUCTW));
2041 pCsw->style = Window->style; /* HCBT_CREATEWND needs the real window style */
2042
2043 // Based on the assumption this is from "unicode source" user32, ReactOS, answer is yes.
2044 if (!IS_ATOM(ClassName->Buffer))
2045 {
2046 if (Window->state & WNDS_ANSICREATOR)
2047 {
2048 ANSI_STRING AnsiString;
2049 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(ClassName)+sizeof(CHAR);
2050 pszClass = UserHeapAlloc(AnsiString.MaximumLength);
2051 if (!pszClass)
2052 {
2053 ERR("UserHeapAlloc() failed!\n");
2054 goto cleanup;
2055 }
2056 RtlZeroMemory(pszClass, AnsiString.MaximumLength);
2057 AnsiString.Buffer = (PCHAR)pszClass;
2058 RtlUnicodeStringToAnsiString(&AnsiString, ClassName, FALSE);
2059 }
2060 else
2061 {
2062 UNICODE_STRING UnicodeString;
2063 UnicodeString.MaximumLength = ClassName->Length + sizeof(UNICODE_NULL);
2064 pszClass = UserHeapAlloc(UnicodeString.MaximumLength);
2065 if (!pszClass)
2066 {
2067 ERR("UserHeapAlloc() failed!\n");
2068 goto cleanup;
2069 }
2070 RtlZeroMemory(pszClass, UnicodeString.MaximumLength);
2071 UnicodeString.Buffer = (PWSTR)pszClass;
2072 RtlCopyUnicodeString(&UnicodeString, ClassName);
2073 }
2074 pCsw->lpszClass = UserHeapAddressToUser(pszClass);
2075 }
2076 if (WindowName->Length)
2077 {
2078 UNICODE_STRING Name;
2079 Name.Buffer = WindowName->Buffer;
2080 Name.Length = (USHORT)min(WindowName->Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2081 Name.MaximumLength = (USHORT)min(WindowName->MaximumLength, MAXUSHORT);
2082
2083 if (Window->state & WNDS_ANSICREATOR)
2084 {
2085 ANSI_STRING AnsiString;
2086 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(&Name) + sizeof(CHAR);
2087 pszName = UserHeapAlloc(AnsiString.MaximumLength);
2088 if (!pszName)
2089 {
2090 ERR("UserHeapAlloc() failed!\n");
2091 goto cleanup;
2092 }
2093 RtlZeroMemory(pszName, AnsiString.MaximumLength);
2094 AnsiString.Buffer = (PCHAR)pszName;
2095 RtlUnicodeStringToAnsiString(&AnsiString, &Name, FALSE);
2096 }
2097 else
2098 {
2099 UNICODE_STRING UnicodeString;
2100 UnicodeString.MaximumLength = Name.Length + sizeof(UNICODE_NULL);
2101 pszName = UserHeapAlloc(UnicodeString.MaximumLength);
2102 if (!pszName)
2103 {
2104 ERR("UserHeapAlloc() failed!\n");
2105 goto cleanup;
2106 }
2107 RtlZeroMemory(pszName, UnicodeString.MaximumLength);
2108 UnicodeString.Buffer = (PWSTR)pszName;
2109 RtlCopyUnicodeString(&UnicodeString, &Name);
2110 }
2111 pCsw->lpszName = UserHeapAddressToUser(pszName);
2112 }
2113
2114 pCbtCreate->lpcs = pCsw;
2115 pCbtCreate->hwndInsertAfter = hwndInsertAfter;
2116
2117 //// Call the WH_CBT hook ////
2118 Result = co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) pCbtCreate);
2119 if (Result != 0)
2120 {
2121 ERR("WH_CBT HCBT_CREATEWND hook failed! 0x%x\n", Result);
2122 goto cleanup;
2123 }
2124 // Write back changes.
2125 Cs->cx = pCsw->cx;
2126 Cs->cy = pCsw->cy;
2127 Cs->x = pCsw->x;
2128 Cs->y = pCsw->y;
2129 hwndInsertAfter = pCbtCreate->hwndInsertAfter;
2130 }
2131
2132 /* NCCREATE and WM_NCCALCSIZE need the original values */
2133 Cs->lpszName = (LPCWSTR) WindowName;
2134 Cs->lpszClass = (LPCWSTR) ClassName;
2135
2136 if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
2137 {
2138 if (ParentWindow != co_GetDesktopWindow(Window))
2139 {
2140 Cs->x += ParentWindow->rcClient.left;
2141 Cs->y += ParentWindow->rcClient.top;
2142 }
2143 }
2144
2145 /* Send the WM_GETMINMAXINFO message */
2146 Size.cx = Cs->cx;
2147 Size.cy = Cs->cy;
2148
2149 if ((Cs->style & WS_THICKFRAME) || !(Cs->style & (WS_POPUP | WS_CHILD)))
2150 {
2151 co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack, &MaxTrack);
2152 if (Size.cx > MaxTrack.x) Size.cx = MaxTrack.x;
2153 if (Size.cy > MaxTrack.y) Size.cy = MaxTrack.y;
2154 if (Size.cx < MinTrack.x) Size.cx = MinTrack.x;
2155 if (Size.cy < MinTrack.y) Size.cy = MinTrack.y;
2156 }
2157
2158 Window->rcWindow.left = Cs->x;
2159 Window->rcWindow.top = Cs->y;
2160 Window->rcWindow.right = Cs->x + Size.cx;
2161 Window->rcWindow.bottom = Cs->y + Size.cy;
2162 /*
2163 if (0 != (Window->style & WS_CHILD) && ParentWindow)
2164 {
2165 ERR("co_UserCreateWindowEx(): Offset rcWindow\n");
2166 RECTL_vOffsetRect(&Window->rcWindow,
2167 ParentWindow->rcClient.left,
2168 ParentWindow->rcClient.top);
2169 }
2170 */
2171 /* correct child window coordinates if mirroring on parent is enabled */
2172 if (ParentWindow != NULL)
2173 {
2174 if ( ((Cs->style & WS_CHILD) == WS_CHILD) &&
2175 ((ParentWindow->ExStyle & WS_EX_LAYOUTRTL) == WS_EX_LAYOUTRTL))
2176 {
2177 Window->rcWindow.right = ParentWindow->rcClient.right - (Window->rcWindow.left - ParentWindow->rcClient.left);
2178 Window->rcWindow.left = Window->rcWindow.right - Size.cx;
2179 }
2180 }
2181
2182 Window->rcClient = Window->rcWindow;
2183
2184 /* Link the window */
2185 if (NULL != ParentWindow)
2186 {
2187 /* Link the window into the siblings list */
2188 if ((Cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
2189 IntLinkHwnd(Window, HWND_BOTTOM);
2190 else
2191 IntLinkHwnd(Window, hwndInsertAfter);
2192 }
2193
2194 if (!(Window->state2 & WNDS2_WIN31COMPAT))
2195 {
2196 if (Class->style & CS_PARENTDC && !(ParentWindow->style & WS_CLIPCHILDREN))
2197 Window->style &= ~(WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
2198 }
2199
2200 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2201 {
2202 if ( !IntIsTopLevelWindow(Window) )
2203 {
2204 if (pti != Window->spwndParent->head.pti)
2205 {
2206 //ERR("CreateWindow Parent in.\n");
2207 UserAttachThreadInput(pti, Window->spwndParent->head.pti, TRUE);
2208 }
2209 }
2210 }
2211
2212 /* Send the NCCREATE message */
2213 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_NCCREATE, 0, (LPARAM) Cs);
2214 if (!Result)
2215 {
2216 ERR("co_UserCreateWindowEx(): NCCREATE message failed\n");
2217 goto cleanup;
2218 }
2219
2220 /* Send the WM_NCCALCSIZE message */
2221 {
2222 // RECT rc;
2223 MaxPos.x = Window->rcWindow.left;
2224 MaxPos.y = Window->rcWindow.top;
2225
2226 Result = co_WinPosGetNonClientSize(Window, &Window->rcWindow, &Window->rcClient);
2227 //rc = Window->rcWindow;
2228 //Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM)&rc);
2229 //Window->rcClient = rc;
2230
2231 RECTL_vOffsetRect(&Window->rcWindow, MaxPos.x - Window->rcWindow.left,
2232 MaxPos.y - Window->rcWindow.top);
2233 }
2234
2235 /* Send the WM_CREATE message. */
2236 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_CREATE, 0, (LPARAM) Cs);
2237 if (Result == (LRESULT)-1)
2238 {
2239 ERR("co_UserCreateWindowEx(): WM_CREATE message failed\n");
2240 goto cleanup;
2241 }
2242
2243 /* Send the EVENT_OBJECT_CREATE event */
2244 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_WINDOW, CHILDID_SELF, 0);
2245
2246 /* By setting the flag below it can be examined to determine if the window
2247 was created successfully and a valid pwnd was passed back to caller since
2248 from here the function has to succeed. */
2249 Window->state2 |= WNDS2_WMCREATEMSGPROCESSED;
2250
2251 /* Send the WM_SIZE and WM_MOVE messages. */
2252 if (!(Window->state & WNDS_SENDSIZEMOVEMSGS))
2253 {
2254 co_WinPosSendSizeMove(Window);
2255 }
2256
2257 /* Show or maybe minimize or maximize the window. */
2258
2259 style = IntSetStyle( Window, 0, WS_MAXIMIZE | WS_MINIMIZE );
2260 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2261 {
2262 RECTL NewPos;
2263 UINT SwFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
2264
2265 SwFlag = co_WinPosMinMaximize(Window, SwFlag, &NewPos);
2266 SwFlag |= SWP_NOZORDER|SWP_FRAMECHANGED; /* Frame always gets changed */
2267 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || UserGetActiveWindow()) SwFlag |= SWP_NOACTIVATE;
2268 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
2269 NewPos.right, NewPos.bottom, SwFlag);
2270 }
2271
2272 /* Send the WM_PARENTNOTIFY message */
2273 IntSendParentNotify(Window, WM_CREATE);
2274
2275 /* Notify the shell that a new window was created */
2276 if (Window->spwndParent == UserGetDesktopWindow() &&
2277 Window->spwndOwner == NULL &&
2278 (Window->style & WS_VISIBLE) &&
2279 (!(Window->ExStyle & WS_EX_TOOLWINDOW) ||
2280 (Window->ExStyle & WS_EX_APPWINDOW)))
2281 {
2282 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)hWnd, 0);
2283 }
2284
2285 /* Initialize and show the window's scrollbars */
2286 if (Window->style & WS_VSCROLL)
2287 {
2288 co_UserShowScrollBar(Window, SB_VERT, FALSE, TRUE);
2289 }
2290 if (Window->style & WS_HSCROLL)
2291 {
2292 co_UserShowScrollBar(Window, SB_HORZ, TRUE, FALSE);
2293 }
2294
2295 /* Show the new window */
2296 if (Cs->style & WS_VISIBLE)
2297 {
2298 if (Window->style & WS_MAXIMIZE)
2299 dwShowMode = SW_SHOW;
2300 else if (Window->style & WS_MINIMIZE)
2301 dwShowMode = SW_SHOWMINIMIZED;
2302
2303 co_WinPosShowWindow(Window, dwShowMode);
2304
2305 if (Window->ExStyle & WS_EX_MDICHILD)
2306 {
2307 ASSERT(ParentWindow);
2308 if(!ParentWindow)
2309 goto cleanup;
2310 co_IntSendMessage(UserHMGetHandle(ParentWindow), WM_MDIREFRESHMENU, 0, 0);
2311 /* ShowWindow won't activate child windows */
2312 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2313 }
2314 }
2315
2316 TRACE("co_UserCreateWindowEx(): Created window %p\n", hWnd);
2317 ret = Window;
2318
2319 cleanup:
2320 if (!ret)
2321 {
2322 TRACE("co_UserCreateWindowEx(): Error Created window!\n");
2323 /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */
2324 if (Window)
2325 co_UserDestroyWindow(Window);
2326 else if (Class)
2327 IntDereferenceClass(Class, pti->pDeskInfo, pti->ppi);
2328 }
2329
2330 if (pCsw) ExFreePoolWithTag(pCsw, TAG_HOOK);
2331 if (pCbtCreate) ExFreePoolWithTag(pCbtCreate, TAG_HOOK);
2332 if (pszName) UserHeapFree(pszName);
2333 if (pszClass) UserHeapFree(pszClass);
2334
2335 if (Window)
2336 {
2337 UserDerefObjectCo(Window);
2338 }
2339 if (ParentWindow) UserDerefObjectCo(ParentWindow);
2340
2341 return ret;
2342 }
2343
2344 NTSTATUS
2345 NTAPI
2346 ProbeAndCaptureLargeString(
2347 OUT PLARGE_STRING plstrSafe,
2348 IN PLARGE_STRING plstrUnsafe)
2349 {
2350 LARGE_STRING lstrTemp;
2351 PVOID pvBuffer = NULL;
2352
2353 _SEH2_TRY
2354 {
2355 /* Probe and copy the string */
2356 ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
2357 lstrTemp = *plstrUnsafe;
2358 }
2359 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2360 {
2361 /* Fail */
2362 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2363 }
2364 _SEH2_END
2365
2366 if (lstrTemp.Length != 0)
2367 {
2368 /* Allocate a buffer from paged pool */
2369 pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
2370 if (!pvBuffer)
2371 {
2372 return STATUS_NO_MEMORY;
2373 }
2374
2375 _SEH2_TRY
2376 {
2377 /* Probe and copy the buffer */
2378 ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
2379 RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
2380 }
2381 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2382 {
2383 /* Cleanup and fail */
2384 ExFreePoolWithTag(pvBuffer, TAG_STRING);
2385 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2386 }
2387 _SEH2_END
2388 }
2389
2390 /* Set the output string */
2391 plstrSafe->Buffer = pvBuffer;
2392 plstrSafe->Length = lstrTemp.Length;
2393 plstrSafe->MaximumLength = lstrTemp.Length;
2394
2395 return STATUS_SUCCESS;
2396 }
2397
2398 /**
2399 * \todo Allow passing plstrClassName as ANSI.
2400 */
2401 HWND
2402 NTAPI
2403 NtUserCreateWindowEx(
2404 DWORD dwExStyle,
2405 PLARGE_STRING plstrClassName,
2406 PLARGE_STRING plstrClsVersion,
2407 PLARGE_STRING plstrWindowName,
2408 DWORD dwStyle,
2409 int x,
2410 int y,
2411 int nWidth,
2412 int nHeight,
2413 HWND hWndParent,
2414 HMENU hMenu,
2415 HINSTANCE hInstance,
2416 LPVOID lpParam,
2417 DWORD dwFlags,
2418 PVOID acbiBuffer)
2419 {
2420 NTSTATUS Status;
2421 LARGE_STRING lstrWindowName;
2422 LARGE_STRING lstrClassName;
2423 UNICODE_STRING ustrClassName;
2424 CREATESTRUCTW Cs;
2425 HWND hwnd = NULL;
2426 PWND pwnd;
2427
2428 lstrWindowName.Buffer = NULL;
2429 lstrClassName.Buffer = NULL;
2430
2431 ASSERT(plstrWindowName);
2432
2433 if ( (dwStyle & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2434 {
2435 /* check hMenu is valid handle */
2436 if (hMenu && !UserGetMenuObject(hMenu))
2437 {
2438 ERR("NtUserCreateWindowEx: Got an invalid menu handle!\n");
2439 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
2440 return NULL;
2441 }
2442 }
2443
2444 /* Copy the window name to kernel mode */
2445 Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
2446 if (!NT_SUCCESS(Status))
2447 {
2448 ERR("NtUserCreateWindowEx: failed to capture plstrWindowName\n");
2449 SetLastNtError(Status);
2450 return NULL;
2451 }
2452
2453 plstrWindowName = &lstrWindowName;
2454
2455 /* Check if the class is an atom */
2456 if (IS_ATOM(plstrClassName))
2457 {
2458 /* It is, pass the atom in the UNICODE_STRING */
2459 ustrClassName.Buffer = (PVOID)plstrClassName;
2460 ustrClassName.Length = 0;
2461 ustrClassName.MaximumLength = 0;
2462 }
2463 else
2464 {
2465 /* It's not, capture the class name */
2466 Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
2467 if (!NT_SUCCESS(Status))
2468 {
2469 ERR("NtUserCreateWindowEx: failed to capture plstrClassName\n");
2470 /* Set last error, cleanup and return */
2471 SetLastNtError(Status);
2472 goto cleanup;
2473 }
2474
2475 /* We pass it on as a UNICODE_STRING */
2476 ustrClassName.Buffer = lstrClassName.Buffer;
2477 ustrClassName.Length = (USHORT)min(lstrClassName.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2478 ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT);
2479 }
2480
2481 /* Fill the CREATESTRUCTW */
2482 /* we will keep here the original parameters */
2483 Cs.style = dwStyle;
2484 Cs.lpCreateParams = lpParam;
2485 Cs.hInstance = hInstance;
2486 Cs.hMenu = hMenu;
2487 Cs.hwndParent = hWndParent;
2488 Cs.cx = nWidth;
2489 Cs.cy = nHeight;
2490 Cs.x = x;
2491 Cs.y = y;
2492 Cs.lpszName = (LPCWSTR) plstrWindowName->Buffer;
2493 if (IS_ATOM(plstrClassName))
2494 Cs.lpszClass = (LPCWSTR) plstrClassName;
2495 else
2496 Cs.lpszClass = (LPCWSTR) plstrClassName->Buffer;
2497 Cs.dwExStyle = dwExStyle;
2498
2499 UserEnterExclusive();
2500
2501 /* Call the internal function */
2502 pwnd = co_UserCreateWindowEx(&Cs, &ustrClassName, plstrWindowName, acbiBuffer);
2503
2504 if(!pwnd)
2505 {
2506 ERR("co_UserCreateWindowEx failed!\n");
2507 }
2508 hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
2509
2510 UserLeave();
2511
2512 cleanup:
2513 if (lstrWindowName.Buffer)
2514 {
2515 ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
2516 }
2517 if (lstrClassName.Buffer)
2518 {
2519 ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
2520 }
2521
2522 return hwnd;
2523 }
2524
2525
2526 BOOLEAN co_UserDestroyWindow(PVOID Object)
2527 {
2528 HWND hWnd;
2529 PWND pwndTemp;
2530 PTHREADINFO ti;
2531 MSG msg;
2532 PWND Window = Object;
2533
2534 ASSERT_REFS_CO(Window); // FIXME: Temp HACK?
2535
2536 hWnd = Window->head.h;
2537 ti = PsGetCurrentThreadWin32Thread();
2538
2539 TRACE("co_UserDestroyWindow \n");
2540
2541 /* Check for owner thread */
2542 if ( Window->head.pti != PsGetCurrentThreadWin32Thread())
2543 {
2544 /* Check if we are destroying the desktop window */
2545 if (! ((Window->head.rpdesk->dwDTFlags & DF_DESTROYED) && Window == Window->head.rpdesk->pDeskInfo->spwnd))
2546 {
2547 EngSetLastError(ERROR_ACCESS_DENIED);
2548 return FALSE;
2549 }
2550 }
2551
2552 /* If window was created successfully and it is hooked */
2553 if ((Window->state2 & WNDS2_WMCREATEMSGPROCESSED))
2554 {
2555 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0))
2556 {
2557 ERR("Destroy Window WH_CBT Call Hook return!\n");
2558 return FALSE;
2559 }
2560 }
2561
2562 if (Window->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME])
2563 {
2564 if ((Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2565 {
2566 if (Window->spwndOwner)
2567 {
2568 //ERR("DestroyWindow Owner out.\n");
2569 UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE);
2570 }
2571 }
2572 }
2573
2574 /* Inform the parent */
2575 if (Window->style & WS_CHILD)
2576 {
2577 IntSendParentNotify(Window, WM_DESTROY);
2578 }
2579
2580 /* Look whether the focus is within the tree of windows we will
2581 * be destroying.
2582 */
2583 if (!co_WinPosShowWindow(Window, SW_HIDE))
2584 { // Rule #1.
2585 if (ti->MessageQueue->spwndActive == Window && ti->MessageQueue == IntGetFocusMessageQueue())
2586 {
2587 co_WinPosActivateOtherWindow(Window);
2588 }
2589 }
2590
2591 // Adjust last active.
2592 if ((pwndTemp = Window->spwndOwner))
2593 {
2594 while (pwndTemp->spwndOwner)
2595 pwndTemp = pwndTemp->spwndOwner;
2596
2597 if (pwndTemp->spwndLastActive == Window)
2598 pwndTemp->spwndLastActive = Window->spwndOwner;
2599 }
2600
2601 if (Window->spwndParent && IntIsWindow(Window->head.h))
2602 {
2603 if ((Window->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
2604 {
2605 if (!IntIsTopLevelWindow(Window))
2606 {
2607 //ERR("DestroyWindow Parent out.\n");
2608 UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE);
2609 }
2610 }
2611 }
2612
2613 if (Window->head.pti->MessageQueue->spwndActive == Window)
2614 Window->head.pti->MessageQueue->spwndActive = NULL;
2615 if (Window->head.pti->MessageQueue->spwndFocus == Window)
2616 Window->head.pti->MessageQueue->spwndFocus = NULL;
2617 if (Window->head.pti->MessageQueue->spwndActivePrev == Window)
2618 Window->head.pti->MessageQueue->spwndActivePrev = NULL;
2619 if (Window->head.pti->MessageQueue->spwndCapture == Window)
2620 Window->head.pti->MessageQueue->spwndCapture = NULL;
2621
2622 /*
2623 * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
2624 */
2625
2626 if ((ti != NULL) && (ti->pDeskInfo != NULL))
2627 {
2628 if (ti->pDeskInfo->hShellWindow == hWnd)
2629 {
2630 ERR("Destroying the ShellWindow!\n");
2631 ti->pDeskInfo->hShellWindow = NULL;
2632 }
2633 }
2634
2635 IntEngWindowChanged(Window, WOC_DELETE);
2636
2637 if (!IntIsWindow(Window->head.h))
2638 {
2639 return TRUE;
2640 }
2641
2642 /* Recursively destroy owned windows */
2643
2644 if (! (Window->style & WS_CHILD))
2645 {
2646 for (;;)
2647 {
2648 BOOL GotOne = FALSE;
2649 HWND *Children;
2650 HWND *ChildHandle;
2651 PWND Child, Desktop;
2652
2653 Desktop = IntIsDesktopWindow(Window) ? Window :
2654 UserGetWindowObject(IntGetDesktopWindow());
2655 Children = IntWinListChildren(Desktop);
2656
2657 if (Children)
2658 {
2659 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
2660 {
2661 Child = UserGetWindowObject(*ChildHandle);
2662 if (Child == NULL)
2663 continue;
2664 if (Child->spwndOwner != Window)
2665 {
2666 continue;
2667 }
2668
2669 if (IntWndBelongsToThread(Child, PsGetCurrentThreadWin32Thread()))
2670 {
2671 USER_REFERENCE_ENTRY ChildRef;
2672 UserRefObjectCo(Child, &ChildRef); // Temp HACK?
2673 co_UserDestroyWindow(Child);
2674 UserDerefObjectCo(Child); // Temp HACK?
2675
2676 GotOne = TRUE;
2677 continue;
2678 }
2679
2680 if (Child->spwndOwner != NULL)
2681 {
2682 Child->spwndOwner = NULL;
2683 }
2684
2685 }
2686 ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
2687 }
2688 if (! GotOne)
2689 {
2690 break;
2691 }
2692 }
2693 }
2694
2695 /* Generate mouse move message for the next window */
2696 msg.message = WM_MOUSEMOVE;
2697 msg.wParam = UserGetMouseButtonsState();
2698 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2699 msg.pt = gpsi->ptCursor;
2700 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2701
2702 if (!IntIsWindow(Window->head.h))
2703 {
2704 return TRUE;
2705 }
2706
2707 /* Destroy the window storage */
2708 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
2709
2710 return TRUE;
2711 }
2712
2713
2714 /*
2715 * @implemented
2716 */
2717 BOOLEAN APIENTRY
2718 NtUserDestroyWindow(HWND Wnd)
2719 {
2720 PWND Window;
2721 DECLARE_RETURN(BOOLEAN);
2722 BOOLEAN ret;
2723 USER_REFERENCE_ENTRY Ref;
2724
2725 TRACE("Enter NtUserDestroyWindow\n");
2726 UserEnterExclusive();
2727
2728 if (!(Window = UserGetWindowObject(Wnd)))
2729 {
2730 RETURN(FALSE);
2731 }
2732
2733 UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy...
2734 ret = co_UserDestroyWindow(Window);
2735 UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy...
2736
2737 RETURN(ret);
2738
2739 CLEANUP:
2740 TRACE("Leave NtUserDestroyWindow, ret=%u\n", _ret_);
2741 UserLeave();
2742 END_CLEANUP;
2743 }
2744
2745
2746 static HWND FASTCALL
2747 IntFindWindow(PWND Parent,
2748 PWND ChildAfter,
2749 RTL_ATOM ClassAtom,
2750 PUNICODE_STRING WindowName)
2751 {
2752 BOOL CheckWindowName;
2753 HWND *List, *phWnd;
2754 HWND Ret = NULL;
2755 UNICODE_STRING CurrentWindowName;
2756
2757 ASSERT(Parent);
2758
2759 CheckWindowName = WindowName->Buffer != 0;
2760
2761 if((List = IntWinListChildren(Parent)))
2762 {
2763 phWnd = List;
2764 if(ChildAfter)
2765 {
2766 /* skip handles before and including ChildAfter */
2767 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2768 ;
2769 }
2770
2771 /* search children */
2772 while(*phWnd)
2773 {
2774 PWND Child;
2775 if(!(Child = UserGetWindowObject(*(phWnd++))))
2776 {
2777 continue;
2778 }
2779
2780 /* Do not send WM_GETTEXT messages in the kernel mode version!
2781 The user mode version however calls GetWindowText() which will
2782 send WM_GETTEXT messages to windows belonging to its processes */
2783 if (!ClassAtom || Child->pcls->atomClassName == ClassAtom)
2784 {
2785 // FIXME: LARGE_STRING truncated
2786 CurrentWindowName.Buffer = Child->strName.Buffer;
2787 CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT);
2788 CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT);
2789 if(!CheckWindowName ||
2790 (Child->strName.Length < 0xFFFF &&
2791 !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
2792 {
2793 Ret = Child->head.h;
2794 break;
2795 }
2796 }
2797 }
2798 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2799 }
2800
2801 return Ret;
2802 }
2803
2804 /*
2805 * FUNCTION:
2806 * Searches a window's children for a window with the specified
2807 * class and name
2808 * ARGUMENTS:
2809 * hwndParent = The window whose childs are to be searched.
2810 * NULL = desktop
2811 * HWND_MESSAGE = message-only windows
2812 *
2813 * hwndChildAfter = Search starts after this child window.
2814 * NULL = start from beginning
2815 *
2816 * ucClassName = Class name to search for
2817 * Reguired parameter.
2818 *
2819 * ucWindowName = Window name
2820 * ->Buffer == NULL = don't care
2821 *
2822 * RETURNS:
2823 * The HWND of the window if it was found, otherwise NULL
2824 */
2825 /*
2826 * @implemented
2827 */
2828 HWND APIENTRY
2829 NtUserFindWindowEx(HWND hwndParent,
2830 HWND hwndChildAfter,
2831 PUNICODE_STRING ucClassName,
2832 PUNICODE_STRING ucWindowName,
2833 DWORD dwUnknown)
2834 {
2835 PWND Parent, ChildAfter;
2836 UNICODE_STRING ClassName = {0}, WindowName = {0};
2837 HWND Desktop, Ret = NULL;
2838 BOOL DoMessageWnd = FALSE;
2839 RTL_ATOM ClassAtom = (RTL_ATOM)0;
2840 DECLARE_RETURN(HWND);
2841
2842 TRACE("Enter NtUserFindWindowEx\n");
2843 UserEnterShared();
2844
2845 if (ucClassName != NULL || ucWindowName != NULL)
2846 {
2847 _SEH2_TRY
2848 {
2849 if (ucClassName != NULL)
2850 {
2851 ClassName = ProbeForReadUnicodeString(ucClassName);
2852 if (ClassName.Length != 0)
2853 {
2854 ProbeForRead(ClassName.Buffer,
2855 ClassName.Length,
2856 sizeof(WCHAR));
2857 }
2858 else if (!IS_ATOM(ClassName.Buffer))
2859 {
2860 EngSetLastError(ERROR_INVALID_PARAMETER);
2861 _SEH2_LEAVE;
2862 }
2863
2864 if (!IntGetAtomFromStringOrAtom(&ClassName,
2865 &ClassAtom))
2866 {
2867 _SEH2_LEAVE;
2868 }
2869 }
2870
2871 if (ucWindowName != NULL)
2872 {
2873 WindowName = ProbeForReadUnicodeString(ucWindowName);
2874 if (WindowName.Length != 0)
2875 {
2876 ProbeForRead(WindowName.Buffer,
2877 WindowName.Length,
2878 sizeof(WCHAR));
2879 }
2880 }
2881 }
2882 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2883 {
2884 SetLastNtError(_SEH2_GetExceptionCode());
2885 _SEH2_YIELD(RETURN(NULL));
2886 }
2887 _SEH2_END;
2888
2889 if (ucClassName != NULL)
2890 {
2891 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
2892 !IS_ATOM(ClassName.Buffer))
2893 {
2894 EngSetLastError(ERROR_INVALID_PARAMETER);
2895 RETURN(NULL);
2896 }
2897 else if (ClassAtom == (RTL_ATOM)0)
2898 {
2899 /* LastError code was set by IntGetAtomFromStringOrAtom */
2900 RETURN(NULL);
2901 }
2902 }
2903 }
2904
2905 Desktop = IntGetCurrentThreadDesktopWindow();
2906
2907 if(hwndParent == NULL)
2908 {
2909 hwndParent = Desktop;
2910 DoMessageWnd = TRUE;
2911 }
2912 else if(hwndParent == HWND_MESSAGE)
2913 {
2914 hwndParent = IntGetMessageWindow();
2915 }
2916
2917 if(!(Parent = UserGetWindowObject(hwndParent)))
2918 {
2919 RETURN( NULL);
2920 }
2921
2922 ChildAfter = NULL;
2923 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
2924 {
2925 RETURN( NULL);
2926 }
2927
2928 _SEH2_TRY
2929 {
2930 if(Parent->head.h == Desktop)
2931 {
2932 HWND *List, *phWnd;
2933 PWND TopLevelWindow;
2934 BOOLEAN CheckWindowName;
2935 BOOLEAN WindowMatches;
2936 BOOLEAN ClassMatches;
2937
2938 /* windows searches through all top-level windows if the parent is the desktop
2939 window */
2940
2941 if((List = IntWinListChildren(Parent)))
2942 {
2943 phWnd = List;
2944
2945 if(ChildAfter)
2946 {
2947 /* skip handles before and including ChildAfter */
2948 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2949 ;
2950 }
2951
2952 CheckWindowName = WindowName.Buffer != 0;
2953
2954 /* search children */
2955 while(*phWnd)
2956 {
2957 UNICODE_STRING ustr;
2958
2959 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
2960 {
2961 continue;
2962 }
2963
2964 /* Do not send WM_GETTEXT messages in the kernel mode version!
2965 The user mode version however calls GetWindowText() which will
2966 send WM_GETTEXT messages to windows belonging to its processes */
2967 ustr.Buffer = TopLevelWindow->strName.Buffer;
2968 ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated
2969 ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT);
2970 WindowMatches = !CheckWindowName ||
2971 (TopLevelWindow->strName.Length < 0xFFFF &&
2972 !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
2973 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
2974 ClassAtom == TopLevelWindow->pcls->atomClassName;
2975
2976 if (WindowMatches && ClassMatches)
2977 {
2978 Ret = TopLevelWindow->head.h;
2979 break;
2980 }
2981
2982 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
2983 {
2984 /* window returns the handle of the top-level window, in case it found
2985 the child window */
2986 Ret = TopLevelWindow->head.h;
2987 break;
2988 }
2989
2990 }
2991 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2992 }
2993 }
2994 else
2995 {
2996 ERR("FindWindowEx: Not Desktop Parent!\n");
2997 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
2998 }
2999
3000 if (Ret == NULL && DoMessageWnd)
3001 {
3002 PWND MsgWindows;
3003
3004 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
3005 {
3006 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
3007 }
3008 }
3009 }
3010 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3011 {
3012 SetLastNtError(_SEH2_GetExceptionCode());
3013 Ret = NULL;
3014 }
3015 _SEH2_END;
3016
3017 RETURN( Ret);
3018
3019 CLEANUP:
3020 TRACE("Leave NtUserFindWindowEx, ret %p\n", _ret_);
3021 UserLeave();
3022 END_CLEANUP;
3023 }
3024
3025
3026 /*
3027 * @implemented
3028 */
3029 PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type)
3030 {
3031 PWND WndAncestor, Parent;
3032
3033 if (Wnd->head.h == IntGetDesktopWindow())
3034 {
3035 return NULL;
3036 }
3037
3038 switch (Type)
3039 {
3040 case GA_PARENT:
3041 {
3042 WndAncestor = Wnd->spwndParent;
3043 break;
3044 }
3045
3046 case GA_ROOT:
3047 {
3048 WndAncestor = Wnd;
3049 Parent = NULL;
3050
3051 for(;;)
3052 {
3053 if(!(Parent = WndAncestor->spwndParent))
3054 {
3055 break;
3056 }
3057 if(IntIsDesktopWindow(Parent))
3058 {
3059 break;
3060 }
3061
3062 WndAncestor = Parent;
3063 }
3064 break;
3065 }
3066
3067 case GA_ROOTOWNER:
3068 {
3069 WndAncestor = Wnd;
3070
3071 for (;;)
3072 {
3073 Parent = IntGetParent(WndAncestor);
3074
3075 if (!Parent)
3076 {
3077 break;
3078 }
3079
3080 WndAncestor = Parent;
3081 }
3082 break;
3083 }
3084
3085 default:
3086 {
3087 return NULL;
3088 }
3089 }
3090
3091 return WndAncestor;
3092 }
3093
3094 /*
3095 * @implemented
3096 */
3097 HWND APIENTRY
3098 NtUserGetAncestor(HWND hWnd, UINT Type)
3099 {
3100 PWND Window, Ancestor;
3101 DECLARE_RETURN(HWND);
3102
3103 TRACE("Enter NtUserGetAncestor\n");
3104 UserEnterExclusive();
3105
3106 if (!(Window = UserGetWindowObject(hWnd)))
3107 {
3108 RETURN(NULL);
3109 }
3110
3111 Ancestor = UserGetAncestor(Window, Type);
3112 /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3113
3114 RETURN(Ancestor ? Ancestor->head.h : NULL);
3115
3116 CLEANUP:
3117 TRACE("Leave NtUserGetAncestor, ret=%p\n", _ret_);
3118 UserLeave();
3119 END_CLEANUP;
3120 }
3121
3122 ////
3123 //// ReactOS work around! Keep it the sames as in Combo.c and Controls.h
3124 ////
3125 /* combo state struct */
3126 typedef struct
3127 {
3128 HWND self;
3129 HWND owner;
3130 UINT dwStyle;
3131 HWND hWndEdit;
3132 HWND hWndLBox;
3133 UINT wState;
3134 HFONT hFont;
3135 RECT textRect;
3136 RECT buttonRect;
3137 RECT droppedRect;
3138 INT droppedIndex;
3139 INT fixedOwnerDrawHeight;
3140 INT droppedWidth; /* last two are not used unless set */
3141 INT editHeight; /* explicitly */
3142 LONG UIState;
3143 } HEADCOMBO,*LPHEADCOMBO;
3144
3145 // Window Extra data container.
3146 typedef struct _WND2CBOX
3147 {
3148 WND;
3149 LPHEADCOMBO pCBox;
3150 } WND2CBOX, *PWND2CBOX;
3151
3152 #define CBF_BUTTONDOWN 0x0002
3153 ////
3154 ////
3155 ////
3156 BOOL
3157 APIENTRY
3158 NtUserGetComboBoxInfo(
3159 HWND hWnd,
3160 PCOMBOBOXINFO pcbi)
3161 {
3162 PWND Wnd;
3163 PPROCESSINFO ppi;
3164 BOOL NotSameppi = FALSE;
3165 BOOL Ret = TRUE;
3166 DECLARE_RETURN(BOOL);
3167
3168 TRACE("Enter NtUserGetComboBoxInfo\n");
3169 UserEnterShared();
3170
3171 if (!(Wnd = UserGetWindowObject(hWnd)))
3172 {
3173 RETURN( FALSE );
3174 }
3175 _SEH2_TRY
3176 {
3177 if(pcbi)
3178 {
3179 ProbeForWrite(pcbi,
3180 sizeof(COMBOBOXINFO),
3181 1);
3182 }
3183 }
3184 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3185 {
3186 SetLastNtError(_SEH2_GetExceptionCode());
3187 _SEH2_YIELD(RETURN(FALSE));
3188 }
3189 _SEH2_END;
3190
3191 if (pcbi->cbSize < sizeof(COMBOBOXINFO))
3192 {
3193 EngSetLastError(ERROR_INVALID_PARAMETER);
3194 RETURN(FALSE);
3195 }
3196
3197 // Pass the user pointer, it was already probed.
3198 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_COMBOBOX]) && Wnd->fnid != FNID_COMBOBOX)
3199 {
3200 RETURN( (BOOL) co_IntSendMessage( Wnd->head.h, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
3201 }
3202
3203 ppi = PsGetCurrentProcessWin32Process();
3204 NotSameppi = ppi != Wnd->head.pti->ppi;
3205 if (NotSameppi)
3206 {
3207 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3208 }
3209
3210 _SEH2_TRY
3211 {
3212 LPHEADCOMBO lphc = ((PWND2CBOX)Wnd)->pCBox;
3213 pcbi->rcItem = lphc->textRect;
3214 pcbi->rcButton = lphc->buttonRect;
3215 pcbi->stateButton = 0;
3216 if (lphc->wState & CBF_BUTTONDOWN)
3217 pcbi->stateButton |= STATE_SYSTEM_PRESSED;
3218 if (RECTL_bIsEmptyRect(&lphc->buttonRect))
3219 pcbi->stateButton |= STATE_SYSTEM_INVISIBLE;
3220 pcbi->hwndCombo = lphc->self;
3221 pcbi->hwndItem = lphc->hWndEdit;
3222 pcbi->hwndList = lphc->hWndLBox;
3223 }
3224 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3225 {
3226 Ret = FALSE;
3227 SetLastNtError(_SEH2_GetExceptionCode());
3228 }
3229 _SEH2_END;
3230
3231 RETURN( Ret);
3232
3233 CLEANUP:
3234 if (NotSameppi) KeDetachProcess();
3235 TRACE("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
3236 UserLeave();
3237 END_CLEANUP;
3238 }
3239
3240 ////
3241 //// ReactOS work around! Keep it the sames as in Listbox.c
3242 ////
3243 /* Listbox structure */
3244 typedef struct
3245 {
3246 HWND self; /* Our own window handle */
3247 HWND owner; /* Owner window to send notifications to */
3248 UINT style; /* Window style */
3249 INT width; /* Window width */
3250 INT height; /* Window height */
3251 VOID *items; /* Array of items */
3252 INT nb_items; /* Number of items */
3253 INT top_item; /* Top visible item */
3254 INT selected_item; /* Selected item */
3255 INT focus_item; /* Item that has the focus */
3256 INT anchor_item; /* Anchor item for extended selection */
3257 INT item_height; /* Default item height */
3258 INT page_size; /* Items per listbox page */
3259 INT column_width; /* Column width for multi-column listboxes */
3260 } LB_DESCR;
3261
3262 // Window Extra data container.
3263 typedef struct _WND2LB
3264 {
3265 WND;
3266 LB_DESCR * pLBiv;
3267 } WND2LB, *PWND2LB;
3268 ////
3269 ////
3270 ////
3271 DWORD
3272 APIENTRY
3273 NtUserGetListBoxInfo(
3274 HWND hWnd)
3275 {
3276 PWND Wnd;
3277 PPROCESSINFO ppi;
3278 BOOL NotSameppi = FALSE;
3279 DWORD Ret = 0;
3280 DECLARE_RETURN(DWORD);
3281
3282 TRACE("Enter NtUserGetListBoxInfo\n");
3283 UserEnterShared();
3284
3285 if (!(Wnd = UserGetWindowObject(hWnd)))
3286 {
3287 RETURN( 0 );
3288 }
3289
3290 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_LISTBOX]) && Wnd->fnid != FNID_LISTBOX)
3291 {
3292 RETURN( (DWORD) co_IntSendMessage( Wnd->head.h, LB_GETLISTBOXINFO, 0, 0 ));
3293 }
3294
3295 // wine lisbox:test_GetListBoxInfo lb_getlistboxinfo = 0, should not send a message!
3296 ppi = PsGetCurrentProcessWin32Process();
3297 NotSameppi = ppi != Wnd->head.pti->ppi;
3298 if (NotSameppi)
3299 {
3300 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3301 }
3302
3303 _SEH2_TRY
3304 {
3305 LB_DESCR *descr = ((PWND2LB)Wnd)->pLBiv;
3306 // See Controls ListBox.c:LB_GETLISTBOXINFO must match...
3307 if (descr->style & LBS_MULTICOLUMN) //// ReactOS
3308 Ret = descr->page_size * descr->column_width;
3309 else
3310 Ret = descr->page_size;
3311 }
3312 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3313 {
3314 Ret = 0;
3315 SetLastNtError(_SEH2_GetExceptionCode());
3316 }
3317 _SEH2_END;
3318
3319 RETURN( Ret);
3320
3321 CLEANUP:
3322 if (NotSameppi) KeDetachProcess();
3323 TRACE("Leave NtUserGetListBoxInfo, ret=%lu\n", _ret_);
3324 UserLeave();
3325 END_CLEANUP;
3326 }
3327
3328 /*
3329 * NtUserSetParent
3330 *
3331 * The NtUserSetParent function changes the parent window of the specified
3332 * child window.
3333 *
3334 * Remarks
3335 * The new parent window and the child window must belong to the same
3336 * application. If the window identified by the hWndChild parameter is
3337 * visible, the system performs the appropriate redrawing and repainting.
3338 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3339 * or WS_POPUP window styles of the window whose parent is being changed.
3340 *
3341 * Status
3342 * @implemented
3343 */
3344
3345 HWND APIENTRY
3346 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
3347 {
3348 DECLARE_RETURN(HWND);
3349
3350 TRACE("Enter NtUserSetParent\n");
3351 UserEnterExclusive();
3352
3353 /*
3354 Check Parent first from user space, set it here.
3355 */
3356 if (!hWndNewParent)
3357 {
3358 hWndNewParent = IntGetDesktopWindow();
3359 }
3360 else if (hWndNewParent == HWND_MESSAGE)
3361 {
3362 hWndNewParent = IntGetMessageWindow();
3363 }
3364
3365 RETURN( co_UserSetParent(hWndChild, hWndNewParent));
3366
3367 CLEANUP:
3368 TRACE("Leave NtUserSetParent, ret=%p\n", _ret_);
3369 UserLeave();
3370 END_CLEANUP;
3371 }
3372
3373 /*
3374 * UserGetShellWindow
3375 *
3376 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3377 *
3378 * Status
3379 * @implemented
3380 */
3381 HWND FASTCALL UserGetShellWindow(VOID)
3382 {
3383 PWINSTATION_OBJECT WinStaObject;
3384 HWND Ret;
3385
3386