xref: /reactos/win32ss/user/ntuser/window.c (revision 98e8827a)
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()) SwFlag |= SWP_NOACTIVATE;
2498       co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
2499                             NewPos.right, NewPos.bottom, SwFlag);
2500    }
2501 
2502    /* Send the WM_PARENTNOTIFY message */
2503    IntSendParentNotify(Window, WM_CREATE);
2504 
2505    /* Notify the shell that a new window was created */
2506    if (Window->spwndOwner == NULL ||
2507        !(Window->spwndOwner->style & WS_VISIBLE) ||
2508        (Window->spwndOwner->ExStyle & WS_EX_TOOLWINDOW))
2509    {
2510       if (UserIsDesktopWindow(Window->spwndParent) &&
2511           (Window->style & WS_VISIBLE) &&
2512           (!(Window->ExStyle & WS_EX_TOOLWINDOW) ||
2513            (Window->ExStyle & WS_EX_APPWINDOW)))
2514       {
2515          co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)hWnd, 0);
2516       }
2517    }
2518 
2519    /* Initialize and show the window's scrollbars */
2520    if (Window->style & WS_VSCROLL)
2521    {
2522       co_UserShowScrollBar(Window, SB_VERT, FALSE, TRUE);
2523    }
2524    if (Window->style & WS_HSCROLL)
2525    {
2526       co_UserShowScrollBar(Window, SB_HORZ, TRUE, FALSE);
2527    }
2528 
2529    /* Show the new window */
2530    if (Cs->style & WS_VISIBLE)
2531    {
2532       if (Window->style & WS_MAXIMIZE)
2533          dwShowMode = SW_SHOW;
2534       else if (Window->style & WS_MINIMIZE)
2535          dwShowMode = SW_SHOWMINIMIZED;
2536 
2537       co_WinPosShowWindow(Window, dwShowMode);
2538 
2539       if (Window->ExStyle & WS_EX_MDICHILD)
2540       {
2541           ASSERT(ParentWindow);
2542           if(!ParentWindow)
2543               goto cleanup;
2544         co_IntSendMessage(UserHMGetHandle(ParentWindow), WM_MDIREFRESHMENU, 0, 0);
2545         /* ShowWindow won't activate child windows */
2546         co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2547       }
2548    }
2549 
2550    if (Class->atomClassName == gaGuiConsoleWndClass)
2551    {
2552        /* Count only console windows manually */
2553        co_IntUserManualGuiCheck(TRUE);
2554    }
2555 
2556    TRACE("co_UserCreateWindowEx(): Created window %p\n", hWnd);
2557    ret = Window;
2558 
2559 cleanup:
2560    if (!ret)
2561    {
2562        TRACE("co_UserCreateWindowEx(): Error Created window!\n");
2563        /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */
2564        if (Window)
2565             co_UserDestroyWindow(Window);
2566        else if (Class)
2567            IntDereferenceClass(Class, pti->pDeskInfo, pti->ppi);
2568    }
2569 
2570    if (pCsw) ExFreePoolWithTag(pCsw, TAG_HOOK);
2571    if (pCbtCreate) ExFreePoolWithTag(pCbtCreate, TAG_HOOK);
2572    if (pszName) UserHeapFree(pszName);
2573    if (pszClass) UserHeapFree(pszClass);
2574 
2575    if (Window)
2576    {
2577       UserDerefObjectCo(Window);
2578    }
2579    if (ParentWindow) UserDerefObjectCo(ParentWindow);
2580 
2581    // See CORE-13717, not setting error on success.
2582    if (ret)
2583       EngSetLastError(ERROR_SUCCESS);
2584 
2585    return ret;
2586 }
2587 
2588 NTSTATUS
2589 NTAPI
2590 ProbeAndCaptureLargeString(
2591     OUT PLARGE_STRING plstrSafe,
2592     IN PLARGE_STRING plstrUnsafe)
2593 {
2594     LARGE_STRING lstrTemp;
2595     PVOID pvBuffer = NULL;
2596 
2597     _SEH2_TRY
2598     {
2599         /* Probe and copy the string */
2600         ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
2601         lstrTemp = *plstrUnsafe;
2602     }
2603     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2604     {
2605         /* Fail */
2606         _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2607     }
2608     _SEH2_END
2609 
2610     if (lstrTemp.Length != 0)
2611     {
2612         /* Allocate a buffer from paged pool */
2613         pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
2614         if (!pvBuffer)
2615         {
2616             return STATUS_NO_MEMORY;
2617         }
2618 
2619         _SEH2_TRY
2620         {
2621             /* Probe and copy the buffer */
2622             ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
2623             RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
2624         }
2625         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2626         {
2627             /* Cleanup and fail */
2628             ExFreePoolWithTag(pvBuffer, TAG_STRING);
2629             _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2630         }
2631         _SEH2_END
2632     }
2633 
2634     /* Set the output string */
2635     plstrSafe->Buffer = pvBuffer;
2636     plstrSafe->Length = lstrTemp.Length;
2637     plstrSafe->MaximumLength = lstrTemp.Length;
2638 
2639     return STATUS_SUCCESS;
2640 }
2641 
2642 /**
2643  * \todo Allow passing plstrClassName as ANSI.
2644  */
2645 HWND
2646 NTAPI
2647 NtUserCreateWindowEx(
2648     DWORD dwExStyle,
2649     PLARGE_STRING plstrClassName,
2650     PLARGE_STRING plstrClsVersion,
2651     PLARGE_STRING plstrWindowName,
2652     DWORD dwStyle,
2653     int x,
2654     int y,
2655     int nWidth,
2656     int nHeight,
2657     HWND hWndParent,
2658     HMENU hMenu,
2659     HINSTANCE hInstance,
2660     LPVOID lpParam,
2661     DWORD dwFlags,
2662     PVOID acbiBuffer)
2663 {
2664     NTSTATUS Status;
2665     LARGE_STRING lstrWindowName;
2666     LARGE_STRING lstrClassName;
2667     LARGE_STRING lstrClsVersion;
2668     UNICODE_STRING ustrClassName;
2669     UNICODE_STRING ustrClsVersion;
2670     CREATESTRUCTW Cs;
2671     HWND hwnd = NULL;
2672     PWND pwnd;
2673 
2674     lstrWindowName.Buffer = NULL;
2675     lstrClassName.Buffer = NULL;
2676     lstrClsVersion.Buffer = NULL;
2677 
2678     if ( (dwStyle & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2679     {
2680         /* check hMenu is valid handle */
2681         if (hMenu && !UserGetMenuObject(hMenu))
2682         {
2683             ERR("NtUserCreateWindowEx: Got an invalid menu handle!\n");
2684             EngSetLastError(ERROR_INVALID_MENU_HANDLE);
2685             return NULL;
2686         }
2687     }
2688 
2689     /* Copy the window name to kernel mode */
2690     Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
2691     if (!NT_SUCCESS(Status))
2692     {
2693         ERR("NtUserCreateWindowEx: failed to capture plstrWindowName\n");
2694         SetLastNtError(Status);
2695         return NULL;
2696     }
2697 
2698     plstrWindowName = &lstrWindowName;
2699 
2700     /* Check if the class is an atom */
2701     if (IS_ATOM(plstrClassName))
2702     {
2703         /* It is, pass the atom in the UNICODE_STRING */
2704         ustrClassName.Buffer = (PVOID)plstrClassName;
2705         ustrClassName.Length = 0;
2706         ustrClassName.MaximumLength = 0;
2707     }
2708     else
2709     {
2710         /* It's not, capture the class name */
2711         Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
2712         if (!NT_SUCCESS(Status))
2713         {
2714             ERR("NtUserCreateWindowEx: failed to capture plstrClassName\n");
2715             /* Set last error, cleanup and return */
2716             SetLastNtError(Status);
2717             goto cleanup;
2718         }
2719 
2720         /* We pass it on as a UNICODE_STRING */
2721         ustrClassName.Buffer = lstrClassName.Buffer;
2722         ustrClassName.Length = (USHORT)min(lstrClassName.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2723         ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT);
2724     }
2725 
2726     /* Check if the class version is an atom */
2727     if (IS_ATOM(plstrClsVersion))
2728     {
2729         /* It is, pass the atom in the UNICODE_STRING */
2730         ustrClsVersion.Buffer = (PVOID)plstrClsVersion;
2731         ustrClsVersion.Length = 0;
2732         ustrClsVersion.MaximumLength = 0;
2733     }
2734     else
2735     {
2736         /* It's not, capture the class name */
2737         Status = ProbeAndCaptureLargeString(&lstrClsVersion, plstrClsVersion);
2738         if (!NT_SUCCESS(Status))
2739         {
2740             ERR("NtUserCreateWindowEx: failed to capture plstrClsVersion\n");
2741             /* Set last error, cleanup and return */
2742             SetLastNtError(Status);
2743             goto cleanup;
2744         }
2745 
2746         /* We pass it on as a UNICODE_STRING */
2747         ustrClsVersion.Buffer = lstrClsVersion.Buffer;
2748         ustrClsVersion.Length = (USHORT)min(lstrClsVersion.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2749         ustrClsVersion.MaximumLength = (USHORT)min(lstrClsVersion.MaximumLength, MAXUSHORT);
2750     }
2751 
2752     /* Fill the CREATESTRUCTW */
2753     /* we will keep here the original parameters */
2754     Cs.style = dwStyle;
2755     Cs.lpCreateParams = lpParam;
2756     Cs.hInstance = hInstance;
2757     Cs.hMenu = hMenu;
2758     Cs.hwndParent = hWndParent;
2759     Cs.cx = nWidth;
2760     Cs.cy = nHeight;
2761     Cs.x = x;
2762     Cs.y = y;
2763     Cs.lpszName = (LPCWSTR) plstrWindowName->Buffer;
2764     Cs.lpszClass = ustrClassName.Buffer;
2765     Cs.dwExStyle = dwExStyle;
2766 
2767     UserEnterExclusive();
2768 
2769     /* Call the internal function */
2770     pwnd = co_UserCreateWindowEx(&Cs, &ustrClsVersion, plstrWindowName, acbiBuffer, dwFlags);
2771 
2772     if(!pwnd)
2773     {
2774         ERR("co_UserCreateWindowEx failed!\n");
2775     }
2776     hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
2777 
2778     UserLeave();
2779 
2780 cleanup:
2781     if (lstrWindowName.Buffer)
2782     {
2783         ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
2784     }
2785     if (lstrClassName.Buffer)
2786     {
2787         ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
2788     }
2789     if (lstrClsVersion.Buffer)
2790     {
2791         ExFreePoolWithTag(lstrClsVersion.Buffer, TAG_STRING);
2792     }
2793 
2794    return hwnd;
2795 }
2796 
2797 // Win: xxxDW_DestroyOwnedWindows
2798 VOID FASTCALL IntDestroyOwnedWindows(PWND Window)
2799 {
2800     HWND* List;
2801     HWND* phWnd;
2802     PWND pWnd;
2803     PTHREADINFO pti = Window->head.pti;
2804     USER_REFERENCE_ENTRY Ref;
2805 
2806     List = IntWinListOwnedPopups(Window);
2807     if (!List)
2808         return;
2809 
2810     for (phWnd = List; *phWnd; ++phWnd)
2811     {
2812         pWnd = ValidateHwndNoErr(*phWnd);
2813         if (pWnd == NULL)
2814             continue;
2815         ASSERT(pWnd->spwndOwner == Window);
2816         ASSERT(pWnd != Window);
2817 
2818         if (IS_IMM_MODE() && !(pti->TIF_flags & TIF_INCLEANUP) &&
2819             pWnd == pti->spwndDefaultIme)
2820         {
2821             continue;
2822         }
2823 
2824         pWnd->spwndOwner = NULL;
2825         if (IntWndBelongsToThread(pWnd, PsGetCurrentThreadWin32Thread()))
2826         {
2827             UserRefObjectCo(pWnd, &Ref); // Temp HACK?
2828             co_UserDestroyWindow(pWnd);
2829             UserDerefObjectCo(pWnd); // Temp HACK?
2830         }
2831         else
2832         {
2833             ERR("IntWndBelongsToThread(0x%p) is FALSE, ignoring.\n", pWnd);
2834         }
2835     }
2836 
2837     ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2838 }
2839 
2840 // Win: xxxDestroyWindow
2841 BOOLEAN co_UserDestroyWindow(PVOID Object)
2842 {
2843    HWND hWnd;
2844    PWND pwndTemp;
2845    PTHREADINFO ti;
2846    MSG msg;
2847    PWND Window = Object;
2848 
2849    ASSERT_REFS_CO(Window); // FIXME: Temp HACK?
2850 
2851    hWnd = Window->head.h;
2852    ti = PsGetCurrentThreadWin32Thread();
2853 
2854    TRACE("co_UserDestroyWindow(Window = 0x%p, hWnd = 0x%p)\n", Window, hWnd);
2855 
2856    /* Check for owner thread */
2857    if (Window->head.pti != ti)
2858    {
2859        /* Check if we are destroying the desktop window */
2860        if (! ((Window->head.rpdesk->dwDTFlags & DF_DESTROYED) && Window == Window->head.rpdesk->pDeskInfo->spwnd))
2861        {
2862            EngSetLastError(ERROR_ACCESS_DENIED);
2863            return FALSE;
2864        }
2865    }
2866 
2867    /* If window was created successfully and it is hooked */
2868    if ((Window->state2 & WNDS2_WMCREATEMSGPROCESSED))
2869    {
2870       if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0))
2871       {
2872          ERR("Destroy Window WH_CBT Call Hook return!\n");
2873          return FALSE;
2874       }
2875    }
2876 
2877    if (Window->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME])
2878    {
2879       if ((Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2880       {
2881          if (Window->spwndOwner)
2882          {
2883             //ERR("DestroyWindow Owner out.\n");
2884             UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE);
2885          }
2886       }
2887    }
2888 
2889    /* Inform the parent */
2890    if (Window->style & WS_CHILD)
2891    {
2892       IntSendParentNotify(Window, WM_DESTROY);
2893    }
2894 
2895    if (!Window->spwndOwner && !IntGetParent(Window))
2896    {
2897       co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM) hWnd, 0);
2898    }
2899 
2900    /* Hide the window */
2901    if (Window->style & WS_VISIBLE)
2902    {
2903       if (Window->style & WS_CHILD)
2904       {
2905          /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
2906          co_WinPosShowWindow(Window, SW_HIDE);
2907       }
2908       else
2909       {
2910          co_WinPosSetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_HIDEWINDOW );
2911       }
2912    }
2913 
2914    /* Adjust last active */
2915    if ((pwndTemp = Window->spwndOwner))
2916    {
2917       while (pwndTemp->spwndOwner)
2918          pwndTemp = pwndTemp->spwndOwner;
2919 
2920       if (pwndTemp->spwndLastActive == Window)
2921          pwndTemp->spwndLastActive = Window->spwndOwner;
2922    }
2923 
2924    if (Window->spwndParent && IntIsWindow(UserHMGetHandle(Window)))
2925    {
2926       if ((Window->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
2927       {
2928          if (!IntIsTopLevelWindow(Window))
2929          {
2930             //ERR("DestroyWindow Parent out.\n");
2931             UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE);
2932          }
2933       }
2934    }
2935 
2936    if (Window->head.pti->MessageQueue->spwndActive == Window)
2937       Window->head.pti->MessageQueue->spwndActive = NULL;
2938    if (Window->head.pti->MessageQueue->spwndFocus == Window)
2939       Window->head.pti->MessageQueue->spwndFocus = NULL;
2940    if (Window->head.pti->MessageQueue->spwndActivePrev == Window)
2941       Window->head.pti->MessageQueue->spwndActivePrev = NULL;
2942    if (Window->head.pti->MessageQueue->spwndCapture == Window)
2943       Window->head.pti->MessageQueue->spwndCapture = NULL;
2944 
2945    /*
2946     * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
2947     */
2948 
2949    if ((ti != NULL) && (ti->pDeskInfo != NULL))
2950    {
2951       if (ti->pDeskInfo->hShellWindow == hWnd)
2952       {
2953          ERR("Destroying the ShellWindow!\n");
2954          ti->pDeskInfo->hShellWindow = NULL;
2955       }
2956    }
2957 
2958    IntEngWindowChanged(Window, WOC_DELETE);
2959 
2960    if (!IntIsWindow(UserHMGetHandle(Window)))
2961    {
2962       return TRUE;
2963    }
2964 
2965     /* Recursively destroy owned windows */
2966     if (!(Window->style & WS_CHILD))
2967     {
2968         IntDestroyOwnedWindows(Window);
2969     }
2970 
2971     /* Generate mouse move message for the next window */
2972     msg.message = WM_MOUSEMOVE;
2973     msg.wParam = UserGetMouseButtonsState();
2974     msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2975     msg.pt = gpsi->ptCursor;
2976     co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2977 
2978    IntNotifyWinEvent(EVENT_OBJECT_DESTROY, Window, OBJID_WINDOW, CHILDID_SELF, 0);
2979 
2980    /* Send destroy messages */
2981    IntSendDestroyMsg(UserHMGetHandle(Window));
2982 
2983    // Destroy the default IME window if necessary
2984    if (IS_IMM_MODE() && !(ti->TIF_flags & TIF_INCLEANUP) &&
2985        ti->spwndDefaultIme && !IS_WND_IMELIKE(Window) && !(Window->state & WNDS_DESTROYED))
2986    {
2987        if (IS_WND_CHILD(Window))
2988        {
2989            if (IntImeCanDestroyDefIMEforChild(ti->spwndDefaultIme, Window))
2990                co_UserDestroyWindow(ti->spwndDefaultIme);
2991        }
2992        else
2993        {
2994            if (IntImeCanDestroyDefIME(ti->spwndDefaultIme, Window))
2995                co_UserDestroyWindow(ti->spwndDefaultIme);
2996        }
2997    }
2998 
2999    if (!IntIsWindow(UserHMGetHandle(Window)))
3000    {
3001       return TRUE;
3002    }
3003 
3004    /* Destroy the window storage */
3005    co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
3006 
3007    return TRUE;
3008 }
3009 
3010 
3011 /*
3012  * @implemented
3013  */
3014 BOOLEAN APIENTRY
3015 NtUserDestroyWindow(HWND Wnd)
3016 {
3017    PWND Window;
3018    DECLARE_RETURN(BOOLEAN);
3019    BOOLEAN ret;
3020    USER_REFERENCE_ENTRY Ref;
3021 
3022    TRACE("Enter NtUserDestroyWindow\n");
3023    UserEnterExclusive();
3024 
3025    if (!(Window = UserGetWindowObject(Wnd)))
3026    {
3027       RETURN(FALSE);
3028    }
3029 
3030    UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy...
3031    ret = co_UserDestroyWindow(Window);
3032    UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy...
3033 
3034    RETURN(ret);
3035 
3036 CLEANUP:
3037    TRACE("Leave NtUserDestroyWindow, ret=%u\n", _ret_);
3038    UserLeave();
3039    END_CLEANUP;
3040 }
3041 
3042 
3043 static HWND FASTCALL
3044 IntFindWindow(PWND Parent,
3045               PWND ChildAfter,
3046               RTL_ATOM ClassAtom,
3047               PUNICODE_STRING WindowName)
3048 {
3049    BOOL CheckWindowName;
3050    HWND *List, *phWnd;
3051    HWND Ret = NULL;
3052    UNICODE_STRING CurrentWindowName;
3053 
3054    ASSERT(Parent);
3055 
3056    CheckWindowName = WindowName->Buffer != 0;
3057 
3058    if((List = IntWinListChildren(Parent)))
3059    {
3060       phWnd = List;
3061       if(ChildAfter)
3062       {
3063          /* skip handles before and including ChildAfter */
3064          while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
3065             ;
3066       }
3067 
3068       /* search children */
3069       while(*phWnd)
3070       {
3071          PWND Child;
3072          if(!(Child = UserGetWindowObject(*(phWnd++))))
3073          {
3074             continue;
3075          }
3076 
3077          /* Do not send WM_GETTEXT messages in the kernel mode version!
3078             The user mode version however calls GetWindowText() which will
3079             send WM_GETTEXT messages to windows belonging to its processes */
3080          if (!ClassAtom || Child->pcls->atomNVClassName == ClassAtom)
3081          {
3082              // FIXME: LARGE_STRING truncated
3083              CurrentWindowName.Buffer = Child->strName.Buffer;
3084              CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT);
3085              CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT);
3086              if(!CheckWindowName ||
3087                 (Child->strName.Length < 0xFFFF &&
3088                  !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
3089              {
3090                 Ret = Child->head.h;
3091                 break;
3092              }
3093          }
3094       }
3095       ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
3096    }
3097 
3098    return Ret;
3099 }
3100 
3101 /*
3102  * FUNCTION:
3103  *   Searches a window's children for a window with the specified
3104  *   class and name
3105  * ARGUMENTS:
3106  *   hwndParent     = The window whose childs are to be searched.
3107  *       NULL = desktop
3108  *       HWND_MESSAGE = message-only windows
3109  *
3110  *   hwndChildAfter = Search starts after this child window.
3111  *       NULL = start from beginning
3112  *
3113  *   ucClassName    = Class name to search for
3114  *       Reguired parameter.
3115  *
3116  *   ucWindowName   = Window name
3117  *       ->Buffer == NULL = don't care
3118  *
3119  * RETURNS:
3120  *   The HWND of the window if it was found, otherwise NULL
3121  */
3122 /*
3123  * @implemented
3124  */
3125 HWND APIENTRY
3126 NtUserFindWindowEx(HWND hwndParent,
3127                    HWND hwndChildAfter,
3128                    PUNICODE_STRING ucClassName,
3129                    PUNICODE_STRING ucWindowName,
3130                    DWORD dwUnknown)
3131 {
3132    PWND Parent, ChildAfter;
3133    UNICODE_STRING ClassName = {0}, WindowName = {0};
3134    HWND Desktop, Ret = NULL;
3135    BOOL DoMessageWnd = FALSE;
3136    RTL_ATOM ClassAtom = (RTL_ATOM)0;
3137    DECLARE_RETURN(HWND);
3138 
3139    TRACE("Enter NtUserFindWindowEx\n");
3140    UserEnterShared();
3141 
3142    if (ucClassName != NULL || ucWindowName != NULL)
3143    {
3144        _SEH2_TRY
3145        {
3146            if (ucClassName != NULL)
3147            {
3148                ClassName = ProbeForReadUnicodeString(ucClassName);
3149                if (ClassName.Length != 0)
3150                {
3151                    ProbeForRead(ClassName.Buffer,
3152                                 ClassName.Length,
3153                                 sizeof(WCHAR));
3154                }
3155                else if (!IS_ATOM(ClassName.Buffer))
3156                {
3157                    EngSetLastError(ERROR_INVALID_PARAMETER);
3158                    _SEH2_LEAVE;
3159                }
3160 
3161                if (!IntGetAtomFromStringOrAtom(&ClassName,
3162                                                &ClassAtom))
3163                {
3164                    EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS);
3165                    _SEH2_LEAVE;
3166                }
3167            }
3168 
3169            if (ucWindowName != NULL)
3170            {
3171                WindowName = ProbeForReadUnicodeString(ucWindowName);
3172                if (WindowName.Length != 0)
3173                {
3174                    ProbeForRead(WindowName.Buffer,
3175                                 WindowName.Length,
3176                                 sizeof(WCHAR));
3177                }
3178            }
3179        }
3180        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3181        {
3182            SetLastNtError(_SEH2_GetExceptionCode());
3183            _SEH2_YIELD(RETURN(NULL));
3184        }
3185        _SEH2_END;
3186 
3187        if (ucClassName != NULL)
3188        {
3189            if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
3190                !IS_ATOM(ClassName.Buffer))
3191            {
3192                EngSetLastError(ERROR_INVALID_PARAMETER);
3193                RETURN(NULL);
3194            }
3195            else if (ClassAtom == (RTL_ATOM)0)
3196            {
3197                /* LastError code was set by IntGetAtomFromStringOrAtom */
3198                RETURN(NULL);
3199            }
3200        }
3201    }
3202 
3203    Desktop = IntGetCurrentThreadDesktopWindow();
3204 
3205    if(hwndParent == NULL)
3206    {
3207       hwndParent = Desktop;
3208       DoMessageWnd = TRUE;
3209    }
3210    else if(hwndParent == HWND_MESSAGE)
3211    {
3212      hwndParent = IntGetMessageWindow();
3213    }
3214 
3215    if(!(Parent = UserGetWindowObject(hwndParent)))
3216    {
3217       RETURN( NULL);
3218    }
3219 
3220    ChildAfter = NULL;
3221    if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
3222    {
3223       RETURN( NULL);
3224    }
3225 
3226    _SEH2_TRY
3227    {
3228        if(Parent->head.h == Desktop)
3229        {
3230           HWND *List, *phWnd;
3231           PWND TopLevelWindow;
3232           BOOLEAN CheckWindowName;
3233           BOOLEAN WindowMatches;
3234           BOOLEAN ClassMatches;
3235 
3236           /* windows searches through all top-level windows if the parent is the desktop
3237              window */
3238 
3239           if((List = IntWinListChildren(Parent)))
3240           {
3241              phWnd = List;
3242 
3243              if(ChildAfter)
3244              {
3245                 /* skip handles before and including ChildAfter */
3246                 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
3247                    ;
3248              }
3249 
3250              CheckWindowName = WindowName.Buffer != 0;
3251 
3252              /* search children */
3253              while(*phWnd)
3254              {
3255                  UNICODE_STRING ustr;
3256 
3257                 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
3258                 {
3259                    continue;
3260                 }
3261 
3262                 /* Do not send WM_GETTEXT messages in the kernel mode version!
3263                    The user mode version however calls GetWindowText() which will
3264                    send WM_GETTEXT messages to windows belonging to its processes */
3265                 ustr.Buffer = TopLevelWindow->strName.Buffer;
3266                 ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated
3267                 ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT);
3268                 WindowMatches = !CheckWindowName ||
3269                                 (TopLevelWindow->strName.Length < 0xFFFF &&
3270                                  !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
3271                 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
3272                                ClassAtom == TopLevelWindow->pcls->atomNVClassName;
3273 
3274                 if (WindowMatches && ClassMatches)
3275                 {
3276                    Ret = TopLevelWindow->head.h;
3277                    break;
3278                 }
3279 
3280                 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
3281                 {
3282                    /* window returns the handle of the top-level window, in case it found
3283                       the child window */
3284                    Ret = TopLevelWindow->head.h;
3285                    break;
3286                 }
3287 
3288              }
3289              ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
3290           }
3291        }
3292        else
3293        {
3294           TRACE("FindWindowEx: Not Desktop Parent!\n");
3295           Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
3296        }
3297 
3298        if (Ret == NULL && DoMessageWnd)
3299        {
3300           PWND MsgWindows;
3301 
3302           if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
3303           {
3304              Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
3305           }
3306        }
3307    }
3308    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3309    {
3310        SetLastNtError(_SEH2_GetExceptionCode());
3311        Ret = NULL;
3312    }
3313    _SEH2_END;
3314 
3315    RETURN( Ret);
3316 
3317 CLEANUP:
3318    TRACE("Leave NtUserFindWindowEx, ret %p\n", _ret_);
3319    UserLeave();
3320    END_CLEANUP;
3321 }
3322 
3323 
3324 /*
3325  * @implemented
3326  */
3327 PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type)
3328 {
3329    PWND WndAncestor, Parent;
3330 
3331    if (Wnd->head.h == IntGetDesktopWindow())
3332    {
3333       return NULL;
3334    }
3335 
3336    switch (Type)
3337    {
3338       case GA_PARENT:
3339          {
3340             WndAncestor = Wnd->spwndParent;
3341             break;
3342          }
3343 
3344       case GA_ROOT:
3345          {
3346             WndAncestor = Wnd;
3347             Parent = NULL;
3348 
3349             for(;;)
3350             {
3351                if(!(Parent = WndAncestor->spwndParent))
3352                {
3353                   break;
3354                }
3355                if(IntIsDesktopWindow(Parent))
3356                {
3357                   break;
3358                }
3359 
3360                WndAncestor = Parent;
3361             }
3362             break;
3363          }
3364 
3365       case GA_ROOTOWNER:
3366          {
3367             WndAncestor = Wnd;
3368 
3369             for (;;)
3370             {
3371                Parent = IntGetParent(WndAncestor);
3372 
3373                if (!Parent)
3374                {
3375                   break;
3376                }
3377 
3378                WndAncestor = Parent;
3379             }
3380             break;
3381          }
3382 
3383       default:
3384          {
3385             return NULL;
3386          }
3387    }
3388 
3389    return WndAncestor;
3390 }
3391 
3392 /*
3393  * @implemented
3394  */
3395 HWND APIENTRY
3396 NtUserGetAncestor(HWND hWnd, UINT Type)
3397 {
3398    PWND Window, Ancestor;
3399    DECLARE_RETURN(HWND);
3400 
3401    TRACE("Enter NtUserGetAncestor\n");
3402    UserEnterExclusive();
3403 
3404    if (!(Window = UserGetWindowObject(hWnd)))
3405    {
3406       RETURN(NULL);
3407    }
3408 
3409    Ancestor = UserGetAncestor(Window, Type);
3410    /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3411 
3412    RETURN(Ancestor ? Ancestor->head.h : NULL);
3413 
3414 CLEANUP:
3415    TRACE("Leave NtUserGetAncestor, ret=%p\n", _ret_);
3416    UserLeave();
3417    END_CLEANUP;
3418 }
3419 
3420 ////
3421 //// ReactOS work around! Keep it the sames as in Combo.c and Controls.h
3422 ////
3423 /* combo state struct */
3424 typedef struct
3425 {
3426    HWND           self;
3427    HWND           owner;
3428    UINT           dwStyle;
3429    HWND           hWndEdit;
3430    HWND           hWndLBox;
3431    UINT           wState;
3432    HFONT          hFont;
3433    RECT           textRect;
3434    RECT           buttonRect;
3435    RECT           droppedRect;
3436    INT            droppedIndex;
3437    INT            fixedOwnerDrawHeight;
3438    INT            droppedWidth;   /* last two are not used unless set */
3439    INT            editHeight;     /* explicitly */
3440    LONG           UIState;
3441 } HEADCOMBO,*LPHEADCOMBO;
3442 
3443 // Window Extra data container.
3444 typedef struct _WND2CBOX
3445 {
3446   WND;
3447   LPHEADCOMBO pCBox;
3448 } WND2CBOX, *PWND2CBOX;
3449 
3450 #define CBF_BUTTONDOWN          0x0002
3451 ////
3452 ////
3453 ////
3454 BOOL
3455 APIENTRY
3456 NtUserGetComboBoxInfo(
3457    HWND hWnd,
3458    PCOMBOBOXINFO pcbi)
3459 {
3460    PWND Wnd;
3461    PPROCESSINFO ppi;
3462    BOOL NotSameppi = FALSE;
3463    BOOL Ret = TRUE;
3464    DECLARE_RETURN(BOOL);
3465 
3466    TRACE("Enter NtUserGetComboBoxInfo\n");
3467    UserEnterShared();
3468 
3469    if (!(Wnd = UserGetWindowObject(hWnd)))
3470    {
3471       RETURN( FALSE );
3472    }
3473    _SEH2_TRY
3474    {
3475         ProbeForWrite(pcbi, sizeof(COMBOBOXINFO), 1);
3476    }
3477    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3478    {
3479        SetLastNtError(_SEH2_GetExceptionCode());
3480        _SEH2_YIELD(RETURN(FALSE));
3481    }
3482    _SEH2_END;
3483 
3484    if (pcbi->cbSize < sizeof(COMBOBOXINFO))
3485    {
3486       EngSetLastError(ERROR_INVALID_PARAMETER);
3487       RETURN(FALSE);
3488    }
3489 
3490    // Pass the user pointer, it was already probed.
3491    if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_COMBOBOX]) && Wnd->fnid != FNID_COMBOBOX)
3492    {
3493       RETURN( (BOOL) co_IntSendMessage( Wnd->head.h, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
3494    }
3495 
3496    ppi = PsGetCurrentProcessWin32Process();
3497    NotSameppi = ppi != Wnd->head.pti->ppi;
3498    if (NotSameppi)
3499    {
3500       KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3501    }
3502 
3503    _SEH2_TRY
3504    {
3505       LPHEADCOMBO lphc = ((PWND2CBOX)Wnd)->pCBox;
3506       pcbi->rcItem = lphc->textRect;
3507       pcbi->rcButton = lphc->buttonRect;
3508       pcbi->stateButton = 0;
3509       if (lphc->wState & CBF_BUTTONDOWN)
3510          pcbi->stateButton |= STATE_SYSTEM_PRESSED;
3511       if (RECTL_bIsEmptyRect(&lphc->buttonRect))
3512          pcbi->stateButton |= STATE_SYSTEM_INVISIBLE;
3513       pcbi->hwndCombo = lphc->self;
3514       pcbi->hwndItem = lphc->hWndEdit;
3515       pcbi->hwndList = lphc->hWndLBox;
3516    }
3517    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3518    {
3519       Ret = FALSE;
3520       SetLastNtError(_SEH2_GetExceptionCode());
3521    }
3522    _SEH2_END;
3523 
3524    RETURN( Ret);
3525 
3526 CLEANUP:
3527    if (NotSameppi) KeDetachProcess();
3528    TRACE("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
3529    UserLeave();
3530    END_CLEANUP;
3531 }
3532 
3533 ////
3534 //// ReactOS work around! Keep it the sames as in Listbox.c
3535 ////
3536 /* Listbox structure */
3537 typedef struct
3538 {
3539     HWND        self;           /* Our own window handle */
3540     HWND        owner;          /* Owner window to send notifications to */
3541     UINT        style;          /* Window style */
3542     INT         width;          /* Window width */
3543     INT         height;         /* Window height */
3544     VOID       *items;          /* Array of items */
3545     INT         nb_items;       /* Number of items */
3546     INT         top_item;       /* Top visible item */
3547     INT         selected_item;  /* Selected item */
3548     INT         focus_item;     /* Item that has the focus */
3549     INT         anchor_item;    /* Anchor item for extended selection */
3550     INT         item_height;    /* Default item height */
3551     INT         page_size;      /* Items per listbox page */
3552     INT         column_width;   /* Column width for multi-column listboxes */
3553 } LB_DESCR;
3554 
3555 // Window Extra data container.
3556 typedef struct _WND2LB
3557 {
3558   WND;
3559   LB_DESCR * pLBiv;
3560 } WND2LB, *PWND2LB;
3561 ////
3562 ////
3563 ////
3564 DWORD
3565 APIENTRY
3566 NtUserGetListBoxInfo(
3567    HWND hWnd)
3568 {
3569    PWND Wnd;
3570    PPROCESSINFO ppi;
3571    BOOL NotSameppi = FALSE;
3572    DWORD Ret = 0;
3573    DECLARE_RETURN(DWORD);
3574 
3575    TRACE("Enter NtUserGetListBoxInfo\n");
3576    UserEnterShared();
3577 
3578    if (!(Wnd = UserGetWindowObject(hWnd)))
3579    {
3580       RETURN( 0 );
3581    }
3582 
3583    if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_LISTBOX]) && Wnd->fnid != FNID_LISTBOX)
3584    {
3585       RETURN( (DWORD) co_IntSendMessage( Wnd->head.h, LB_GETLISTBOXINFO, 0, 0 ));
3586    }
3587 
3588    // wine lisbox:test_GetListBoxInfo lb_getlistboxinfo = 0, should not send a message!
3589    ppi = PsGetCurrentProcessWin32Process();
3590    NotSameppi = ppi != Wnd->head.pti->ppi;
3591    if (NotSameppi)
3592    {
3593       KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3594    }
3595 
3596    _SEH2_TRY
3597    {
3598       LB_DESCR *descr = ((PWND2LB)Wnd)->pLBiv;
3599       // See Controls ListBox.c:LB_GETLISTBOXINFO must match...
3600       Ret = descr->page_size;
3601    }
3602    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3603    {
3604       Ret = 0;
3605       SetLastNtError(_SEH2_GetExceptionCode());
3606    }
3607    _SEH2_END;
3608 
3609    RETURN( Ret);
3610 
3611 CLEANUP:
3612    if (NotSameppi) KeDetachProcess();
3613    TRACE("Leave NtUserGetListBoxInfo, ret=%lu\n", _ret_);
3614    UserLeave();
3615    END_CLEANUP;
3616 }
3617 
3618 /*
3619  * NtUserSetParent
3620  *
3621  * The NtUserSetParent function changes the parent window of the specified
3622  * child window.
3623  *
3624  * Remarks
3625  *    The new parent window and the child window must belong to the same
3626  *    application. If the window identified by the hWndChild parameter is
3627  *    visible, the system performs the appropriate redrawing and repainting.
3628  *    For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3629  *    or WS_POPUP window styles of the window whose parent is being changed.
3630  *
3631  * Status
3632  *    @implemented
3633  */
3634 
3635 HWND APIENTRY
3636 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
3637 {
3638    DECLARE_RETURN(HWND);
3639 
3640    TRACE("Enter NtUserSetParent\n");
3641    UserEnterExclusive();
3642 
3643    /*
3644       Check Parent first from user space, set it here.
3645     */
3646    if (!hWndNewParent)
3647    {
3648       hWndNewParent = IntGetDesktopWindow();
3649    }
3650    else if (hWndNewParent == HWND_MESSAGE)
3651    {
3652       hWndNewParent = IntGetMessageWindow();
3653    }
3654 
3655    RETURN( co_UserSetParent(hWndChild, hWndNewParent));
3656 
3657 CLEANUP:
3658    TRACE("Leave NtUserSetParent, ret=%p\n", _ret_);
3659    UserLeave();
3660    END_CLEANUP;
3661 }
3662 
3663 /*
3664  * UserGetShellWindow
3665  *
3666  * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3667  *
3668  * Status
3669  *    @implemented
3670  */
3671 HWND FASTCALL UserGetShellWindow(VOID)
3672 {
3673    PWINSTATION_OBJECT WinStaObject;
3674    HWND Ret;
3675 
3676    NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3677                      UserMode,
3678                      0,
3679                      &WinStaObject,
3680                      0);
3681 
3682    if (!NT_SUCCESS(Status))
3683    {
3684       SetLastNtError(Status);
3685       return( (HWND)0);
3686    }
3687 
3688    Ret = (HWND)WinStaObject->ShellWindow;
3689 
3690    ObDereferenceObject(WinStaObject);
3691    return( Ret);
3692 }
3693 
3694 /*
3695  * NtUserSetShellWindowEx
3696  *
3697  * This is undocumented function to set global shell window. The global
3698  * shell window has special handling of window position.
3699  *
3700  * Status
3701  *    @implemented
3702  */
3703 BOOL APIENTRY
3704 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
3705 {
3706    PWINSTATION_OBJECT WinStaObject;
3707    PWND WndShell, WndListView;
3708    DECLARE_RETURN(BOOL);
3709    USER_REFERENCE_ENTRY Ref;
3710    NTSTATUS Status;
3711    PTHREADINFO ti;
3712 
3713    TRACE("Enter NtUserSetShellWindowEx\n");
3714    UserEnterExclusive();
3715 
3716    if (!(WndShell = UserGetWindowObject(hwndShell)))
3717    {
3718       RETURN(FALSE);
3719    }
3720 
3721    if (!(WndListView = UserGetWindowObject(hwndListView)))
3722    {
3723       RETURN(FALSE);
3724    }
3725 
3726    Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3727                      UserMode,
3728                      0,
3729                      &WinStaObject,
3730                      0);
3731 
3732    if (!NT_SUCCESS(Status))
3733    {
3734       SetLastNtError(Status);
3735       RETURN( FALSE);
3736    }
3737 
3738    /*
3739     * Test if we are permitted to change the shell window.
3740     */
3741    if (WinStaObject->ShellWindow)
3742    {
3743       ObDereferenceObject(WinStaObject);
3744       RETURN( FALSE);
3745    }
3746 
3747    /*
3748     * Move shell window into background.
3749     */
3750    if (hwndListView && hwndListView != hwndShell)
3751    {
3752       /*
3753        * Disabled for now to get Explorer working.
3754        * -- Filip, 01/nov/2003
3755        */
3756 #if 0
3757       co_WinPosSetWindowPos(WndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3758 #endif
3759 
3760       if (WndListView->ExStyle & WS_EX_TOPMOST)
3761       {
3762          ObDereferenceObject(WinStaObject);
3763          RETURN( FALSE);
3764       }
3765    }
3766 
3767    if (WndShell->ExStyle & WS_EX_TOPMOST)
3768    {
3769       ObDereferenceObject(WinStaObject);
3770       RETURN( FALSE);
3771    }
3772 
3773    UserRefObjectCo(WndShell, &Ref);
3774    WndShell->state2 |= WNDS2_BOTTOMMOST;
3775    co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3776 
3777    WinStaObject->ShellWindow = hwndShell;
3778    WinStaObject->ShellListView = hwndListView;
3779 
3780    ti = GetW32ThreadInfo();
3781    if (ti->pDeskInfo)
3782    {
3783        ti->pDeskInfo->hShellWindow = hwndShell;
3784        ti->pDeskInfo->spwndShell = WndShell;
3785        ti->pDeskInfo->spwndBkGnd = WndListView;
3786        ti->pDeskInfo->ppiShellProcess = ti->ppi;
3787    }
3788 
3789    UserRegisterHotKey(WndShell, SC_TASKLIST, MOD_CONTROL, VK_ESCAPE);
3790 
3791    UserDerefObjectCo(WndShell);
3792 
3793    ObDereferenceObject(WinStaObject);
3794    RETURN( TRUE);
3795 
3796 CLEANUP:
3797    TRACE("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_);
3798    UserLeave();
3799    END_CLEANUP;
3800 }
3801 
3802 // Fixes wine Win test_window_styles and todo tests...
3803 static BOOL FASTCALL
3804 IntCheckFrameEdge(ULONG Style, ULONG ExStyle)
3805 {
3806    if (ExStyle & WS_EX_DLGMODALFRAME)
3807       return TRUE;
3808    else if (!(ExStyle & WS_EX_STATICEDGE) && (Style & (WS_DLGFRAME | WS_THICKFRAME)))
3809       return TRUE;
3810    else
3811       return FALSE;
3812 }
3813 
3814 static LONG_PTR
3815 co_IntSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi, ULONG Size, BOOL bAlter)
3816 {
3817    PWND Window, Parent;
3818    PWINSTATION_OBJECT WindowStation;
3819    LONG_PTR OldValue;
3820    STYLESTRUCT Style;
3821 
3822    if (!(Window = UserGetWindowObject(hWnd)))
3823    {
3824       return( 0);
3825    }
3826 
3827    if ((INT)Index >= 0)
3828    {
3829       if ((Index + Size) > Window->cbwndExtra)
3830       {
3831          EngSetLastError(ERROR_INVALID_INDEX);
3832          return( 0);
3833       }
3834 
3835 #ifdef _WIN64
3836       if (Size == sizeof(LONG))
3837       {
3838          OldValue = *((LONG *)((PCHAR)(Window + 1) + Index));
3839          *((LONG*)((PCHAR)(Window + 1) + Index)) = (LONG)NewValue;
3840       }
3841       else
3842 #endif
3843       {
3844          OldValue = *((LONG_PTR *)((PCHAR)(Window + 1) + Index));
3845          /*
3846          if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW)
3847          {
3848             OldValue = (LONG_PTR)IntSetWindowProc( Wnd, (WNDPROC)NewValue, Ansi);
3849             if (!OldValue) return 0;
3850          }
3851          */
3852          *((LONG_PTR*)((PCHAR)(Window + 1) + Index)) = NewValue;
3853       }
3854 
3855    }
3856    else
3857    {
3858 #ifdef _WIN64
3859       if (Size == sizeof(LONG))
3860       {
3861          if ((Index != GWL_STYLE) &&
3862              (Index != GWL_EXSTYLE) &&
3863              (Index != GWL_ID) &&
3864              (Index != GWL_USERDATA))
3865          {
3866             ERR("NtUserSetWindowLong(): Index requires pointer size: %lu\n", Index);
3867             EngSetLastError(ERROR_INVALID_INDEX);
3868             return 0;
3869          }
3870       }
3871 #endif
3872 
3873       switch (Index)
3874       {
3875          case GWL_EXSTYLE: // LONG
3876             OldValue = (LONG) Window->ExStyle;
3877             Style.styleOld = OldValue;
3878             Style.styleNew = NewValue;
3879 
3880             co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
3881 
3882             /*
3883              * Remove extended window style bit WS_EX_TOPMOST for shell windows.
3884              */
3885             WindowStation = Window->head.pti->rpdesk->rpwinstaParent;
3886             if(WindowStation)
3887             {
3888                if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
3889                   Style.styleNew &= ~WS_EX_TOPMOST;
3890             }
3891             /* WS_EX_WINDOWEDGE depends on some other styles */
3892             if (IntCheckFrameEdge(Window->style, NewValue))
3893                Style.styleNew |= WS_EX_WINDOWEDGE;
3894             else
3895                Style.styleNew &= ~WS_EX_WINDOWEDGE;
3896 
3897             if (!(Window->ExStyle & WS_EX_LAYERED))
3898             {
3899                SetLayeredStatus(Window, 0);
3900             }
3901 
3902             Window->ExStyle = (DWORD)Style.styleNew;
3903 
3904             co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
3905             break;
3906 
3907          case GWL_STYLE: // LONG
3908             OldValue = (LONG) Window->style;
3909             Style.styleOld = OldValue;
3910             Style.styleNew = NewValue;
3911 
3912             if (!bAlter)
3913                 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
3914 
3915             /* WS_CLIPSIBLINGS can't be reset on top-level windows */
3916             if (UserIsDesktopWindow(Window->spwndParent)) Style.styleNew |= WS_CLIPSIBLINGS;
3917             /* WS_MINIMIZE can't be reset */
3918             if (OldValue & WS_MINIMIZE) Style.styleNew |= WS_MINIMIZE;
3919             /* Fixes wine FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change WS_EX_WINDOWEDGE too */
3920             if (IntCheckFrameEdge(NewValue, Window->ExStyle))
3921                Window->ExStyle |= WS_EX_WINDOWEDGE;
3922             else
3923                Window->ExStyle &= ~WS_EX_WINDOWEDGE;
3924 
3925             if ((OldValue & (WS_CHILD | WS_POPUP)) == WS_CHILD)
3926             {
3927                if ((NewValue & (WS_CHILD | WS_POPUP)) != WS_CHILD)
3928                {
3929                   //// From child to non-child it should be null already.
3930                   ERR("IDMenu going null! %d\n",Window->IDMenu);
3931                   Window->IDMenu = 0; // Window->spmenu = 0;
3932                }
3933             }
3934             else
3935             {
3936                if ((NewValue & (WS_CHILD | WS_POPUP)) == WS_CHILD)
3937                {
3938                   PMENU pMenu = UserGetMenuObject(UlongToHandle(Window->IDMenu));
3939                   Window->state &= ~WNDS_HASMENU;
3940                   if (pMenu)
3941                   {
3942                      ERR("IDMenu released 0x%p\n",pMenu);
3943                      // ROS may not hold a lock after setting menu to window. But it should!
3944                      //IntReleaseMenuObject(pMenu);
3945                   }
3946                }
3947             }
3948 
3949             if ((Style.styleOld ^ Style.styleNew) & WS_VISIBLE)
3950             {
3951                if (Style.styleOld & WS_VISIBLE) Window->head.pti->cVisWindows--;
3952                if (Style.styleNew & WS_VISIBLE) Window->head.pti->cVisWindows++;
3953                DceResetActiveDCEs( Window );
3954             }
3955             Window->style = (DWORD)Style.styleNew;
3956 
3957             if (!bAlter)
3958                 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
3959             break;
3960 
3961          case GWLP_WNDPROC: // LONG_PTR
3962          {
3963             if ( Window->head.pti->ppi != PsGetCurrentProcessWin32Process() ||
3964                  Window->fnid & FNID_FREED)
3965             {
3966                EngSetLastError(ERROR_ACCESS_DENIED);
3967                return( 0);
3968             }
3969             OldValue = (LONG_PTR)IntSetWindowProc(Window,
3970                                                   (WNDPROC)NewValue,
3971                                                   Ansi);
3972             break;
3973          }
3974 
3975          case GWLP_HINSTANCE: // LONG_PTR
3976             OldValue = (LONG_PTR) Window->hModule;
3977             Window->hModule = (HINSTANCE) NewValue;
3978             break;
3979 
3980          case GWLP_HWNDPARENT: // LONG_PTR
3981             Parent = Window->spwndParent;
3982             if (Parent && (Parent->head.h == IntGetDesktopWindow()))
3983                OldValue = (LONG_PTR) IntSetOwner(Window->head.h, (HWND) NewValue);
3984             else
3985                OldValue = (LONG_PTR) co_UserSetParent(Window->head.h, (HWND) NewValue);
3986             break;
3987 
3988          case GWLP_ID: // LONG
3989             OldValue = (LONG) Window->IDMenu;
3990             Window->IDMenu = (UINT) NewValue;
3991             break;
3992 
3993          case GWLP_USERDATA: // LONG or LONG_PTR
3994             OldValue = Window->dwUserData;
3995             Window->dwUserData = NewValue;
3996             break;
3997 
3998          default:
3999             ERR("NtUserSetWindowLong(): Unsupported index %lu\n", Index);
4000             EngSetLastError(ERROR_INVALID_INDEX);
4001             OldValue = 0;
4002             break;
4003       }
4004    }
4005 
4006    return( OldValue);
4007 }
4008 
4009 LONG FASTCALL
4010 co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
4011 {
4012     return (LONG)co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG), FALSE);
4013 }
4014 
4015 LONG_PTR FASTCALL
4016 co_UserSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi)
4017 {
4018     return co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG_PTR), FALSE);
4019 }
4020 
4021 /*
4022  * NtUserSetWindowLong
4023  *
4024  * The NtUserSetWindowLong function changes an attribute of the specified
4025  * window. The function also sets the 32-bit (long) value at the specified
4026  * offset into the extra window memory.
4027  *
4028  * Status
4029  *    @implemented
4030  */
4031 
4032 LONG APIENTRY
4033 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
4034 {
4035    LONG ret;
4036 
4037    UserEnterExclusive();
4038 
4039    if (hWnd == IntGetDesktopWindow())
4040    {
4041       EngSetLastError(STATUS_ACCESS_DENIED);
4042       UserLeave();
4043       return 0;
4044    }
4045 
4046    ret = (LONG)co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG), FALSE);
4047 
4048    UserLeave();
4049 
4050    return ret;
4051 }
4052 
4053 #ifdef _WIN64
4054 LONG_PTR APIENTRY
4055 NtUserSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi)
4056 {
4057     LONG_PTR ret;
4058 
4059     UserEnterExclusive();
4060 
4061     if (hWnd == IntGetDesktopWindow())
4062     {
4063         EngSetLastError(STATUS_ACCESS_DENIED);
4064         UserLeave();
4065         return 0;
4066     }
4067 
4068     ret = co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG_PTR), FALSE);
4069 
4070     UserLeave();
4071 
4072     return ret;
4073 }
4074 #endif // _WIN64
4075 
4076 DWORD APIENTRY
4077 NtUserAlterWindowStyle(HWND hWnd, DWORD Index, LONG NewValue)
4078 {
4079    LONG ret;
4080 
4081    UserEnterExclusive();
4082 
4083    if (hWnd == IntGetDesktopWindow())
4084    {
4085       EngSetLastError(STATUS_ACCESS_DENIED);
4086       UserLeave();
4087       return 0;
4088    }
4089 
4090    ret = co_IntSetWindowLongPtr(hWnd, Index, NewValue, FALSE, sizeof(LONG), TRUE);
4091 
4092    UserLeave();
4093 
4094    return ret;
4095 }
4096 
4097 
4098 /*
4099  * NtUserSetWindowWord
4100  *
4101  * Legacy function similar to NtUserSetWindowLong.
4102  *
4103  * Status
4104  *    @implemented
4105  */
4106 
4107 WORD APIENTRY
4108 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue)
4109 {
4110    PWND Window;
4111    WORD OldValue;
4112    DECLARE_RETURN(WORD);
4113 
4114    TRACE("Enter NtUserSetWindowWord\n");
4115    UserEnterExclusive();
4116 
4117    if (hWnd == IntGetDesktopWindow())
4118    {
4119       EngSetLastError(STATUS_ACCESS_DENIED);
4120       RETURN( 0);
4121    }
4122 
4123    if (!(Window = UserGetWindowObject(hWnd)))
4124    {
4125       RETURN( 0);
4126    }
4127 
4128    switch (Index)
4129    {
4130       case GWL_ID:
4131       case GWL_HINSTANCE:
4132       case GWL_HWNDPARENT:
4133          RETURN( (WORD)co_UserSetWindowLong(UserHMGetHandle(Window), Index, (UINT)NewValue, TRUE));
4134       default:
4135          if (Index < 0)
4136          {
4137             EngSetLastError(ERROR_INVALID_INDEX);
4138             RETURN( 0);
4139          }
4140    }
4141 
4142    if ((ULONG)Index > (Window->cbwndExtra - sizeof(WORD)))
4143    {
4144       EngSetLastError(ERROR_INVALID_PARAMETER);
4145       RETURN( 0);
4146    }
4147 
4148    OldValue = *((WORD *)((PCHAR)(Window + 1) + Index));
4149    *((WORD *)((PCHAR)(Window + 1) + Index)) = NewValue;
4150 
4151    RETURN( OldValue);
4152 
4153 CLEANUP:
4154    TRACE("Leave NtUserSetWindowWord, ret=%u\n", _ret_);
4155    UserLeave();
4156    END_CLEANUP;
4157 }
4158 
4159 /*
4160  QueryWindow based on KJK::Hyperion and James Tabor.
4161 
4162  0 = QWUniqueProcessId
4163  1 = QWUniqueThreadId
4164  2 = QWActiveWindow
4165  3 = QWFocusWindow
4166  4 = QWIsHung            Implements IsHungAppWindow found
4167                                 by KJK::Hyperion.
4168 
4169  9 = QWKillWindow        When I called this with hWnd ==
4170                            DesktopWindow, it shutdown the system
4171                            and rebooted.
4172 */
4173 /*
4174  * @implemented
4175  */
4176 DWORD_PTR APIENTRY
4177 NtUserQueryWindow(HWND hWnd, DWORD Index)
4178 {
4179 /* Console Leader Process CID Window offsets */
4180 #define GWLP_CONSOLE_LEADER_PID 0
4181 #define GWLP_CONSOLE_LEADER_TID 4
4182 
4183    DWORD_PTR Result;
4184    PWND pWnd, pwndActive;
4185    PTHREADINFO pti, ptiActive;
4186    DECLARE_RETURN(UINT);
4187 
4188    TRACE("Enter NtUserQueryWindow\n");
4189    UserEnterShared();
4190 
4191    if (!(pWnd = UserGetWindowObject(hWnd)))
4192    {
4193       RETURN( 0);
4194    }
4195 
4196    switch(Index)
4197    {
4198       case QUERY_WINDOW_UNIQUE_PROCESS_ID:
4199       {
4200          if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
4201               (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) )
4202          {
4203             // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_PID)
4204             Result = (DWORD_PTR)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_PID)));
4205          }
4206          else
4207          {
4208             Result = (DWORD_PTR)IntGetWndProcessId(pWnd);
4209          }
4210          break;
4211       }
4212 
4213       case QUERY_WINDOW_UNIQUE_THREAD_ID:
4214       {
4215          if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
4216               (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) )
4217          {
4218             // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_TID)
4219             Result = (DWORD_PTR)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_TID)));
4220          }
4221          else
4222          {
4223             Result = (DWORD_PTR)IntGetWndThreadId(pWnd);
4224          }
4225          break;
4226       }
4227 
4228       case QUERY_WINDOW_ACTIVE:
4229          Result = (DWORD_PTR)(pWnd->head.pti->MessageQueue->spwndActive ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndActive) : 0);
4230          break;
4231 
4232       case QUERY_WINDOW_FOCUS:
4233          Result = (DWORD_PTR)(pWnd->head.pti->MessageQueue->spwndFocus ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndFocus) : 0);
4234          break;
4235 
4236       case QUERY_WINDOW_ISHUNG:
4237          Result = (pWnd->fnid == FNID_GHOST) || MsqIsHung(pWnd->head.pti, MSQ_HUNG);
4238          break;
4239 
4240       case QUERY_WINDOW_REAL_ID:
4241          Result = (DWORD_PTR)pWnd->head.pti->pEThread->Cid.UniqueProcess;
4242          break;
4243 
4244       case QUERY_WINDOW_FOREGROUND:
4245          Result = (pWnd->head.pti->MessageQueue == gpqForeground);
4246          break;
4247 
4248       case QUERY_WINDOW_DEFAULT_IME: /* default IME window */
4249          if (pWnd->head.pti->spwndDefaultIme)
4250             Result = (DWORD_PTR)UserHMGetHandle(pWnd->head.pti->spwndDefaultIme);
4251          else
4252             Result = 0;
4253          break;
4254 
4255       case QUERY_WINDOW_DEFAULT_ICONTEXT: /* default input context handle */
4256          if (pWnd->head.pti->spDefaultImc)
4257             Result = (DWORD_PTR)UserHMGetHandle(pWnd->head.pti->spDefaultImc);
4258          else
4259             Result = 0;
4260          break;
4261 
4262       case QUERY_WINDOW_ACTIVE_IME:
4263          Result = 0;
4264          if (gpqForeground && gpqForeground->spwndActive)
4265          {
4266              pwndActive = gpqForeground->spwndActive;
4267              pti = PsGetCurrentThreadWin32Thread();
4268              if (pti->rpdesk == pwndActive->head.rpdesk)
4269              {
4270                 ptiActive = pwndActive->head.pti;
4271                 if (ptiActive->spwndDefaultIme)
4272                    Result = (DWORD_PTR)UserHMGetHandle(ptiActive->spwndDefaultIme);
4273              }
4274          }
4275          break;
4276 
4277       default:
4278          Result = 0;
4279          break;
4280    }
4281 
4282    RETURN( Result);
4283 
4284 CLEANUP:
4285    TRACE("Leave NtUserQueryWindow, ret=%u\n", _ret_);
4286    UserLeave();
4287    END_CLEANUP;
4288 }
4289 
4290 /*
4291  * @implemented
4292  */
4293 UINT APIENTRY
4294 NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe)
4295 {
4296    UNICODE_STRING SafeMessageName;
4297    NTSTATUS Status;
4298    UINT Ret;
4299    DECLARE_RETURN(UINT);
4300 
4301    TRACE("Enter NtUserRegisterWindowMessage\n");
4302    UserEnterExclusive();
4303 
4304    if(MessageNameUnsafe == NULL)
4305    {
4306       EngSetLastError(ERROR_INVALID_PARAMETER);
4307       RETURN( 0);
4308    }
4309 
4310    Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe);
4311    if(!NT_SUCCESS(Status))
4312    {
4313       SetLastNtError(Status);
4314       RETURN( 0);
4315    }
4316 
4317    Ret = (UINT)IntAddAtom(SafeMessageName.Buffer);
4318    if (SafeMessageName.Buffer)
4319       ExFreePoolWithTag(SafeMessageName.Buffer, TAG_STRING);
4320    RETURN( Ret);
4321 
4322 CLEANUP:
4323    TRACE("Leave NtUserRegisterWindowMessage, ret=%u\n", _ret_);
4324    UserLeave();
4325    END_CLEANUP;
4326 }
4327 
4328 /*
4329  * @implemented
4330  */
4331 BOOL APIENTRY
4332 NtUserSetWindowFNID(HWND hWnd,
4333                     WORD fnID)
4334 {
4335    PWND Wnd;
4336    DECLARE_RETURN(BOOL);
4337 
4338    TRACE("Enter NtUserSetWindowFNID\n");
4339    UserEnterExclusive();
4340 
4341    if (!(Wnd = UserGetWindowObject(hWnd)))
4342    {
4343       RETURN( FALSE);
4344    }
4345 
4346    if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
4347    {
4348       EngSetLastError(ERROR_ACCESS_DENIED);
4349       RETURN( FALSE);
4350    }
4351 
4352    // From user land we only set these.
4353    if (fnID != FNID_DESTROY)
4354    {
4355       /* HACK: The minimum should be FNID_BUTTON, but menu code relies on this */
4356       if (fnID < FNID_FIRST || fnID > FNID_GHOST ||
4357           Wnd->fnid != 0)
4358       {
4359          EngSetLastError(ERROR_INVALID_PARAMETER);
4360          RETURN( FALSE);
4361       }
4362    }
4363 
4364    Wnd->fnid |= fnID;
4365    RETURN( TRUE);
4366 
4367 CLEANUP:
4368    TRACE("Leave NtUserSetWindowFNID\n");
4369    UserLeave();
4370    END_CLEANUP;
4371 }
4372 
4373 BOOL APIENTRY
4374 DefSetText(PWND Wnd, PCWSTR WindowText)
4375 {
4376    UNICODE_STRING UnicodeString;
4377    BOOL Ret = FALSE;
4378 
4379    RtlInitUnicodeString(&UnicodeString, WindowText);
4380 
4381    if (UnicodeString.Length != 0)
4382    {
4383       if (Wnd->strName.MaximumLength > 0 &&
4384           UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
4385       {
4386          ASSERT(Wnd->strName.Buffer != NULL);
4387 
4388          Wnd->strName.Length = UnicodeString.Length;
4389          Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4390          RtlCopyMemory(Wnd->strName.Buffer,
4391                               UnicodeString.Buffer,
4392                               UnicodeString.Length);
4393       }
4394       else
4395       {
4396          PWCHAR buf;
4397          Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4398          buf = Wnd->strName.Buffer;
4399          Wnd->strName.Buffer = NULL;
4400          if (buf != NULL)
4401          {
4402             DesktopHeapFree(Wnd->head.rpdesk, buf);
4403          }
4404 
4405          Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
4406                                                    UnicodeString.Length + sizeof(UNICODE_NULL));
4407          if (Wnd->strName.Buffer != NULL)
4408          {
4409             Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4410             RtlCopyMemory(Wnd->strName.Buffer,
4411                                  UnicodeString.Buffer,
4412                                  UnicodeString.Length);
4413             Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4414             Wnd->strName.Length = UnicodeString.Length;
4415          }
4416          else
4417          {
4418             EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4419             goto Exit;
4420          }
4421       }
4422    }
4423    else
4424    {
4425       Wnd->strName.Length = 0;
4426       if (Wnd->strName.Buffer != NULL)
4427           Wnd->strName.Buffer[0] = L'\0';
4428    }
4429 
4430    // FIXME: HAX! Windows does not do this in here!
4431    // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4432    // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4433    /* Send shell notifications */
4434    if (!Wnd->spwndOwner && !IntGetParent(Wnd))
4435    {
4436       co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) UserHMGetHandle(Wnd), FALSE); // FIXME Flashing?
4437    }
4438 
4439    Ret = TRUE;
4440 Exit:
4441    if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
4442    return Ret;
4443 }
4444 
4445 /*
4446  * NtUserDefSetText
4447  *
4448  * Undocumented function that is called from DefWindowProc to set
4449  * window text.
4450  *
4451  * Status
4452  *    @implemented
4453  */
4454 BOOL APIENTRY
4455 NtUserDefSetText(HWND hWnd, PLARGE_STRING WindowText)
4456 {
4457    PWND Wnd;
4458    LARGE_STRING SafeText;
4459    UNICODE_STRING UnicodeString;
4460    BOOL Ret = TRUE;
4461 
4462    TRACE("Enter NtUserDefSetText\n");
4463 
4464    if (WindowText != NULL)
4465    {
4466       _SEH2_TRY
4467       {
4468          SafeText = ProbeForReadLargeString(WindowText);
4469       }
4470       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4471       {
4472          Ret = FALSE;
4473          SetLastNtError(_SEH2_GetExceptionCode());
4474       }
4475       _SEH2_END;
4476 
4477       if (!Ret)
4478          return FALSE;
4479    }
4480    else
4481       return TRUE;
4482 
4483    UserEnterExclusive();
4484 
4485    if(!(Wnd = UserGetWindowObject(hWnd)))
4486    {
4487       UserLeave();
4488       return FALSE;
4489    }
4490 
4491    // ReactOS uses Unicode and not mixed. Up/Down converting will take time.
4492    // Brought to you by: The Wine Project! Dysfunctional Thought Processes!
4493    // Now we know what the bAnsi is for.
4494    RtlInitUnicodeString(&UnicodeString, NULL);
4495    if (SafeText.Buffer)
4496    {
4497       _SEH2_TRY
4498       {
4499          if (SafeText.bAnsi)
4500             ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(CHAR));
4501          else
4502             ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(WCHAR));
4503          Ret = RtlLargeStringToUnicodeString(&UnicodeString, &SafeText);
4504       }
4505       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4506       {
4507          Ret = FALSE;
4508          SetLastNtError(_SEH2_GetExceptionCode());
4509       }
4510       _SEH2_END;
4511       if (!Ret) goto Exit;
4512    }
4513 
4514    if (UnicodeString.Length != 0)
4515    {
4516       if (Wnd->strName.MaximumLength > 0 &&
4517           UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
4518       {
4519          ASSERT(Wnd->strName.Buffer != NULL);
4520 
4521          Wnd->strName.Length = UnicodeString.Length;
4522          Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4523          RtlCopyMemory(Wnd->strName.Buffer,
4524                               UnicodeString.Buffer,
4525                               UnicodeString.Length);
4526       }
4527       else
4528       {
4529          PWCHAR buf;
4530          Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4531          buf = Wnd->strName.Buffer;
4532          Wnd->strName.Buffer = NULL;
4533          if (buf != NULL)
4534          {
4535             DesktopHeapFree(Wnd->head.rpdesk, buf);
4536          }
4537 
4538          Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
4539                                                    UnicodeString.Length + sizeof(UNICODE_NULL));
4540          if (Wnd->strName.Buffer != NULL)
4541          {
4542             Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4543             RtlCopyMemory(Wnd->strName.Buffer,
4544                                  UnicodeString.Buffer,
4545                                  UnicodeString.Length);
4546             Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4547             Wnd->strName.Length = UnicodeString.Length;
4548          }
4549          else
4550          {
4551             EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4552             Ret = FALSE;
4553             goto Exit;
4554          }
4555       }
4556    }
4557    else
4558    {
4559       Wnd->strName.Length = 0;
4560       if (Wnd->strName.Buffer != NULL)
4561           Wnd->strName.Buffer[0] = L'\0';
4562    }
4563 
4564    // FIXME: HAX! Windows does not do this in here!
4565    // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4566    // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4567    /* Send shell notifications */
4568    if (!Wnd->spwndOwner && !IntGetParent(Wnd))
4569    {
4570       co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) hWnd, FALSE); // FIXME Flashing?
4571    }
4572 
4573    Ret = TRUE;
4574 Exit:
4575    if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
4576    TRACE("Leave NtUserDefSetText, ret=%i\n", Ret);
4577    UserLeave();
4578    return Ret;
4579 }
4580 
4581 /*
4582  * NtUserInternalGetWindowText
4583  *
4584  * Status
4585  *    @implemented
4586  */
4587 
4588 INT APIENTRY
4589 NtUserInternalGetWindowText(HWND hWnd, LPWSTR lpString, INT nMaxCount)
4590 {
4591    PWND Wnd;
4592    NTSTATUS Status;
4593    INT Result;
4594    DECLARE_RETURN(INT);
4595 
4596    TRACE("Enter NtUserInternalGetWindowText\n");
4597    UserEnterShared();
4598 
4599    if(lpString && (nMaxCount <= 1))
4600    {
4601       EngSetLastError(ERROR_INVALID_PARAMETER);
4602       RETURN( 0);
4603    }
4604 
4605    if(!(Wnd = UserGetWindowObject(hWnd)))
4606    {
4607       RETURN( 0);
4608    }
4609 
4610    Result = Wnd->strName.Length / sizeof(WCHAR);
4611    if(lpString)
4612    {
4613       const WCHAR Terminator = L'\0';
4614       INT Copy;
4615       WCHAR *Buffer = (WCHAR*)lpString;
4616 
4617       Copy = min(nMaxCount - 1, Result);
4618       if(Copy > 0)
4619       {
4620          Status = MmCopyToCaller(Buffer, Wnd->strName.Buffer, Copy * sizeof(WCHAR));
4621          if(!NT_SUCCESS(Status))
4622          {
4623             SetLastNtError(Status);
4624             RETURN( 0);
4625          }
4626          Buffer += Copy;
4627       }
4628 
4629       Status = MmCopyToCaller(Buffer, &Terminator, sizeof(WCHAR));
4630       if(!NT_SUCCESS(Status))
4631       {
4632          SetLastNtError(Status);
4633          RETURN( 0);
4634       }
4635 
4636       Result = Copy;
4637    }
4638 
4639    RETURN( Result);
4640 
4641 CLEANUP:
4642    TRACE("Leave NtUserInternalGetWindowText, ret=%i\n",_ret_);
4643    UserLeave();
4644    END_CLEANUP;
4645 }
4646 
4647 /*
4648   API Call
4649 */
4650 BOOL
4651 FASTCALL
4652 IntShowOwnedPopups(PWND OwnerWnd, BOOL fShow )
4653 {
4654    int count = 0;
4655    PWND pWnd;
4656    HWND *win_array;
4657 
4658 //   ASSERT(OwnerWnd);
4659 
4660    TRACE("Enter ShowOwnedPopups Show: %s\n", (fShow ? "TRUE" : "FALSE"));
4661 
4662    /* NOTE: Popups are not children */
4663    win_array = IntWinListOwnedPopups(OwnerWnd);
4664 
4665    if (!win_array)
4666       return TRUE;
4667 
4668    while (win_array[count])
4669       count++;
4670    while (--count >= 0)
4671    {
4672       if (!(pWnd = ValidateHwndNoErr( win_array[count] )))
4673          continue;
4674       if (pWnd->spwndOwner != OwnerWnd)
4675          continue;
4676 
4677       if (fShow)
4678       {
4679          if (pWnd->state & WNDS_HIDDENPOPUP)
4680          {
4681             /* In Windows, ShowOwnedPopups(TRUE) generates
4682              * WM_SHOWWINDOW messages with SW_PARENTOPENING,
4683              * regardless of the state of the owner
4684              */
4685             co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
4686             pWnd->state &= ~WNDS_HIDDENPOPUP;
4687             continue;
4688          }
4689       }
4690       else
4691       {
4692          if (pWnd->style & WS_VISIBLE)
4693          {
4694             /* In Windows, ShowOwnedPopups(FALSE) generates
4695              * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
4696              * regardless of the state of the owner
4697              */
4698             co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
4699             pWnd->state |= WNDS_HIDDENPOPUP;
4700             continue;
4701          }
4702       }
4703    }
4704    ExFreePoolWithTag(win_array, USERTAG_WINDOWLIST);
4705    TRACE("Leave ShowOwnedPopups\n");
4706    return TRUE;
4707 }
4708 
4709 /* EOF */
4710