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