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