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