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