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