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