xref: /reactos/win32ss/user/ntuser/window.c (revision 10e7643c)
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS Win32k subsystem
4  * PURPOSE:          Windows
5  * FILE:             win32ss/user/ntuser/window.c
6  * PROGRAMERS:       Casper S. Hornstrup (chorns@users.sourceforge.net)
7  *                   Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
8  */
9 
10 #include <win32k.h>
11 #include <ddk/immdev.h>
12 DBG_DEFAULT_CHANNEL(UserWnd);
13 
14 INT gNestedWindowLimit = 50;
15 
16 PWINDOWLIST gpwlList = NULL;
17 PWINDOWLIST gpwlCache = NULL;
18 
19 /* HELPER FUNCTIONS ***********************************************************/
20 
21 PVOID FASTCALL
22 IntReAllocatePoolWithTag(
23     POOL_TYPE PoolType,
24     PVOID pOld,
25     SIZE_T cbOld,
26     SIZE_T cbNew,
27     ULONG Tag)
28 {
29     PVOID pNew = ExAllocatePoolWithTag(PoolType, cbNew, Tag);
30     if (!pNew)
31         return NULL;
32 
33     RtlCopyMemory(pNew, pOld, min(cbOld, cbNew));
34     ExFreePoolWithTag(pOld, Tag);
35     return pNew;
36 }
37 
38 BOOL FASTCALL UserUpdateUiState(PWND Wnd, WPARAM wParam)
39 {
40     WORD Action = LOWORD(wParam);
41     WORD Flags = HIWORD(wParam);
42 
43     if (Flags & ~(UISF_HIDEFOCUS | UISF_HIDEACCEL | UISF_ACTIVE))
44     {
45         EngSetLastError(ERROR_INVALID_PARAMETER);
46         return FALSE;
47     }
48 
49     switch (Action)
50     {
51         case UIS_INITIALIZE:
52             EngSetLastError(ERROR_INVALID_PARAMETER);
53             return FALSE;
54 
55         case UIS_SET:
56             if (Flags & UISF_HIDEFOCUS)
57                 Wnd->HideFocus = TRUE;
58             if (Flags & UISF_HIDEACCEL)
59                 Wnd->HideAccel = TRUE;
60             break;
61 
62         case UIS_CLEAR:
63             if (Flags & UISF_HIDEFOCUS)
64                 Wnd->HideFocus = FALSE;
65             if (Flags & UISF_HIDEACCEL)
66                 Wnd->HideAccel = FALSE;
67             break;
68     }
69 
70     return TRUE;
71 }
72 
73 PWND FASTCALL IntGetWindowObject(HWND hWnd)
74 {
75    PWND Window;
76 
77    if (!hWnd) return NULL;
78 
79    Window = UserGetWindowObject(hWnd);
80    if (Window)
81       Window->head.cLockObj++;
82 
83    return Window;
84 }
85 
86 PWND FASTCALL VerifyWnd(PWND pWnd)
87 {
88     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++] = Child->head.h;
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++] = Child->head.h;
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 (Window->head.h == ThreadData->rpdesk->rpwinstaParent->ShellWindow)
661          ThreadData->rpdesk->rpwinstaParent->ShellWindow = NULL;
662 
663       if (Window->head.h == 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 = WndOldParent->head.h;
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 = Window->head.h;
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 = Window->head.h;
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( pWindow->spwndParent->head.h,
1702                                WM_PARENTNOTIFY,
1703                                MAKEWPARAM( msg, pWindow->IDMenu),
1704                                (LPARAM)pWindow->head.h );
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 = pti->rpdesk->pDeskInfo->spwnd->head.h;
2219    hWndOwner = NULL;
2220 
2221     if (Cs->hwndParent == HWND_MESSAGE)
2222     {
2223         Cs->hwndParent = hWndParent = pti->rpdesk->spwndMessage->head.h;
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(Window->head.h, 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 = Window->head.h;
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    DECLARE_RETURN(BOOLEAN);
3041    BOOLEAN ret;
3042    USER_REFERENCE_ENTRY Ref;
3043 
3044    TRACE("Enter NtUserDestroyWindow\n");
3045    UserEnterExclusive();
3046 
3047    if (!(Window = UserGetWindowObject(Wnd)))
3048    {
3049       RETURN(FALSE);
3050    }
3051 
3052    UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy...
3053    ret = co_UserDestroyWindow(Window);
3054    UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy...
3055 
3056    RETURN(ret);
3057 
3058 CLEANUP:
3059    TRACE("Leave NtUserDestroyWindow, ret=%u\n", _ret_);
3060    UserLeave();
3061    END_CLEANUP;
3062 }
3063 
3064 
3065 HWND FASTCALL
3066 IntFindWindow(PWND Parent,
3067               PWND ChildAfter,
3068               RTL_ATOM ClassAtom,
3069               PUNICODE_STRING WindowName)
3070 {
3071    BOOL CheckWindowName;
3072    HWND *List, *phWnd;
3073    HWND Ret = NULL;
3074    UNICODE_STRING CurrentWindowName;
3075 
3076    ASSERT(Parent);
3077 
3078    CheckWindowName = WindowName->Buffer != 0;
3079 
3080    if((List = IntWinListChildren(Parent)))
3081    {
3082       phWnd = List;
3083       if(ChildAfter)
3084       {
3085          /* skip handles before and including ChildAfter */
3086          while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
3087             ;
3088       }
3089 
3090       /* search children */
3091       while(*phWnd)
3092       {
3093          PWND Child;
3094          if(!(Child = UserGetWindowObject(*(phWnd++))))
3095          {
3096             continue;
3097          }
3098 
3099          /* Do not send WM_GETTEXT messages in the kernel mode version!
3100             The user mode version however calls GetWindowText() which will
3101             send WM_GETTEXT messages to windows belonging to its processes */
3102          if (!ClassAtom || Child->pcls->atomNVClassName == ClassAtom)
3103          {
3104              // FIXME: LARGE_STRING truncated
3105              CurrentWindowName.Buffer = Child->strName.Buffer;
3106              CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT);
3107              CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT);
3108              if(!CheckWindowName ||
3109                 (Child->strName.Length < 0xFFFF &&
3110                  !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
3111              {
3112                 Ret = Child->head.h;
3113                 break;
3114              }
3115          }
3116       }
3117       ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
3118    }
3119 
3120    return Ret;
3121 }
3122 
3123 /*
3124  * FUNCTION:
3125  *   Searches a window's children for a window with the specified
3126  *   class and name
3127  * ARGUMENTS:
3128  *   hwndParent     = The window whose childs are to be searched.
3129  *       NULL = desktop
3130  *       HWND_MESSAGE = message-only windows
3131  *
3132  *   hwndChildAfter = Search starts after this child window.
3133  *       NULL = start from beginning
3134  *
3135  *   ucClassName    = Class name to search for
3136  *       Reguired parameter.
3137  *
3138  *   ucWindowName   = Window name
3139  *       ->Buffer == NULL = don't care
3140  *
3141  * RETURNS:
3142  *   The HWND of the window if it was found, otherwise NULL
3143  */
3144 /*
3145  * @implemented
3146  */
3147 HWND APIENTRY
3148 NtUserFindWindowEx(HWND hwndParent,
3149                    HWND hwndChildAfter,
3150                    PUNICODE_STRING ucClassName,
3151                    PUNICODE_STRING ucWindowName,
3152                    DWORD dwUnknown)
3153 {
3154    PWND Parent, ChildAfter;
3155    UNICODE_STRING ClassName = {0}, WindowName = {0};
3156    HWND Desktop, Ret = NULL;
3157    BOOL DoMessageWnd = FALSE;
3158    RTL_ATOM ClassAtom = (RTL_ATOM)0;
3159    DECLARE_RETURN(HWND);
3160 
3161    TRACE("Enter NtUserFindWindowEx\n");
3162    UserEnterShared();
3163 
3164    if (ucClassName != NULL || ucWindowName != NULL)
3165    {
3166        _SEH2_TRY
3167        {
3168            if (ucClassName != NULL)
3169            {
3170                ClassName = ProbeForReadUnicodeString(ucClassName);
3171                if (ClassName.Length != 0)
3172                {
3173                    ProbeForRead(ClassName.Buffer,
3174                                 ClassName.Length,
3175                                 sizeof(WCHAR));
3176                }
3177                else if (!IS_ATOM(ClassName.Buffer))
3178                {
3179                    EngSetLastError(ERROR_INVALID_PARAMETER);
3180                    _SEH2_LEAVE;
3181                }
3182 
3183                if (!IntGetAtomFromStringOrAtom(&ClassName,
3184                                                &ClassAtom))
3185                {
3186                    EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS);
3187                    _SEH2_LEAVE;
3188                }
3189            }
3190 
3191            if (ucWindowName != NULL)
3192            {
3193                WindowName = ProbeForReadUnicodeString(ucWindowName);
3194                if (WindowName.Length != 0)
3195                {
3196                    ProbeForRead(WindowName.Buffer,
3197                                 WindowName.Length,
3198                                 sizeof(WCHAR));
3199                }
3200            }
3201        }
3202        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3203        {
3204            SetLastNtError(_SEH2_GetExceptionCode());
3205            _SEH2_YIELD(RETURN(NULL));
3206        }
3207        _SEH2_END;
3208 
3209        if (ucClassName != NULL)
3210        {
3211            if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
3212                !IS_ATOM(ClassName.Buffer))
3213            {
3214                EngSetLastError(ERROR_INVALID_PARAMETER);
3215                RETURN(NULL);
3216            }
3217            else if (ClassAtom == (RTL_ATOM)0)
3218            {
3219                /* LastError code was set by IntGetAtomFromStringOrAtom */
3220                RETURN(NULL);
3221            }
3222        }
3223    }
3224 
3225    Desktop = IntGetCurrentThreadDesktopWindow();
3226 
3227    if(hwndParent == NULL)
3228    {
3229       hwndParent = Desktop;
3230       DoMessageWnd = TRUE;
3231    }
3232    else if(hwndParent == HWND_MESSAGE)
3233    {
3234      hwndParent = IntGetMessageWindow();
3235    }
3236 
3237    if(!(Parent = UserGetWindowObject(hwndParent)))
3238    {
3239       RETURN( NULL);
3240    }
3241 
3242    ChildAfter = NULL;
3243    if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
3244    {
3245       RETURN( NULL);
3246    }
3247 
3248    _SEH2_TRY
3249    {
3250        if(Parent->head.h == Desktop)
3251        {
3252           HWND *List, *phWnd;
3253           PWND TopLevelWindow;
3254           BOOLEAN CheckWindowName;
3255           BOOLEAN WindowMatches;
3256           BOOLEAN ClassMatches;
3257 
3258           /* windows searches through all top-level windows if the parent is the desktop
3259              window */
3260 
3261           if((List = IntWinListChildren(Parent)))
3262           {
3263              phWnd = List;
3264 
3265              if(ChildAfter)
3266              {
3267                 /* skip handles before and including ChildAfter */
3268                 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
3269                    ;
3270              }
3271 
3272              CheckWindowName = WindowName.Buffer != 0;
3273 
3274              /* search children */
3275              while(*phWnd)
3276              {
3277                  UNICODE_STRING ustr;
3278 
3279                 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
3280                 {
3281                    continue;
3282                 }
3283 
3284                 /* Do not send WM_GETTEXT messages in the kernel mode version!
3285                    The user mode version however calls GetWindowText() which will
3286                    send WM_GETTEXT messages to windows belonging to its processes */
3287                 ustr.Buffer = TopLevelWindow->strName.Buffer;
3288                 ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated
3289                 ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT);
3290                 WindowMatches = !CheckWindowName ||
3291                                 (TopLevelWindow->strName.Length < 0xFFFF &&
3292                                  !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
3293                 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
3294                                ClassAtom == TopLevelWindow->pcls->atomNVClassName;
3295 
3296                 if (WindowMatches && ClassMatches)
3297                 {
3298                    Ret = TopLevelWindow->head.h;
3299                    break;
3300                 }
3301 
3302                 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
3303                 {
3304                    /* window returns the handle of the top-level window, in case it found
3305                       the child window */
3306                    Ret = TopLevelWindow->head.h;
3307                    break;
3308                 }
3309 
3310              }
3311              ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
3312           }
3313        }
3314        else
3315        {
3316           TRACE("FindWindowEx: Not Desktop Parent!\n");
3317           Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
3318        }
3319 
3320        if (Ret == NULL && DoMessageWnd)
3321        {
3322           PWND MsgWindows;
3323 
3324           if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
3325           {
3326              Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
3327           }
3328        }
3329    }
3330    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3331    {
3332        SetLastNtError(_SEH2_GetExceptionCode());
3333        Ret = NULL;
3334    }
3335    _SEH2_END;
3336 
3337    RETURN( Ret);
3338 
3339 CLEANUP:
3340    TRACE("Leave NtUserFindWindowEx, ret %p\n", _ret_);
3341    UserLeave();
3342    END_CLEANUP;
3343 }
3344 
3345 
3346 /*
3347  * @implemented
3348  */
3349 PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type)
3350 {
3351    PWND WndAncestor, Parent;
3352 
3353    if (Wnd->head.h == IntGetDesktopWindow())
3354    {
3355       return NULL;
3356    }
3357 
3358    switch (Type)
3359    {
3360       case GA_PARENT:
3361          {
3362             WndAncestor = Wnd->spwndParent;
3363             break;
3364          }
3365 
3366       case GA_ROOT:
3367          {
3368             WndAncestor = Wnd;
3369             Parent = NULL;
3370 
3371             for(;;)
3372             {
3373                if(!(Parent = WndAncestor->spwndParent))
3374                {
3375                   break;
3376                }
3377                if(IntIsDesktopWindow(Parent))
3378                {
3379                   break;
3380                }
3381 
3382                WndAncestor = Parent;
3383             }
3384             break;
3385          }
3386 
3387       case GA_ROOTOWNER:
3388          {
3389             WndAncestor = Wnd;
3390 
3391             for (;;)
3392             {
3393                Parent = IntGetParent(WndAncestor);
3394 
3395                if (!Parent)
3396                {
3397                   break;
3398                }
3399 
3400                WndAncestor = Parent;
3401             }
3402             break;
3403          }
3404 
3405       default:
3406          {
3407             return NULL;
3408          }
3409    }
3410 
3411    return WndAncestor;
3412 }
3413 
3414 /*
3415  * @implemented
3416  */
3417 HWND APIENTRY
3418 NtUserGetAncestor(HWND hWnd, UINT Type)
3419 {
3420    PWND Window, Ancestor;
3421    DECLARE_RETURN(HWND);
3422 
3423    TRACE("Enter NtUserGetAncestor\n");
3424    UserEnterExclusive();
3425 
3426    if (!(Window = UserGetWindowObject(hWnd)))
3427    {
3428       RETURN(NULL);
3429    }
3430 
3431    Ancestor = UserGetAncestor(Window, Type);
3432    /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3433 
3434    RETURN(Ancestor ? Ancestor->head.h : NULL);
3435 
3436 CLEANUP:
3437    TRACE("Leave NtUserGetAncestor, ret=%p\n", _ret_);
3438    UserLeave();
3439    END_CLEANUP;
3440 }
3441 
3442 ////
3443 //// ReactOS work around! Keep it the sames as in Combo.c and Controls.h
3444 ////
3445 /* combo state struct */
3446 typedef struct
3447 {
3448    HWND           self;
3449    HWND           owner;
3450    UINT           dwStyle;
3451    HWND           hWndEdit;
3452    HWND           hWndLBox;
3453    UINT           wState;
3454    HFONT          hFont;
3455    RECT           textRect;
3456    RECT           buttonRect;
3457    RECT           droppedRect;
3458    INT            droppedIndex;
3459    INT            fixedOwnerDrawHeight;
3460    INT            droppedWidth;   /* last two are not used unless set */
3461    INT            editHeight;     /* explicitly */
3462    LONG           UIState;
3463 } HEADCOMBO,*LPHEADCOMBO;
3464 
3465 // Window Extra data container.
3466 typedef struct _WND2CBOX
3467 {
3468   WND;
3469   LPHEADCOMBO pCBox;
3470 } WND2CBOX, *PWND2CBOX;
3471 
3472 #define CBF_BUTTONDOWN          0x0002
3473 ////
3474 ////
3475 ////
3476 BOOL
3477 APIENTRY
3478 NtUserGetComboBoxInfo(
3479    HWND hWnd,
3480    PCOMBOBOXINFO pcbi)
3481 {
3482    PWND Wnd;
3483    PPROCESSINFO ppi;
3484    BOOL NotSameppi = FALSE;
3485    BOOL Ret = TRUE;
3486    DECLARE_RETURN(BOOL);
3487 
3488    TRACE("Enter NtUserGetComboBoxInfo\n");
3489    UserEnterShared();
3490 
3491    if (!(Wnd = UserGetWindowObject(hWnd)))
3492    {
3493       RETURN( FALSE );
3494    }
3495    _SEH2_TRY
3496    {
3497         ProbeForWrite(pcbi, sizeof(COMBOBOXINFO), 1);
3498    }
3499    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3500    {
3501        SetLastNtError(_SEH2_GetExceptionCode());
3502        _SEH2_YIELD(RETURN(FALSE));
3503    }
3504    _SEH2_END;
3505 
3506    if (pcbi->cbSize < sizeof(COMBOBOXINFO))
3507    {
3508       EngSetLastError(ERROR_INVALID_PARAMETER);
3509       RETURN(FALSE);
3510    }
3511 
3512    // Pass the user pointer, it was already probed.
3513    if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_COMBOBOX]) && Wnd->fnid != FNID_COMBOBOX)
3514    {
3515       RETURN( (BOOL) co_IntSendMessage( Wnd->head.h, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
3516    }
3517 
3518    ppi = PsGetCurrentProcessWin32Process();
3519    NotSameppi = ppi != Wnd->head.pti->ppi;
3520    if (NotSameppi)
3521    {
3522       KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3523    }
3524 
3525    _SEH2_TRY
3526    {
3527       LPHEADCOMBO lphc = ((PWND2CBOX)Wnd)->pCBox;
3528       pcbi->rcItem = lphc->textRect;
3529       pcbi->rcButton = lphc->buttonRect;
3530       pcbi->stateButton = 0;
3531       if (lphc->wState & CBF_BUTTONDOWN)
3532          pcbi->stateButton |= STATE_SYSTEM_PRESSED;
3533       if (RECTL_bIsEmptyRect(&lphc->buttonRect))
3534          pcbi->stateButton |= STATE_SYSTEM_INVISIBLE;
3535       pcbi->hwndCombo = lphc->self;
3536       pcbi->hwndItem = lphc->hWndEdit;
3537       pcbi->hwndList = lphc->hWndLBox;
3538    }
3539    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3540    {
3541       Ret = FALSE;
3542       SetLastNtError(_SEH2_GetExceptionCode());
3543    }
3544    _SEH2_END;
3545 
3546    RETURN( Ret);
3547 
3548 CLEANUP:
3549    if (NotSameppi) KeDetachProcess();
3550    TRACE("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
3551    UserLeave();
3552    END_CLEANUP;
3553 }
3554 
3555 ////
3556 //// ReactOS work around! Keep it the sames as in Listbox.c
3557 ////
3558 /* Listbox structure */
3559 typedef struct
3560 {
3561     HWND        self;           /* Our own window handle */
3562     HWND        owner;          /* Owner window to send notifications to */
3563     UINT        style;          /* Window style */
3564     INT         width;          /* Window width */
3565     INT         height;         /* Window height */
3566     VOID       *items;          /* Array of items */
3567     INT         nb_items;       /* Number of items */
3568     INT         top_item;       /* Top visible item */
3569     INT         selected_item;  /* Selected item */
3570     INT         focus_item;     /* Item that has the focus */
3571     INT         anchor_item;    /* Anchor item for extended selection */
3572     INT         item_height;    /* Default item height */
3573     INT         page_size;      /* Items per listbox page */
3574     INT         column_width;   /* Column width for multi-column listboxes */
3575 } LB_DESCR;
3576 
3577 // Window Extra data container.
3578 typedef struct _WND2LB
3579 {
3580   WND;
3581   LB_DESCR * pLBiv;
3582 } WND2LB, *PWND2LB;
3583 ////
3584 ////
3585 ////
3586 DWORD
3587 APIENTRY
3588 NtUserGetListBoxInfo(
3589    HWND hWnd)
3590 {
3591    PWND Wnd;
3592    PPROCESSINFO ppi;
3593    BOOL NotSameppi = FALSE;
3594    DWORD Ret = 0;
3595    DECLARE_RETURN(DWORD);
3596 
3597    TRACE("Enter NtUserGetListBoxInfo\n");
3598    UserEnterShared();
3599 
3600    if (!(Wnd = UserGetWindowObject(hWnd)))
3601    {
3602       RETURN( 0 );
3603    }
3604 
3605    if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_LISTBOX]) && Wnd->fnid != FNID_LISTBOX)
3606    {
3607       RETURN( (DWORD) co_IntSendMessage( Wnd->head.h, LB_GETLISTBOXINFO, 0, 0 ));
3608    }
3609 
3610    // wine lisbox:test_GetListBoxInfo lb_getlistboxinfo = 0, should not send a message!
3611    ppi = PsGetCurrentProcessWin32Process();
3612    NotSameppi = ppi != Wnd->head.pti->ppi;
3613    if (NotSameppi)
3614    {
3615       KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3616    }
3617 
3618    _SEH2_TRY
3619    {
3620       LB_DESCR *descr = ((PWND2LB)Wnd)->pLBiv;
3621       // See Controls ListBox.c:LB_GETLISTBOXINFO must match...
3622       Ret = descr->page_size;
3623    }
3624    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3625    {
3626       Ret = 0;
3627       SetLastNtError(_SEH2_GetExceptionCode());
3628    }
3629    _SEH2_END;
3630 
3631    RETURN( Ret);
3632 
3633 CLEANUP:
3634    if (NotSameppi) KeDetachProcess();
3635    TRACE("Leave NtUserGetListBoxInfo, ret=%lu\n", _ret_);
3636    UserLeave();
3637    END_CLEANUP;
3638 }
3639 
3640 /*
3641  * NtUserSetParent
3642  *
3643  * The NtUserSetParent function changes the parent window of the specified
3644  * child window.
3645  *
3646  * Remarks
3647  *    The new parent window and the child window must belong to the same
3648  *    application. If the window identified by the hWndChild parameter is
3649  *    visible, the system performs the appropriate redrawing and repainting.
3650  *    For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3651  *    or WS_POPUP window styles of the window whose parent is being changed.
3652  *
3653  * Status
3654  *    @implemented
3655  */
3656 
3657 HWND APIENTRY
3658 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
3659 {
3660    DECLARE_RETURN(HWND);
3661 
3662    TRACE("Enter NtUserSetParent\n");
3663    UserEnterExclusive();
3664 
3665    /*
3666       Check Parent first from user space, set it here.
3667     */
3668    if (!hWndNewParent)
3669    {
3670       hWndNewParent = IntGetDesktopWindow();
3671    }
3672    else if (hWndNewParent == HWND_MESSAGE)
3673    {
3674       hWndNewParent = IntGetMessageWindow();
3675    }
3676 
3677    RETURN( co_UserSetParent(hWndChild, hWndNewParent));
3678 
3679 CLEANUP:
3680    TRACE("Leave NtUserSetParent, ret=%p\n", _ret_);
3681    UserLeave();
3682    END_CLEANUP;
3683 }
3684 
3685 /*
3686  * UserGetShellWindow
3687  *
3688  * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3689  *
3690  * Status
3691  *    @implemented
3692  */
3693 HWND FASTCALL UserGetShellWindow(VOID)
3694 {
3695    PWINSTATION_OBJECT WinStaObject;
3696    HWND Ret;
3697 
3698    NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3699                      UserMode,
3700                      0,
3701                      &WinStaObject,
3702                      0);
3703 
3704    if (!NT_SUCCESS(Status))
3705    {
3706       SetLastNtError(Status);
3707       return( (HWND)0);
3708    }
3709 
3710    Ret = (HWND)WinStaObject->ShellWindow;
3711 
3712    ObDereferenceObject(WinStaObject);
3713    return( Ret);
3714 }
3715 
3716 /*
3717  * NtUserSetShellWindowEx
3718  *
3719  * This is undocumented function to set global shell window. The global
3720  * shell window has special handling of window position.
3721  *
3722  * Status
3723  *    @implemented
3724  */
3725 BOOL APIENTRY
3726 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
3727 {
3728    PWINSTATION_OBJECT WinStaObject;
3729    PWND WndShell, WndListView;
3730    DECLARE_RETURN(BOOL);
3731    USER_REFERENCE_ENTRY Ref;
3732    NTSTATUS Status;
3733    PTHREADINFO ti;
3734 
3735    TRACE("Enter NtUserSetShellWindowEx\n");
3736    UserEnterExclusive();
3737 
3738    if (!(WndShell = UserGetWindowObject(hwndShell)))
3739    {
3740       RETURN(FALSE);
3741    }
3742 
3743    if (!(WndListView = UserGetWindowObject(hwndListView)))
3744    {
3745       RETURN(FALSE);
3746    }
3747 
3748    Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3749                      UserMode,
3750                      0,
3751                      &WinStaObject,
3752                      0);
3753 
3754    if (!NT_SUCCESS(Status))
3755    {
3756       SetLastNtError(Status);
3757       RETURN( FALSE);
3758    }
3759 
3760    /*
3761     * Test if we are permitted to change the shell window.
3762     */
3763    if (WinStaObject->ShellWindow)
3764    {
3765       ObDereferenceObject(WinStaObject);
3766       RETURN( FALSE);
3767    }
3768 
3769    /*
3770     * Move shell window into background.
3771     */
3772    if (hwndListView && hwndListView != hwndShell)
3773    {
3774       /*
3775        * Disabled for now to get Explorer working.
3776        * -- Filip, 01/nov/2003
3777        */
3778 #if 0
3779       co_WinPosSetWindowPos(WndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3780 #endif
3781 
3782       if (WndListView->ExStyle & WS_EX_TOPMOST)
3783       {
3784          ObDereferenceObject(WinStaObject);
3785          RETURN( FALSE);
3786       }
3787    }
3788 
3789    if (WndShell->ExStyle & WS_EX_TOPMOST)
3790    {
3791       ObDereferenceObject(WinStaObject);
3792       RETURN( FALSE);
3793    }
3794 
3795    UserRefObjectCo(WndShell, &Ref);
3796    WndShell->state2 |= WNDS2_BOTTOMMOST;
3797    co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3798 
3799    WinStaObject->ShellWindow = hwndShell;
3800    WinStaObject->ShellListView = hwndListView;
3801 
3802    ti = GetW32ThreadInfo();
3803    if (ti->pDeskInfo)
3804    {
3805        ti->pDeskInfo->hShellWindow = hwndShell;
3806        ti->pDeskInfo->spwndShell = WndShell;
3807        ti->pDeskInfo->spwndBkGnd = WndListView;
3808        ti->pDeskInfo->ppiShellProcess = ti->ppi;
3809    }
3810 
3811    UserRegisterHotKey(WndShell, SC_TASKLIST, MOD_CONTROL, VK_ESCAPE);
3812 
3813    UserDerefObjectCo(WndShell);
3814 
3815    ObDereferenceObject(WinStaObject);
3816    RETURN( TRUE);
3817 
3818 CLEANUP:
3819    TRACE("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_);
3820    UserLeave();
3821    END_CLEANUP;
3822 }
3823 
3824 // Fixes wine Win test_window_styles and todo tests...
3825 static BOOL FASTCALL
3826 IntCheckFrameEdge(ULONG Style, ULONG ExStyle)
3827 {
3828    if (ExStyle & WS_EX_DLGMODALFRAME)
3829       return TRUE;
3830    else if (!(ExStyle & WS_EX_STATICEDGE) && (Style & (WS_DLGFRAME | WS_THICKFRAME)))
3831       return TRUE;
3832    else
3833       return FALSE;
3834 }
3835 
3836 static LONG_PTR
3837 co_IntSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi, ULONG Size, BOOL bAlter)
3838 {
3839    PWND Window, Parent;
3840    PWINSTATION_OBJECT WindowStation;
3841    LONG_PTR OldValue;
3842    STYLESTRUCT Style;
3843 
3844    if (!(Window = UserGetWindowObject(hWnd)))
3845    {
3846       return( 0);
3847    }
3848 
3849    if ((INT)Index >= 0)
3850    {
3851       if ((Index + Size) > Window->cbwndExtra)
3852       {
3853          EngSetLastError(ERROR_INVALID_INDEX);
3854          return( 0);
3855       }
3856 
3857 #ifdef _WIN64
3858       if (Size == sizeof(LONG))
3859       {
3860          OldValue = *((LONG *)((PCHAR)(Window + 1) + Index));
3861          *((LONG*)((PCHAR)(Window + 1) + Index)) = (LONG)NewValue;
3862       }
3863       else
3864 #endif
3865       {
3866          OldValue = *((LONG_PTR *)((PCHAR)(Window + 1) + Index));
3867          /*
3868          if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW)
3869          {
3870             OldValue = (LONG_PTR)IntSetWindowProc( Wnd, (WNDPROC)NewValue, Ansi);
3871             if (!OldValue) return 0;
3872          }
3873          */
3874          *((LONG_PTR*)((PCHAR)(Window + 1) + Index)) = NewValue;
3875       }
3876 
3877    }
3878    else
3879    {
3880 #ifdef _WIN64
3881       if (Size == sizeof(LONG))
3882       {
3883          if ((Index != GWL_STYLE) &&
3884              (Index != GWL_EXSTYLE) &&
3885              (Index != GWL_ID) &&
3886              (Index != GWL_USERDATA))
3887          {
3888             ERR("NtUserSetWindowLong(): Index requires pointer size: %lu\n", Index);
3889             EngSetLastError(ERROR_INVALID_INDEX);
3890             return 0;
3891          }
3892       }
3893 #endif
3894 
3895       switch (Index)
3896       {
3897          case GWL_EXSTYLE: // LONG
3898             OldValue = (LONG) Window->ExStyle;
3899             Style.styleOld = OldValue;
3900             Style.styleNew = NewValue;
3901 
3902             co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
3903 
3904             /*
3905              * Remove extended window style bit WS_EX_TOPMOST for shell windows.
3906              */
3907             WindowStation = Window->head.pti->rpdesk->rpwinstaParent;
3908             if(WindowStation)
3909             {
3910                if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
3911                   Style.styleNew &= ~WS_EX_TOPMOST;
3912             }
3913             /* WS_EX_WINDOWEDGE depends on some other styles */
3914             if (IntCheckFrameEdge(Window->style, NewValue))
3915                Style.styleNew |= WS_EX_WINDOWEDGE;
3916             else
3917                Style.styleNew &= ~WS_EX_WINDOWEDGE;
3918 
3919             if (!(Window->ExStyle & WS_EX_LAYERED))
3920             {
3921                SetLayeredStatus(Window, 0);
3922             }
3923 
3924             Window->ExStyle = (DWORD)Style.styleNew;
3925 
3926             co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
3927             break;
3928 
3929          case GWL_STYLE: // LONG
3930             OldValue = (LONG) Window->style;
3931             Style.styleOld = OldValue;
3932             Style.styleNew = NewValue;
3933 
3934             if (!bAlter)
3935                 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
3936 
3937             /* WS_CLIPSIBLINGS can't be reset on top-level windows */
3938             if (UserIsDesktopWindow(Window->spwndParent)) Style.styleNew |= WS_CLIPSIBLINGS;
3939             /* WS_MINIMIZE can't be reset */
3940             if (OldValue & WS_MINIMIZE) Style.styleNew |= WS_MINIMIZE;
3941             /* Fixes wine FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change WS_EX_WINDOWEDGE too */
3942             if (IntCheckFrameEdge(NewValue, Window->ExStyle))
3943                Window->ExStyle |= WS_EX_WINDOWEDGE;
3944             else
3945                Window->ExStyle &= ~WS_EX_WINDOWEDGE;
3946 
3947             if ((OldValue & (WS_CHILD | WS_POPUP)) == WS_CHILD)
3948             {
3949                if ((NewValue & (WS_CHILD | WS_POPUP)) != WS_CHILD)
3950                {
3951                   //// From child to non-child it should be null already.
3952                   ERR("IDMenu going null! %d\n",Window->IDMenu);
3953                   Window->IDMenu = 0; // Window->spmenu = 0;
3954                }
3955             }
3956             else
3957             {
3958                if ((NewValue & (WS_CHILD | WS_POPUP)) == WS_CHILD)
3959                {
3960                   PMENU pMenu = UserGetMenuObject(UlongToHandle(Window->IDMenu));
3961                   Window->state &= ~WNDS_HASMENU;
3962                   if (pMenu)
3963                   {
3964                      ERR("IDMenu released 0x%p\n",pMenu);
3965                      // ROS may not hold a lock after setting menu to window. But it should!
3966                      //IntReleaseMenuObject(pMenu);
3967                   }
3968                }
3969             }
3970 
3971             if ((Style.styleOld ^ Style.styleNew) & WS_VISIBLE)
3972             {
3973                if (Style.styleOld & WS_VISIBLE) Window->head.pti->cVisWindows--;
3974                if (Style.styleNew & WS_VISIBLE) Window->head.pti->cVisWindows++;
3975                DceResetActiveDCEs( Window );
3976             }
3977             Window->style = (DWORD)Style.styleNew;
3978 
3979             if (!bAlter)
3980                 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
3981             break;
3982 
3983          case GWLP_WNDPROC: // LONG_PTR
3984          {
3985             if ( Window->head.pti->ppi != PsGetCurrentProcessWin32Process() ||
3986                  Window->fnid & FNID_FREED)
3987             {
3988                EngSetLastError(ERROR_ACCESS_DENIED);
3989                return( 0);
3990             }
3991             OldValue = (LONG_PTR)IntSetWindowProc(Window,
3992                                                   (WNDPROC)NewValue,
3993                                                   Ansi);
3994             break;
3995          }
3996 
3997          case GWLP_HINSTANCE: // LONG_PTR
3998             OldValue = (LONG_PTR) Window->hModule;
3999             Window->hModule = (HINSTANCE) NewValue;
4000             break;
4001 
4002          case GWLP_HWNDPARENT: // LONG_PTR
4003             Parent = Window->spwndParent;
4004             if (Parent && (Parent->head.h == IntGetDesktopWindow()))
4005                OldValue = (LONG_PTR) IntSetOwner(Window->head.h, (HWND) NewValue);
4006             else
4007                OldValue = (LONG_PTR) co_UserSetParent(Window->head.h, (HWND) NewValue);
4008             break;
4009 
4010          case GWLP_ID: // LONG
4011             OldValue = (LONG) Window->IDMenu;
4012             Window->IDMenu = (UINT) NewValue;
4013             break;
4014 
4015          case GWLP_USERDATA: // LONG or LONG_PTR
4016             OldValue = Window->dwUserData;
4017             Window->dwUserData = NewValue;
4018             break;
4019 
4020          default:
4021             ERR("NtUserSetWindowLong(): Unsupported index %lu\n", Index);
4022             EngSetLastError(ERROR_INVALID_INDEX);
4023             OldValue = 0;
4024             break;
4025       }
4026    }
4027 
4028    return( OldValue);
4029 }
4030 
4031 LONG FASTCALL
4032 co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
4033 {
4034     return (LONG)co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG), FALSE);
4035 }
4036 
4037 LONG_PTR FASTCALL
4038 co_UserSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi)
4039 {
4040     return co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG_PTR), FALSE);
4041 }
4042 
4043 /*
4044  * NtUserSetWindowLong
4045  *
4046  * The NtUserSetWindowLong function changes an attribute of the specified
4047  * window. The function also sets the 32-bit (long) value at the specified
4048  * offset into the extra window memory.
4049  *
4050  * Status
4051  *    @implemented
4052  */
4053 
4054 LONG APIENTRY
4055 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
4056 {
4057    LONG ret;
4058 
4059    UserEnterExclusive();
4060 
4061    if (hWnd == IntGetDesktopWindow())
4062    {
4063       EngSetLastError(STATUS_ACCESS_DENIED);
4064       UserLeave();
4065       return 0;
4066    }
4067 
4068    ret = (LONG)co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG), FALSE);
4069 
4070    UserLeave();
4071 
4072    return ret;
4073 }
4074 
4075 #ifdef _WIN64
4076 LONG_PTR APIENTRY
4077 NtUserSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi)
4078 {
4079     LONG_PTR ret;
4080 
4081     UserEnterExclusive();
4082 
4083     if (hWnd == IntGetDesktopWindow())
4084     {
4085         EngSetLastError(STATUS_ACCESS_DENIED);
4086         UserLeave();
4087         return 0;
4088     }
4089 
4090     ret = co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG_PTR), FALSE);
4091 
4092     UserLeave();
4093 
4094     return ret;
4095 }
4096 #endif // _WIN64
4097 
4098 DWORD APIENTRY
4099 NtUserAlterWindowStyle(HWND hWnd, DWORD Index, LONG NewValue)
4100 {
4101    LONG ret;
4102 
4103    UserEnterExclusive();
4104 
4105    if (hWnd == IntGetDesktopWindow())
4106    {
4107       EngSetLastError(STATUS_ACCESS_DENIED);
4108       UserLeave();
4109       return 0;
4110    }
4111 
4112    ret = co_IntSetWindowLongPtr(hWnd, Index, NewValue, FALSE, sizeof(LONG), TRUE);
4113 
4114    UserLeave();
4115 
4116    return ret;
4117 }
4118 
4119 
4120 /*
4121  * NtUserSetWindowWord
4122  *
4123  * Legacy function similar to NtUserSetWindowLong.
4124  *
4125  * Status
4126  *    @implemented
4127  */
4128 
4129 WORD APIENTRY
4130 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue)
4131 {
4132    PWND Window;
4133    WORD OldValue;
4134    DECLARE_RETURN(WORD);
4135 
4136    TRACE("Enter NtUserSetWindowWord\n");
4137    UserEnterExclusive();
4138 
4139    if (hWnd == IntGetDesktopWindow())
4140    {
4141       EngSetLastError(STATUS_ACCESS_DENIED);
4142       RETURN( 0);
4143    }
4144 
4145    if (!(Window = UserGetWindowObject(hWnd)))
4146    {
4147       RETURN( 0);
4148    }
4149 
4150    switch (Index)
4151    {
4152       case GWL_ID:
4153       case GWL_HINSTANCE:
4154       case GWL_HWNDPARENT:
4155          RETURN( (WORD)co_UserSetWindowLong(UserHMGetHandle(Window), Index, (UINT)NewValue, TRUE));
4156       default:
4157          if (Index < 0)
4158          {
4159             EngSetLastError(ERROR_INVALID_INDEX);
4160             RETURN( 0);
4161          }
4162    }
4163 
4164    if ((ULONG)Index > (Window->cbwndExtra - sizeof(WORD)))
4165    {
4166       EngSetLastError(ERROR_INVALID_INDEX);
4167       RETURN( 0);
4168    }
4169 
4170    OldValue = *((WORD *)((PCHAR)(Window + 1) + Index));
4171    *((WORD *)((PCHAR)(Window + 1) + Index)) = NewValue;
4172 
4173    RETURN( OldValue);
4174 
4175 CLEANUP:
4176    TRACE("Leave NtUserSetWindowWord, ret=%u\n", _ret_);
4177    UserLeave();
4178    END_CLEANUP;
4179 }
4180 
4181 /*
4182  QueryWindow based on KJK::Hyperion and James Tabor.
4183 
4184  0 = QWUniqueProcessId
4185  1 = QWUniqueThreadId
4186  2 = QWActiveWindow
4187  3 = QWFocusWindow
4188  4 = QWIsHung            Implements IsHungAppWindow found
4189                                 by KJK::Hyperion.
4190 
4191  9 = QWKillWindow        When I called this with hWnd ==
4192                            DesktopWindow, it shutdown the system
4193                            and rebooted.
4194 */
4195 /*
4196  * @implemented
4197  */
4198 DWORD_PTR APIENTRY
4199 NtUserQueryWindow(HWND hWnd, DWORD Index)
4200 {
4201 /* Console Leader Process CID Window offsets */
4202 #define GWLP_CONSOLE_LEADER_PID 0
4203 #define GWLP_CONSOLE_LEADER_TID 4
4204 
4205    DWORD_PTR Result;
4206    PWND pWnd, pwndActive;
4207    PTHREADINFO pti, ptiActive;
4208    DECLARE_RETURN(UINT);
4209 
4210    TRACE("Enter NtUserQueryWindow\n");
4211    UserEnterShared();
4212 
4213    if (!(pWnd = UserGetWindowObject(hWnd)))
4214    {
4215       RETURN( 0);
4216    }
4217 
4218    switch(Index)
4219    {
4220       case QUERY_WINDOW_UNIQUE_PROCESS_ID:
4221       {
4222          if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
4223               (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) )
4224          {
4225             // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_PID)
4226             Result = (DWORD_PTR)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_PID)));
4227          }
4228          else
4229          {
4230             Result = (DWORD_PTR)IntGetWndProcessId(pWnd);
4231          }
4232          break;
4233       }
4234 
4235       case QUERY_WINDOW_UNIQUE_THREAD_ID:
4236       {
4237          if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
4238               (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) )
4239          {
4240             // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_TID)
4241             Result = (DWORD_PTR)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_TID)));
4242          }
4243          else
4244          {
4245             Result = (DWORD_PTR)IntGetWndThreadId(pWnd);
4246          }
4247          break;
4248       }
4249 
4250       case QUERY_WINDOW_ACTIVE:
4251          Result = (DWORD_PTR)(pWnd->head.pti->MessageQueue->spwndActive ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndActive) : 0);
4252          break;
4253 
4254       case QUERY_WINDOW_FOCUS:
4255          Result = (DWORD_PTR)(pWnd->head.pti->MessageQueue->spwndFocus ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndFocus) : 0);
4256          break;
4257 
4258       case QUERY_WINDOW_ISHUNG:
4259          Result = (pWnd->fnid == FNID_GHOST) || MsqIsHung(pWnd->head.pti, MSQ_HUNG);
4260          break;
4261 
4262       case QUERY_WINDOW_REAL_ID:
4263          Result = (DWORD_PTR)pWnd->head.pti->pEThread->Cid.UniqueProcess;
4264          break;
4265 
4266       case QUERY_WINDOW_FOREGROUND:
4267          Result = (pWnd->head.pti->MessageQueue == gpqForeground);
4268          break;
4269 
4270       case QUERY_WINDOW_DEFAULT_IME: /* default IME window */
4271          if (pWnd->head.pti->spwndDefaultIme)
4272             Result = (DWORD_PTR)UserHMGetHandle(pWnd->head.pti->spwndDefaultIme);
4273          else
4274             Result = 0;
4275          break;
4276 
4277       case QUERY_WINDOW_DEFAULT_ICONTEXT: /* default input context handle */
4278          if (pWnd->head.pti->spDefaultImc)
4279             Result = (DWORD_PTR)UserHMGetHandle(pWnd->head.pti->spDefaultImc);
4280          else
4281             Result = 0;
4282          break;
4283 
4284       case QUERY_WINDOW_ACTIVE_IME:
4285          Result = 0;
4286          if (gpqForeground && gpqForeground->spwndActive)
4287          {
4288              pwndActive = gpqForeground->spwndActive;
4289              pti = PsGetCurrentThreadWin32Thread();
4290              if (pti->rpdesk == pwndActive->head.rpdesk)
4291              {
4292                 ptiActive = pwndActive->head.pti;
4293                 if (ptiActive->spwndDefaultIme)
4294                    Result = (DWORD_PTR)UserHMGetHandle(ptiActive->spwndDefaultIme);
4295              }
4296          }
4297          break;
4298 
4299       default:
4300          Result = 0;
4301          break;
4302    }
4303 
4304    RETURN( Result);
4305 
4306 CLEANUP:
4307    TRACE("Leave NtUserQueryWindow, ret=%u\n", _ret_);
4308    UserLeave();
4309    END_CLEANUP;
4310 }
4311 
4312 /*
4313  * @implemented
4314  */
4315 UINT APIENTRY
4316 NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe)
4317 {
4318    UNICODE_STRING SafeMessageName;
4319    NTSTATUS Status;
4320    UINT Ret;
4321    DECLARE_RETURN(UINT);
4322 
4323    TRACE("Enter NtUserRegisterWindowMessage\n");
4324    UserEnterExclusive();
4325 
4326    if(MessageNameUnsafe == NULL)
4327    {
4328       EngSetLastError(ERROR_INVALID_PARAMETER);
4329       RETURN( 0);
4330    }
4331 
4332    Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe);
4333    if(!NT_SUCCESS(Status))
4334    {
4335       SetLastNtError(Status);
4336       RETURN( 0);
4337    }
4338 
4339    Ret = (UINT)IntAddAtom(SafeMessageName.Buffer);
4340    if (SafeMessageName.Buffer)
4341       ExFreePoolWithTag(SafeMessageName.Buffer, TAG_STRING);
4342    RETURN( Ret);
4343 
4344 CLEANUP:
4345    TRACE("Leave NtUserRegisterWindowMessage, ret=%u\n", _ret_);
4346    UserLeave();
4347    END_CLEANUP;
4348 }
4349 
4350 /*
4351  * @implemented
4352  */
4353 BOOL APIENTRY
4354 NtUserSetWindowFNID(HWND hWnd,
4355                     WORD fnID)
4356 {
4357    PWND Wnd;
4358    DECLARE_RETURN(BOOL);
4359 
4360    TRACE("Enter NtUserSetWindowFNID\n");
4361    UserEnterExclusive();
4362 
4363    if (!(Wnd = UserGetWindowObject(hWnd)))
4364    {
4365       RETURN( FALSE);
4366    }
4367 
4368    if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
4369    {
4370       EngSetLastError(ERROR_ACCESS_DENIED);
4371       RETURN( FALSE);
4372    }
4373 
4374    // From user land we only set these.
4375    if (fnID != FNID_DESTROY)
4376    {
4377       /* HACK: The minimum should be FNID_BUTTON, but menu code relies on this */
4378       if (fnID < FNID_FIRST || fnID > FNID_GHOST ||
4379           Wnd->fnid != 0)
4380       {
4381          EngSetLastError(ERROR_INVALID_PARAMETER);
4382          RETURN( FALSE);
4383       }
4384    }
4385 
4386    Wnd->fnid |= fnID;
4387    RETURN( TRUE);
4388 
4389 CLEANUP:
4390    TRACE("Leave NtUserSetWindowFNID\n");
4391    UserLeave();
4392    END_CLEANUP;
4393 }
4394 
4395 BOOL APIENTRY
4396 DefSetText(PWND Wnd, PCWSTR WindowText)
4397 {
4398    UNICODE_STRING UnicodeString;
4399    BOOL Ret = FALSE;
4400 
4401    RtlInitUnicodeString(&UnicodeString, WindowText);
4402 
4403    if (UnicodeString.Length != 0)
4404    {
4405       if (Wnd->strName.MaximumLength > 0 &&
4406           UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
4407       {
4408          ASSERT(Wnd->strName.Buffer != NULL);
4409 
4410          Wnd->strName.Length = UnicodeString.Length;
4411          Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4412          RtlCopyMemory(Wnd->strName.Buffer,
4413                               UnicodeString.Buffer,
4414                               UnicodeString.Length);
4415       }
4416       else
4417       {
4418          PWCHAR buf;
4419          Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4420          buf = Wnd->strName.Buffer;
4421          Wnd->strName.Buffer = NULL;
4422          if (buf != NULL)
4423          {
4424             DesktopHeapFree(Wnd->head.rpdesk, buf);
4425          }
4426 
4427          Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
4428                                                    UnicodeString.Length + sizeof(UNICODE_NULL));
4429          if (Wnd->strName.Buffer != NULL)
4430          {
4431             Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4432             RtlCopyMemory(Wnd->strName.Buffer,
4433                                  UnicodeString.Buffer,
4434                                  UnicodeString.Length);
4435             Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4436             Wnd->strName.Length = UnicodeString.Length;
4437          }
4438          else
4439          {
4440             EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4441             goto Exit;
4442          }
4443       }
4444    }
4445    else
4446    {
4447       Wnd->strName.Length = 0;
4448       if (Wnd->strName.Buffer != NULL)
4449           Wnd->strName.Buffer[0] = L'\0';
4450    }
4451 
4452    // FIXME: HAX! Windows does not do this in here!
4453    // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4454    // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4455    /* Send shell notifications */
4456    if (!Wnd->spwndOwner && !IntGetParent(Wnd))
4457    {
4458       co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) UserHMGetHandle(Wnd), FALSE); // FIXME Flashing?
4459    }
4460 
4461    Ret = TRUE;
4462 Exit:
4463    if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
4464    return Ret;
4465 }
4466 
4467 /*
4468  * NtUserDefSetText
4469  *
4470  * Undocumented function that is called from DefWindowProc to set
4471  * window text.
4472  *
4473  * Status
4474  *    @implemented
4475  */
4476 BOOL APIENTRY
4477 NtUserDefSetText(HWND hWnd, PLARGE_STRING WindowText)
4478 {
4479    PWND Wnd;
4480    LARGE_STRING SafeText;
4481    UNICODE_STRING UnicodeString;
4482    BOOL Ret = TRUE;
4483 
4484    TRACE("Enter NtUserDefSetText\n");
4485 
4486    if (WindowText != NULL)
4487    {
4488       _SEH2_TRY
4489       {
4490          SafeText = ProbeForReadLargeString(WindowText);
4491       }
4492       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4493       {
4494          Ret = FALSE;
4495          SetLastNtError(_SEH2_GetExceptionCode());
4496       }
4497       _SEH2_END;
4498 
4499       if (!Ret)
4500          return FALSE;
4501    }
4502    else
4503       return TRUE;
4504 
4505    UserEnterExclusive();
4506 
4507    if(!(Wnd = UserGetWindowObject(hWnd)))
4508    {
4509       UserLeave();
4510       return FALSE;
4511    }
4512 
4513    // ReactOS uses Unicode and not mixed. Up/Down converting will take time.
4514    // Brought to you by: The Wine Project! Dysfunctional Thought Processes!
4515    // Now we know what the bAnsi is for.
4516    RtlInitUnicodeString(&UnicodeString, NULL);
4517    if (SafeText.Buffer)
4518    {
4519       _SEH2_TRY
4520       {
4521          if (SafeText.bAnsi)
4522             ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(CHAR));
4523          else
4524             ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(WCHAR));
4525          Ret = RtlLargeStringToUnicodeString(&UnicodeString, &SafeText);
4526       }
4527       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4528       {
4529          Ret = FALSE;
4530          SetLastNtError(_SEH2_GetExceptionCode());
4531       }
4532       _SEH2_END;
4533       if (!Ret) goto Exit;
4534    }
4535 
4536    if (UnicodeString.Length != 0)
4537    {
4538       if (Wnd->strName.MaximumLength > 0 &&
4539           UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
4540       {
4541          ASSERT(Wnd->strName.Buffer != NULL);
4542 
4543          Wnd->strName.Length = UnicodeString.Length;
4544          Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4545          RtlCopyMemory(Wnd->strName.Buffer,
4546                               UnicodeString.Buffer,
4547                               UnicodeString.Length);
4548       }
4549       else
4550       {
4551          PWCHAR buf;
4552          Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4553          buf = Wnd->strName.Buffer;
4554          Wnd->strName.Buffer = NULL;
4555          if (buf != NULL)
4556          {
4557             DesktopHeapFree(Wnd->head.rpdesk, buf);
4558          }
4559 
4560          Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
4561                                                    UnicodeString.Length + sizeof(UNICODE_NULL));
4562          if (Wnd->strName.Buffer != NULL)
4563          {
4564             Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4565             RtlCopyMemory(Wnd->strName.Buffer,
4566                                  UnicodeString.Buffer,
4567                                  UnicodeString.Length);
4568             Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4569             Wnd->strName.Length = UnicodeString.Length;
4570          }
4571          else
4572          {
4573             EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4574             Ret = FALSE;
4575             goto Exit;
4576          }
4577       }
4578    }
4579    else
4580    {
4581       Wnd->strName.Length = 0;
4582       if (Wnd->strName.Buffer != NULL)
4583           Wnd->strName.Buffer[0] = L'\0';
4584    }
4585 
4586    // FIXME: HAX! Windows does not do this in here!
4587    // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4588    // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4589    /* Send shell notifications */
4590    if (!Wnd->spwndOwner && !IntGetParent(Wnd))
4591    {
4592       co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) hWnd, FALSE); // FIXME Flashing?
4593    }
4594 
4595    Ret = TRUE;
4596 Exit:
4597    if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
4598    TRACE("Leave NtUserDefSetText, ret=%i\n", Ret);
4599    UserLeave();
4600    return Ret;
4601 }
4602 
4603 /*
4604  * NtUserInternalGetWindowText
4605  *
4606  * Status
4607  *    @implemented
4608  */
4609 
4610 INT APIENTRY
4611 NtUserInternalGetWindowText(HWND hWnd, LPWSTR lpString, INT nMaxCount)
4612 {
4613    PWND Wnd;
4614    NTSTATUS Status;
4615    INT Result;
4616    DECLARE_RETURN(INT);
4617 
4618    TRACE("Enter NtUserInternalGetWindowText\n");
4619    UserEnterShared();
4620 
4621    if(lpString && (nMaxCount <= 1))
4622    {
4623       EngSetLastError(ERROR_INVALID_PARAMETER);
4624       RETURN( 0);
4625    }
4626 
4627    if(!(Wnd = UserGetWindowObject(hWnd)))
4628    {
4629       RETURN( 0);
4630    }
4631 
4632    Result = Wnd->strName.Length / sizeof(WCHAR);
4633    if(lpString)
4634    {
4635       const WCHAR Terminator = L'\0';
4636       INT Copy;
4637       WCHAR *Buffer = (WCHAR*)lpString;
4638 
4639       Copy = min(nMaxCount - 1, Result);
4640       if(Copy > 0)
4641       {
4642          Status = MmCopyToCaller(Buffer, Wnd->strName.Buffer, Copy * sizeof(WCHAR));
4643          if(!NT_SUCCESS(Status))
4644          {
4645             SetLastNtError(Status);
4646             RETURN( 0);
4647          }
4648          Buffer += Copy;
4649       }
4650 
4651       Status = MmCopyToCaller(Buffer, &Terminator, sizeof(WCHAR));
4652       if(!NT_SUCCESS(Status))
4653       {
4654          SetLastNtError(Status);
4655          RETURN( 0);
4656       }
4657 
4658       Result = Copy;
4659    }
4660 
4661    RETURN( Result);
4662 
4663 CLEANUP:
4664    TRACE("Leave NtUserInternalGetWindowText, ret=%i\n",_ret_);
4665    UserLeave();
4666    END_CLEANUP;
4667 }
4668 
4669 /*
4670   API Call
4671 */
4672 BOOL
4673 FASTCALL
4674 IntShowOwnedPopups(PWND OwnerWnd, BOOL fShow )
4675 {
4676    int count = 0;
4677    PWND pWnd;
4678    HWND *win_array;
4679 
4680 //   ASSERT(OwnerWnd);
4681 
4682    TRACE("Enter ShowOwnedPopups Show: %s\n", (fShow ? "TRUE" : "FALSE"));
4683 
4684    /* NOTE: Popups are not children */
4685    win_array = IntWinListOwnedPopups(OwnerWnd);
4686 
4687    if (!win_array)
4688       return TRUE;
4689 
4690    while (win_array[count])
4691       count++;
4692    while (--count >= 0)
4693    {
4694       if (!(pWnd = ValidateHwndNoErr( win_array[count] )))
4695          continue;
4696       ASSERT(pWnd->spwndOwner == OwnerWnd);
4697 
4698       if (fShow)
4699       {
4700          if (pWnd->state & WNDS_HIDDENPOPUP)
4701          {
4702             /* In Windows, ShowOwnedPopups(TRUE) generates
4703              * WM_SHOWWINDOW messages with SW_PARENTOPENING,
4704              * regardless of the state of the owner
4705              */
4706             co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
4707             pWnd->state &= ~WNDS_HIDDENPOPUP;
4708             continue;
4709          }
4710       }
4711       else
4712       {
4713          if (pWnd->style & WS_VISIBLE)
4714          {
4715             /* In Windows, ShowOwnedPopups(FALSE) generates
4716              * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
4717              * regardless of the state of the owner
4718              */
4719             co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
4720             pWnd->state |= WNDS_HIDDENPOPUP;
4721             continue;
4722          }
4723       }
4724    }
4725    ExFreePoolWithTag(win_array, USERTAG_WINDOWLIST);
4726    TRACE("Leave ShowOwnedPopups\n");
4727    return TRUE;
4728 }
4729 
4730 /* EOF */
4731