xref: /reactos/win32ss/user/ntuser/window.c (revision 5e2fe089)
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 {
1620    PWND pWnd = NULL;
1621    HWND hWnd;
1622    PTHREADINFO pti = NULL;
1623    BOOL MenuChanged;
1624    BOOL bUnicodeWindow;
1625 
1626    pti = pdeskCreated ? gptiDesktopThread : GetW32ThreadInfo();
1627 
1628    if (!(Cs->dwExStyle & WS_EX_LAYOUTRTL))
1629    {      // Need both here for wine win.c test_CreateWindow.
1630       //if (Cs->hwndParent && ParentWindow)
1631       if (ParentWindow) // It breaks more tests..... WIP.
1632       {
1633          if ( (Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD &&
1634               ParentWindow->ExStyle & WS_EX_LAYOUTRTL &&
1635              !(ParentWindow->ExStyle & WS_EX_NOINHERITLAYOUT) )
1636             Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1637       }
1638       else
1639       { /*
1640          * Note from MSDN <http://msdn.microsoft.com/en-us/library/aa913269.aspx>:
1641          *
1642          * Dialog boxes and message boxes do not inherit layout, so you must
1643          * set the layout explicitly.
1644          */
1645          if ( Class->fnid != FNID_DIALOG )
1646          {
1647             if (pti->ppi->dwLayout & LAYOUT_RTL)
1648             {
1649                Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1650             }
1651          }
1652       }
1653    }
1654 
1655    /* Automatically add WS_EX_WINDOWEDGE */
1656    if ((Cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1657          ((!(Cs->dwExStyle & WS_EX_STATICEDGE)) &&
1658          (Cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1659       Cs->dwExStyle |= WS_EX_WINDOWEDGE;
1660    else
1661       Cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1662 
1663    /* Is it a unicode window? */
1664    bUnicodeWindow =!(Cs->dwExStyle & WS_EX_SETANSICREATOR);
1665    Cs->dwExStyle &= ~WS_EX_SETANSICREATOR;
1666 
1667    /* Allocate the new window */
1668    pWnd = (PWND) UserCreateObject( gHandleTable,
1669                                    pdeskCreated ? pdeskCreated : pti->rpdesk,
1670                                    pti,
1671                                   (PHANDLE)&hWnd,
1672                                    TYPE_WINDOW,
1673                                    sizeof(WND) + Class->cbwndExtra);
1674 
1675    if (!pWnd)
1676    {
1677       goto AllocError;
1678    }
1679 
1680    TRACE("Created window object with handle %p\n", hWnd);
1681 
1682    if (pdeskCreated && pdeskCreated->DesktopWindow == NULL )
1683    {  /* HACK: Helper for win32csr/desktopbg.c */
1684       /* If there is no desktop window yet, we must be creating it */
1685       TRACE("CreateWindow setting desktop.\n");
1686       pdeskCreated->DesktopWindow = hWnd;
1687       pdeskCreated->pDeskInfo->spwnd = pWnd;
1688    }
1689 
1690    /*
1691     * Fill out the structure describing it.
1692     */
1693    /* Remember, pWnd->head is setup in object.c ... */
1694    pWnd->spwndParent = ParentWindow;
1695    pWnd->spwndOwner = OwnerWindow;
1696    pWnd->fnid = 0;
1697    pWnd->spwndLastActive = pWnd;
1698    pWnd->state2 |= WNDS2_WIN40COMPAT; // FIXME!!!
1699    pWnd->pcls = Class;
1700    pWnd->hModule = Cs->hInstance;
1701    pWnd->style = Cs->style & ~WS_VISIBLE;
1702    pWnd->ExStyle = Cs->dwExStyle;
1703    pWnd->cbwndExtra = pWnd->pcls->cbwndExtra;
1704    pWnd->pActCtx = acbiBuffer;
1705    pWnd->InternalPos.MaxPos.x  = pWnd->InternalPos.MaxPos.y  = -1;
1706    pWnd->InternalPos.IconPos.x = pWnd->InternalPos.IconPos.y = -1;
1707 
1708    if (pWnd->spwndParent != NULL && Cs->hwndParent != 0)
1709    {
1710        pWnd->HideFocus = pWnd->spwndParent->HideFocus;
1711        pWnd->HideAccel = pWnd->spwndParent->HideAccel;
1712    }
1713 
1714    pWnd->head.pti->cWindows++;
1715 
1716    if (Class->spicn && !Class->spicnSm)
1717    {
1718        HICON IconSmHandle = NULL;
1719        if((Class->spicn->CURSORF_flags & (CURSORF_LRSHARED | CURSORF_FROMRESOURCE))
1720                == (CURSORF_LRSHARED | CURSORF_FROMRESOURCE))
1721        {
1722            IconSmHandle = co_IntCopyImage(
1723                UserHMGetHandle(Class->spicn),
1724                IMAGE_ICON,
1725                UserGetSystemMetrics( SM_CXSMICON ),
1726                UserGetSystemMetrics( SM_CYSMICON ),
1727                LR_COPYFROMRESOURCE);
1728        }
1729        if (!IconSmHandle)
1730        {
1731            /* Retry without copying from resource */
1732            IconSmHandle = co_IntCopyImage(
1733                UserHMGetHandle(Class->spicn),
1734                IMAGE_ICON,
1735                UserGetSystemMetrics( SM_CXSMICON ),
1736                UserGetSystemMetrics( SM_CYSMICON ),
1737                0);
1738        }
1739 
1740        if (IconSmHandle)
1741        {
1742            Class->spicnSm = UserGetCurIconObject(IconSmHandle);
1743            Class->CSF_flags |= CSF_CACHEDSMICON;
1744        }
1745    }
1746 
1747    if (pWnd->pcls->CSF_flags & CSF_SERVERSIDEPROC)
1748       pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
1749 
1750  /* BugBoy Comments: Comment below say that System classes are always created
1751     as UNICODE. In windows, creating a window with the ANSI version of CreateWindow
1752     sets the window to ansi as verified by testing with IsUnicodeWindow API.
1753 
1754     No where can I see in code or through testing does the window change back
1755     to ANSI after being created as UNICODE in ROS. I didnt do more testing to
1756     see what problems this would cause. */
1757 
1758    // Set WndProc from Class.
1759    pWnd->lpfnWndProc  = pWnd->pcls->lpfnWndProc;
1760 
1761    // GetWindowProc, test for non server side default classes and set WndProc.
1762     if ( pWnd->pcls->fnid <= FNID_GHOST && pWnd->pcls->fnid >= FNID_BUTTON )
1763     {
1764       if (bUnicodeWindow)
1765       {
1766          if (GETPFNCLIENTA(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1767             pWnd->lpfnWndProc = GETPFNCLIENTW(pWnd->pcls->fnid);
1768       }
1769       else
1770       {
1771          if (GETPFNCLIENTW(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1772             pWnd->lpfnWndProc = GETPFNCLIENTA(pWnd->pcls->fnid);
1773       }
1774     }
1775 
1776    // If not an Unicode caller, set Ansi creator bit.
1777    if (!bUnicodeWindow) pWnd->state |= WNDS_ANSICREATOR;
1778 
1779    // Clone Class Ansi/Unicode proc type.
1780    if (pWnd->pcls->CSF_flags & CSF_ANSIPROC)
1781    {
1782       pWnd->state |= WNDS_ANSIWINDOWPROC;
1783       pWnd->Unicode = FALSE;
1784    }
1785    else
1786    { /*
1787       * It seems there can be both an Ansi creator and Unicode Class Window
1788       * WndProc, unless the following overriding conditions occur:
1789       */
1790       if ( !bUnicodeWindow &&
1791           ( Class->atomClassName == gpsi->atomSysClass[ICLS_BUTTON]    ||
1792             Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOBOX]  ||
1793             Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOLBOX] ||
1794             Class->atomClassName == gpsi->atomSysClass[ICLS_DIALOG]    ||
1795             Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT]      ||
1796             Class->atomClassName == gpsi->atomSysClass[ICLS_IME]       ||
1797             Class->atomClassName == gpsi->atomSysClass[ICLS_LISTBOX]   ||
1798             Class->atomClassName == gpsi->atomSysClass[ICLS_MDICLIENT] ||
1799             Class->atomClassName == gpsi->atomSysClass[ICLS_STATIC] ) )
1800       { // Override Class and set the window Ansi WndProc.
1801          pWnd->state |= WNDS_ANSIWINDOWPROC;
1802          pWnd->Unicode = FALSE;
1803       }
1804       else
1805       { // Set the window Unicode WndProc.
1806          pWnd->state &= ~WNDS_ANSIWINDOWPROC;
1807          pWnd->Unicode = TRUE;
1808       }
1809    }
1810 
1811    /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx,
1812       then my testing shows that windows (2k and XP) creates a CallProc for it immediately
1813       Dont understand why it does this. */
1814    if (Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT])
1815    {
1816       PCALLPROCDATA CallProc;
1817       CallProc = CreateCallProc(pWnd->head.rpdesk, pWnd->lpfnWndProc, pWnd->Unicode , pWnd->head.pti->ppi);
1818 
1819       if (!CallProc)
1820       {
1821          EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1822          ERR("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %p\n", hWnd);
1823       }
1824       else
1825       {
1826          UserAddCallProcToClass(pWnd->pcls, CallProc);
1827       }
1828    }
1829 
1830    InitializeListHead(&pWnd->PropListHead);
1831    pWnd->PropListItems = 0;
1832 
1833    if ( WindowName->Buffer != NULL && WindowName->Length > 0 )
1834    {
1835       pWnd->strName.Buffer = DesktopHeapAlloc(pWnd->head.rpdesk,
1836                                              WindowName->Length + sizeof(UNICODE_NULL));
1837       if (pWnd->strName.Buffer == NULL)
1838       {
1839           goto AllocError;
1840       }
1841 
1842       RtlCopyMemory(pWnd->strName.Buffer, WindowName->Buffer, WindowName->Length);
1843       pWnd->strName.Buffer[WindowName->Length / sizeof(WCHAR)] = L'\0';
1844       pWnd->strName.Length = WindowName->Length;
1845       pWnd->strName.MaximumLength = WindowName->Length + sizeof(UNICODE_NULL);
1846    }
1847 
1848    /* Correct the window style. */
1849    if ((pWnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1850    {
1851       pWnd->style |= WS_CLIPSIBLINGS;
1852       if (!(pWnd->style & WS_POPUP))
1853       {
1854          pWnd->style |= WS_CAPTION;
1855       }
1856    }
1857 
1858    /* WS_EX_WINDOWEDGE depends on some other styles */
1859    if (pWnd->ExStyle & WS_EX_DLGMODALFRAME)
1860        pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1861    else if (pWnd->style & (WS_DLGFRAME | WS_THICKFRAME))
1862    {
1863        if (!((pWnd->ExStyle & WS_EX_STATICEDGE) &&
1864             (pWnd->style & (WS_CHILD | WS_POPUP))))
1865            pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1866    }
1867     else
1868         pWnd->ExStyle &= ~WS_EX_WINDOWEDGE;
1869 
1870    if (!(pWnd->style & (WS_CHILD | WS_POPUP)))
1871       pWnd->state |= WNDS_SENDSIZEMOVEMSGS;
1872 
1873    /* Set the window menu */
1874    if ((Cs->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1875    {
1876       if (Cs->hMenu)
1877       {
1878          IntSetMenu(pWnd, Cs->hMenu, &MenuChanged);
1879       }
1880       else if (pWnd->pcls->lpszMenuName) // Take it from the parent.
1881       {
1882           UNICODE_STRING MenuName;
1883           HMENU hMenu;
1884 
1885           if (IS_INTRESOURCE(pWnd->pcls->lpszMenuName))
1886           {
1887              MenuName.Length = 0;
1888              MenuName.MaximumLength = 0;
1889              MenuName.Buffer = pWnd->pcls->lpszMenuName;
1890           }
1891           else
1892           {
1893              RtlInitUnicodeString( &MenuName, pWnd->pcls->lpszMenuName);
1894           }
1895           hMenu = co_IntCallLoadMenu( pWnd->pcls->hModule, &MenuName);
1896           if (hMenu) IntSetMenu(pWnd, hMenu, &MenuChanged);
1897       }
1898    }
1899    else // Not a child
1900       pWnd->IDMenu = (UINT_PTR)Cs->hMenu;
1901 
1902 
1903    if ( ParentWindow &&
1904         ParentWindow != ParentWindow->head.rpdesk->spwndMessage &&
1905         ParentWindow != ParentWindow->head.rpdesk->pDeskInfo->spwnd )
1906    {
1907        PWND Owner = IntGetNonChildAncestor(ParentWindow);
1908 
1909        if (!IntValidateOwnerDepth(pWnd, Owner))
1910        {
1911           EngSetLastError(ERROR_INVALID_PARAMETER);
1912           goto Error;
1913        }
1914        if ( pWnd->spwndOwner &&
1915             pWnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
1916        {
1917           pWnd->ExStyle |= WS_EX_TOPMOST;
1918        }
1919        if ( pWnd->spwndOwner &&
1920             Class->atomClassName != gpsi->atomSysClass[ICLS_IME] &&
1921             pti != pWnd->spwndOwner->head.pti)
1922        {
1923           //ERR("CreateWindow Owner in.\n");
1924           UserAttachThreadInput(pti, pWnd->spwndOwner->head.pti, TRUE);
1925        }
1926    }
1927 
1928    /* Insert the window into the thread's window list. */
1929    InsertTailList (&pti->WindowListHead, &pWnd->ThreadListEntry);
1930 
1931    /* Handle "CS_CLASSDC", it is tested first. */
1932    if ( (pWnd->pcls->style & CS_CLASSDC) && !(pWnd->pcls->pdce) )
1933    {  /* One DCE per class to have CLASS. */
1934       pWnd->pcls->pdce = DceAllocDCE( pWnd, DCE_CLASS_DC );
1935    }
1936    else if ( pWnd->pcls->style & CS_OWNDC)
1937    {  /* Allocate a DCE for this window. */
1938       DceAllocDCE(pWnd, DCE_WINDOW_DC);
1939    }
1940 
1941    return pWnd;
1942 
1943 AllocError:
1944    ERR("IntCreateWindow Allocation Error.\n");
1945    SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1946 Error:
1947    if(pWnd)
1948       UserDereferenceObject(pWnd);
1949    return NULL;
1950 }
1951 
1952 /*
1953  * @implemented
1954  */
1955 PWND FASTCALL
1956 co_UserCreateWindowEx(CREATESTRUCTW* Cs,
1957                      PUNICODE_STRING ClassName,
1958                      PLARGE_STRING WindowName,
1959                      PVOID acbiBuffer)
1960 {
1961    ULONG style;
1962    PWND Window = NULL, ParentWindow = NULL, OwnerWindow;
1963    HWND hWnd, hWndParent, hWndOwner, hwndInsertAfter;
1964    PWINSTATION_OBJECT WinSta;
1965    PCLS Class = NULL;
1966    SIZE Size;
1967    POINT MaxSize, MaxPos, MinTrack, MaxTrack;
1968    CBT_CREATEWNDW * pCbtCreate;
1969    LRESULT Result;
1970    USER_REFERENCE_ENTRY ParentRef, Ref;
1971    PTHREADINFO pti;
1972    DWORD dwShowMode = SW_SHOW;
1973    CREATESTRUCTW *pCsw = NULL;
1974    PVOID pszClass = NULL, pszName = NULL;
1975    PWND ret = NULL;
1976 
1977    /* Get the current window station and reference it */
1978    pti = GetW32ThreadInfo();
1979    if (pti == NULL || pti->rpdesk == NULL)
1980    {
1981       ERR("Thread is not attached to a desktop! Cannot create window!\n");
1982       return NULL; // There is nothing to cleanup.
1983    }
1984    WinSta = pti->rpdesk->rpwinstaParent;
1985    ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0);
1986 
1987    pCsw = NULL;
1988    pCbtCreate = NULL;
1989 
1990    /* Get the class and reference it */
1991    Class = IntGetAndReferenceClass(ClassName, Cs->hInstance, FALSE);
1992    if(!Class)
1993    {
1994        EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS);
1995        ERR("Failed to find class %wZ\n", ClassName);
1996        goto cleanup;
1997    }
1998 
1999    /* Now find the parent and the owner window */
2000    hWndParent = pti->rpdesk->pDeskInfo->spwnd->head.h;
2001    hWndOwner = NULL;
2002 
2003     if (Cs->hwndParent == HWND_MESSAGE)
2004     {
2005         Cs->hwndParent = hWndParent = pti->rpdesk->spwndMessage->head.h;
2006     }
2007     else if (Cs->hwndParent)
2008     {
2009         if ((Cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
2010             hWndOwner = Cs->hwndParent;
2011         else
2012             hWndParent = Cs->hwndParent;
2013     }
2014     else if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
2015     {
2016          ERR("Cannot create a child window without a parent!\n");
2017          EngSetLastError(ERROR_TLW_WITH_WSCHILD);
2018          goto cleanup;  /* WS_CHILD needs a parent, but WS_POPUP doesn't */
2019     }
2020 
2021     ParentWindow = hWndParent ? UserGetWindowObject(hWndParent): NULL;
2022     OwnerWindow = hWndOwner ? UserGetWindowObject(hWndOwner): NULL;
2023 
2024     if (hWndParent && !ParentWindow)
2025     {
2026         ERR("Got invalid parent window handle\n");
2027         goto cleanup;
2028     }
2029     else if (hWndOwner && !OwnerWindow)
2030     {
2031         ERR("Got invalid owner window handle\n");
2032         ParentWindow = NULL;
2033         goto cleanup;
2034     }
2035 
2036     if(OwnerWindow)
2037     {
2038        if (IntIsDesktopWindow(OwnerWindow)) OwnerWindow = NULL;
2039        else if (ParentWindow && !IntIsDesktopWindow(ParentWindow))
2040        {
2041           ERR("an owned window must be created as top-level\n");
2042           EngSetLastError( STATUS_ACCESS_DENIED );
2043           goto cleanup;
2044        }
2045        else /* owner must be a top-level window */
2046        {
2047           while ((OwnerWindow->style & (WS_POPUP|WS_CHILD)) == WS_CHILD && !IntIsDesktopWindow(OwnerWindow->spwndParent))
2048                  OwnerWindow = OwnerWindow->spwndParent;
2049        }
2050     }
2051 
2052    /* Fix the position and the size of the window */
2053    if (ParentWindow)
2054    {
2055        UserRefObjectCo(ParentWindow, &ParentRef);
2056        IntFixWindowCoordinates(Cs, ParentWindow, &dwShowMode);
2057    }
2058 
2059    /* Allocate and initialize the new window */
2060    Window = IntCreateWindow(Cs,
2061                             WindowName,
2062                             Class,
2063                             ParentWindow,
2064                             OwnerWindow,
2065                             acbiBuffer,
2066                             NULL);
2067    if(!Window)
2068    {
2069        ERR("IntCreateWindow failed!\n");
2070        goto cleanup;
2071    }
2072 
2073    hWnd = UserHMGetHandle(Window);
2074    hwndInsertAfter = HWND_TOP;
2075 
2076    UserRefObjectCo(Window, &Ref);
2077    UserDereferenceObject(Window);
2078    ObDereferenceObject(WinSta);
2079 
2080    //// Check for a hook to eliminate overhead. ////
2081    if ( ISITHOOKED(WH_CBT) ||  (pti->rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_CBT)) )
2082    {
2083       // Allocate the calling structures Justin Case this goes Global.
2084       pCsw = ExAllocatePoolWithTag(NonPagedPool, sizeof(CREATESTRUCTW), TAG_HOOK);
2085       pCbtCreate = ExAllocatePoolWithTag(NonPagedPool, sizeof(CBT_CREATEWNDW), TAG_HOOK);
2086       if (!pCsw || !pCbtCreate)
2087       {
2088       	 ERR("UserHeapAlloc() failed!\n");
2089       	 goto cleanup;
2090       }
2091 
2092       /* Fill the new CREATESTRUCTW */
2093       RtlCopyMemory(pCsw, Cs, sizeof(CREATESTRUCTW));
2094       pCsw->style = Window->style; /* HCBT_CREATEWND needs the real window style */
2095 
2096       // Based on the assumption this is from "unicode source" user32, ReactOS, answer is yes.
2097       if (!IS_ATOM(ClassName->Buffer))
2098       {
2099          if (Window->state & WNDS_ANSICREATOR)
2100          {
2101             ANSI_STRING AnsiString;
2102             AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(ClassName)+sizeof(CHAR);
2103             pszClass = UserHeapAlloc(AnsiString.MaximumLength);
2104             if (!pszClass)
2105             {
2106                ERR("UserHeapAlloc() failed!\n");
2107                goto cleanup;
2108             }
2109             RtlZeroMemory(pszClass, AnsiString.MaximumLength);
2110             AnsiString.Buffer = (PCHAR)pszClass;
2111             RtlUnicodeStringToAnsiString(&AnsiString, ClassName, FALSE);
2112          }
2113          else
2114          {
2115             UNICODE_STRING UnicodeString;
2116             UnicodeString.MaximumLength = ClassName->Length + sizeof(UNICODE_NULL);
2117             pszClass = UserHeapAlloc(UnicodeString.MaximumLength);
2118             if (!pszClass)
2119             {
2120                ERR("UserHeapAlloc() failed!\n");
2121                goto cleanup;
2122             }
2123             RtlZeroMemory(pszClass, UnicodeString.MaximumLength);
2124             UnicodeString.Buffer = (PWSTR)pszClass;
2125             RtlCopyUnicodeString(&UnicodeString, ClassName);
2126          }
2127          pCsw->lpszClass = UserHeapAddressToUser(pszClass);
2128       }
2129       if (WindowName->Length)
2130       {
2131          UNICODE_STRING Name;
2132          Name.Buffer = WindowName->Buffer;
2133          Name.Length = (USHORT)min(WindowName->Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2134          Name.MaximumLength = (USHORT)min(WindowName->MaximumLength, MAXUSHORT);
2135 
2136          if (Window->state & WNDS_ANSICREATOR)
2137          {
2138             ANSI_STRING AnsiString;
2139             AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(&Name) + sizeof(CHAR);
2140             pszName = UserHeapAlloc(AnsiString.MaximumLength);
2141             if (!pszName)
2142             {
2143                ERR("UserHeapAlloc() failed!\n");
2144                goto cleanup;
2145             }
2146             RtlZeroMemory(pszName, AnsiString.MaximumLength);
2147             AnsiString.Buffer = (PCHAR)pszName;
2148             RtlUnicodeStringToAnsiString(&AnsiString, &Name, FALSE);
2149          }
2150          else
2151          {
2152             UNICODE_STRING UnicodeString;
2153             UnicodeString.MaximumLength = Name.Length + sizeof(UNICODE_NULL);
2154             pszName = UserHeapAlloc(UnicodeString.MaximumLength);
2155             if (!pszName)
2156             {
2157                ERR("UserHeapAlloc() failed!\n");
2158                goto cleanup;
2159             }
2160             RtlZeroMemory(pszName, UnicodeString.MaximumLength);
2161             UnicodeString.Buffer = (PWSTR)pszName;
2162             RtlCopyUnicodeString(&UnicodeString, &Name);
2163          }
2164          pCsw->lpszName = UserHeapAddressToUser(pszName);
2165       }
2166 
2167       pCbtCreate->lpcs = pCsw;
2168       pCbtCreate->hwndInsertAfter = hwndInsertAfter;
2169 
2170       //// Call the WH_CBT hook ////
2171       Result = co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) pCbtCreate);
2172       if (Result != 0)
2173       {
2174          ERR("WH_CBT HCBT_CREATEWND hook failed! 0x%x\n", Result);
2175          goto cleanup;
2176       }
2177       // Write back changes.
2178       Cs->cx = pCsw->cx;
2179       Cs->cy = pCsw->cy;
2180       Cs->x = pCsw->x;
2181       Cs->y = pCsw->y;
2182       hwndInsertAfter = pCbtCreate->hwndInsertAfter;
2183    }
2184 
2185    /* NCCREATE and WM_NCCALCSIZE need the original values */
2186    Cs->lpszName = (LPCWSTR) WindowName;
2187    Cs->lpszClass = (LPCWSTR) ClassName;
2188 
2189    if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
2190    {
2191       if (ParentWindow != co_GetDesktopWindow(Window))
2192       {
2193          Cs->x += ParentWindow->rcClient.left;
2194          Cs->y += ParentWindow->rcClient.top;
2195       }
2196    }
2197 
2198    /* Send the WM_GETMINMAXINFO message */
2199    Size.cx = Cs->cx;
2200    Size.cy = Cs->cy;
2201 
2202    if ((Cs->style & WS_THICKFRAME) || !(Cs->style & (WS_POPUP | WS_CHILD)))
2203    {
2204       co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack, &MaxTrack);
2205       if (Size.cx > MaxTrack.x) Size.cx = MaxTrack.x;
2206       if (Size.cy > MaxTrack.y) Size.cy = MaxTrack.y;
2207       if (Size.cx < MinTrack.x) Size.cx = MinTrack.x;
2208       if (Size.cy < MinTrack.y) Size.cy = MinTrack.y;
2209    }
2210 
2211    Window->rcWindow.left = Cs->x;
2212    Window->rcWindow.top = Cs->y;
2213    Window->rcWindow.right = Cs->x + Size.cx;
2214    Window->rcWindow.bottom = Cs->y + Size.cy;
2215  /*
2216    if (0 != (Window->style & WS_CHILD) && ParentWindow)
2217    {
2218       ERR("co_UserCreateWindowEx(): Offset rcWindow\n");
2219       RECTL_vOffsetRect(&Window->rcWindow,
2220                         ParentWindow->rcClient.left,
2221                         ParentWindow->rcClient.top);
2222    }
2223  */
2224    /* correct child window coordinates if mirroring on parent is enabled */
2225    if (ParentWindow != NULL)
2226    {
2227       if ( ((Cs->style & WS_CHILD) == WS_CHILD) &&
2228           ((ParentWindow->ExStyle & WS_EX_LAYOUTRTL) ==  WS_EX_LAYOUTRTL))
2229       {
2230           Window->rcWindow.right = ParentWindow->rcClient.right - (Window->rcWindow.left - ParentWindow->rcClient.left);
2231           Window->rcWindow.left = Window->rcWindow.right - Size.cx;
2232       }
2233    }
2234 
2235    Window->rcClient = Window->rcWindow;
2236 
2237    /* Link the window */
2238    if (NULL != ParentWindow)
2239    {
2240       /* Link the window into the siblings list */
2241       if ((Cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
2242           IntLinkHwnd(Window, HWND_BOTTOM);
2243       else
2244           IntLinkHwnd(Window, hwndInsertAfter);
2245    }
2246 
2247    if (!(Window->state2 & WNDS2_WIN31COMPAT))
2248    {
2249       if (Class->style & CS_PARENTDC && !(ParentWindow->style & WS_CLIPCHILDREN))
2250          Window->style &= ~(WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
2251    }
2252 
2253    if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2254    {
2255       if ( !IntIsTopLevelWindow(Window) )
2256       {
2257          if (pti != Window->spwndParent->head.pti)
2258          {
2259             //ERR("CreateWindow Parent in.\n");
2260             UserAttachThreadInput(pti, Window->spwndParent->head.pti, TRUE);
2261          }
2262       }
2263    }
2264 
2265    /* Send the NCCREATE message */
2266    Result = co_IntSendMessage(UserHMGetHandle(Window), WM_NCCREATE, 0, (LPARAM) Cs);
2267    if (!Result)
2268    {
2269       ERR("co_UserCreateWindowEx(): NCCREATE message failed\n");
2270       goto cleanup;
2271    }
2272 
2273    /* Send the WM_NCCALCSIZE message */
2274    {
2275   // RECT rc;
2276    MaxPos.x = Window->rcWindow.left;
2277    MaxPos.y = Window->rcWindow.top;
2278 
2279    Result = co_WinPosGetNonClientSize(Window, &Window->rcWindow, &Window->rcClient);
2280    //rc = Window->rcWindow;
2281    //Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM)&rc);
2282    //Window->rcClient = rc;
2283 
2284    RECTL_vOffsetRect(&Window->rcWindow, MaxPos.x - Window->rcWindow.left,
2285                                      MaxPos.y - Window->rcWindow.top);
2286    }
2287 
2288    /* Send the WM_CREATE message. */
2289    Result = co_IntSendMessage(UserHMGetHandle(Window), WM_CREATE, 0, (LPARAM) Cs);
2290    if (Result == (LRESULT)-1)
2291    {
2292       ERR("co_UserCreateWindowEx(): WM_CREATE message failed\n");
2293       goto cleanup;
2294    }
2295 
2296    /* Send the EVENT_OBJECT_CREATE event */
2297    IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_WINDOW, CHILDID_SELF, 0);
2298 
2299    /* By setting the flag below it can be examined to determine if the window
2300       was created successfully and a valid pwnd was passed back to caller since
2301       from here the function has to succeed. */
2302    Window->state2 |= WNDS2_WMCREATEMSGPROCESSED;
2303 
2304    /* Send the WM_SIZE and WM_MOVE messages. */
2305    if (!(Window->state & WNDS_SENDSIZEMOVEMSGS))
2306    {
2307         co_WinPosSendSizeMove(Window);
2308    }
2309 
2310    /* Show or maybe minimize or maximize the window. */
2311 
2312    style = IntSetStyle( Window, 0, WS_MAXIMIZE | WS_MINIMIZE );
2313    if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2314    {
2315       RECTL NewPos;
2316       UINT SwFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
2317 
2318       SwFlag = co_WinPosMinMaximize(Window, SwFlag, &NewPos);
2319       SwFlag |= SWP_NOZORDER|SWP_FRAMECHANGED; /* Frame always gets changed */
2320       if (!(style & WS_VISIBLE) || (style & WS_CHILD) || UserGetActiveWindow()) SwFlag |= SWP_NOACTIVATE;
2321       co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
2322                             NewPos.right, NewPos.bottom, SwFlag);
2323    }
2324 
2325    /* Send the WM_PARENTNOTIFY message */
2326    IntSendParentNotify(Window, WM_CREATE);
2327 
2328    /* Notify the shell that a new window was created */
2329    if (UserIsDesktopWindow(Window->spwndParent) &&
2330        Window->spwndOwner == NULL &&
2331        (Window->style & WS_VISIBLE) &&
2332        (!(Window->ExStyle & WS_EX_TOOLWINDOW) ||
2333         (Window->ExStyle & WS_EX_APPWINDOW)))
2334    {
2335       co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)hWnd, 0);
2336    }
2337 
2338    /* Initialize and show the window's scrollbars */
2339    if (Window->style & WS_VSCROLL)
2340    {
2341       co_UserShowScrollBar(Window, SB_VERT, FALSE, TRUE);
2342    }
2343    if (Window->style & WS_HSCROLL)
2344    {
2345       co_UserShowScrollBar(Window, SB_HORZ, TRUE, FALSE);
2346    }
2347 
2348    /* Show the new window */
2349    if (Cs->style & WS_VISIBLE)
2350    {
2351       if (Window->style & WS_MAXIMIZE)
2352          dwShowMode = SW_SHOW;
2353       else if (Window->style & WS_MINIMIZE)
2354          dwShowMode = SW_SHOWMINIMIZED;
2355 
2356       co_WinPosShowWindow(Window, dwShowMode);
2357 
2358       if (Window->ExStyle & WS_EX_MDICHILD)
2359       {
2360           ASSERT(ParentWindow);
2361           if(!ParentWindow)
2362               goto cleanup;
2363         co_IntSendMessage(UserHMGetHandle(ParentWindow), WM_MDIREFRESHMENU, 0, 0);
2364         /* ShowWindow won't activate child windows */
2365         co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2366       }
2367    }
2368 
2369    if (Class->atomClassName == gaGuiConsoleWndClass)
2370    {
2371        /* Count only console windows manually */
2372        co_IntUserManualGuiCheck(TRUE);
2373    }
2374 
2375    TRACE("co_UserCreateWindowEx(): Created window %p\n", hWnd);
2376    ret = Window;
2377 
2378 cleanup:
2379    if (!ret)
2380    {
2381        TRACE("co_UserCreateWindowEx(): Error Created window!\n");
2382        /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */
2383        if (Window)
2384             co_UserDestroyWindow(Window);
2385        else if (Class)
2386            IntDereferenceClass(Class, pti->pDeskInfo, pti->ppi);
2387    }
2388 
2389    if (pCsw) ExFreePoolWithTag(pCsw, TAG_HOOK);
2390    if (pCbtCreate) ExFreePoolWithTag(pCbtCreate, TAG_HOOK);
2391    if (pszName) UserHeapFree(pszName);
2392    if (pszClass) UserHeapFree(pszClass);
2393 
2394    if (Window)
2395    {
2396       UserDerefObjectCo(Window);
2397    }
2398    if (ParentWindow) UserDerefObjectCo(ParentWindow);
2399 
2400    // See CORE-13717, not setting error on success.
2401    if (ret)
2402       EngSetLastError(ERROR_SUCCESS);
2403 
2404    return ret;
2405 }
2406 
2407 NTSTATUS
2408 NTAPI
2409 ProbeAndCaptureLargeString(
2410     OUT PLARGE_STRING plstrSafe,
2411     IN PLARGE_STRING plstrUnsafe)
2412 {
2413     LARGE_STRING lstrTemp;
2414     PVOID pvBuffer = NULL;
2415 
2416     _SEH2_TRY
2417     {
2418         /* Probe and copy the string */
2419         ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
2420         lstrTemp = *plstrUnsafe;
2421     }
2422     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2423     {
2424         /* Fail */
2425         _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2426     }
2427     _SEH2_END
2428 
2429     if (lstrTemp.Length != 0)
2430     {
2431         /* Allocate a buffer from paged pool */
2432         pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
2433         if (!pvBuffer)
2434         {
2435             return STATUS_NO_MEMORY;
2436         }
2437 
2438         _SEH2_TRY
2439         {
2440             /* Probe and copy the buffer */
2441             ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
2442             RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
2443         }
2444         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2445         {
2446             /* Cleanup and fail */
2447             ExFreePoolWithTag(pvBuffer, TAG_STRING);
2448             _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2449         }
2450         _SEH2_END
2451     }
2452 
2453     /* Set the output string */
2454     plstrSafe->Buffer = pvBuffer;
2455     plstrSafe->Length = lstrTemp.Length;
2456     plstrSafe->MaximumLength = lstrTemp.Length;
2457 
2458     return STATUS_SUCCESS;
2459 }
2460 
2461 /**
2462  * \todo Allow passing plstrClassName as ANSI.
2463  */
2464 HWND
2465 NTAPI
2466 NtUserCreateWindowEx(
2467     DWORD dwExStyle,
2468     PLARGE_STRING plstrClassName,
2469     PLARGE_STRING plstrClsVersion,
2470     PLARGE_STRING plstrWindowName,
2471     DWORD dwStyle,
2472     int x,
2473     int y,
2474     int nWidth,
2475     int nHeight,
2476     HWND hWndParent,
2477     HMENU hMenu,
2478     HINSTANCE hInstance,
2479     LPVOID lpParam,
2480     DWORD dwFlags,
2481     PVOID acbiBuffer)
2482 {
2483     NTSTATUS Status;
2484     LARGE_STRING lstrWindowName;
2485     LARGE_STRING lstrClassName;
2486     LARGE_STRING lstrClsVersion;
2487     UNICODE_STRING ustrClassName;
2488     UNICODE_STRING ustrClsVersion;
2489     CREATESTRUCTW Cs;
2490     HWND hwnd = NULL;
2491     PWND pwnd;
2492 
2493     lstrWindowName.Buffer = NULL;
2494     lstrClassName.Buffer = NULL;
2495     lstrClsVersion.Buffer = NULL;
2496 
2497     ASSERT(plstrWindowName);
2498 
2499     if ( (dwStyle & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2500     {
2501         /* check hMenu is valid handle */
2502         if (hMenu && !UserGetMenuObject(hMenu))
2503         {
2504             ERR("NtUserCreateWindowEx: Got an invalid menu handle!\n");
2505             EngSetLastError(ERROR_INVALID_MENU_HANDLE);
2506             return NULL;
2507         }
2508     }
2509 
2510     /* Copy the window name to kernel mode */
2511     Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
2512     if (!NT_SUCCESS(Status))
2513     {
2514         ERR("NtUserCreateWindowEx: failed to capture plstrWindowName\n");
2515         SetLastNtError(Status);
2516         return NULL;
2517     }
2518 
2519     plstrWindowName = &lstrWindowName;
2520 
2521     /* Check if the class is an atom */
2522     if (IS_ATOM(plstrClassName))
2523     {
2524         /* It is, pass the atom in the UNICODE_STRING */
2525         ustrClassName.Buffer = (PVOID)plstrClassName;
2526         ustrClassName.Length = 0;
2527         ustrClassName.MaximumLength = 0;
2528     }
2529     else
2530     {
2531         /* It's not, capture the class name */
2532         Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
2533         if (!NT_SUCCESS(Status))
2534         {
2535             ERR("NtUserCreateWindowEx: failed to capture plstrClassName\n");
2536             /* Set last error, cleanup and return */
2537             SetLastNtError(Status);
2538             goto cleanup;
2539         }
2540 
2541         /* We pass it on as a UNICODE_STRING */
2542         ustrClassName.Buffer = lstrClassName.Buffer;
2543         ustrClassName.Length = (USHORT)min(lstrClassName.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2544         ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT);
2545     }
2546 
2547     /* Check if the class version is an atom */
2548     if (IS_ATOM(plstrClsVersion))
2549     {
2550         /* It is, pass the atom in the UNICODE_STRING */
2551         ustrClsVersion.Buffer = (PVOID)plstrClsVersion;
2552         ustrClsVersion.Length = 0;
2553         ustrClsVersion.MaximumLength = 0;
2554     }
2555     else
2556     {
2557         /* It's not, capture the class name */
2558         Status = ProbeAndCaptureLargeString(&lstrClsVersion, plstrClsVersion);
2559         if (!NT_SUCCESS(Status))
2560         {
2561             ERR("NtUserCreateWindowEx: failed to capture plstrClsVersion\n");
2562             /* Set last error, cleanup and return */
2563             SetLastNtError(Status);
2564             goto cleanup;
2565         }
2566 
2567         /* We pass it on as a UNICODE_STRING */
2568         ustrClsVersion.Buffer = lstrClsVersion.Buffer;
2569         ustrClsVersion.Length = (USHORT)min(lstrClsVersion.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2570         ustrClsVersion.MaximumLength = (USHORT)min(lstrClsVersion.MaximumLength, MAXUSHORT);
2571     }
2572 
2573     /* Fill the CREATESTRUCTW */
2574     /* we will keep here the original parameters */
2575     Cs.style = dwStyle;
2576     Cs.lpCreateParams = lpParam;
2577     Cs.hInstance = hInstance;
2578     Cs.hMenu = hMenu;
2579     Cs.hwndParent = hWndParent;
2580     Cs.cx = nWidth;
2581     Cs.cy = nHeight;
2582     Cs.x = x;
2583     Cs.y = y;
2584     Cs.lpszName = (LPCWSTR) plstrWindowName->Buffer;
2585     Cs.lpszClass = ustrClassName.Buffer;
2586     Cs.dwExStyle = dwExStyle;
2587 
2588     UserEnterExclusive();
2589 
2590     /* Call the internal function */
2591     pwnd = co_UserCreateWindowEx(&Cs, &ustrClsVersion, plstrWindowName, acbiBuffer);
2592 
2593     if(!pwnd)
2594     {
2595         ERR("co_UserCreateWindowEx failed!\n");
2596     }
2597     hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
2598 
2599     UserLeave();
2600 
2601 cleanup:
2602     if (lstrWindowName.Buffer)
2603     {
2604         ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
2605     }
2606     if (lstrClassName.Buffer)
2607     {
2608         ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
2609     }
2610     if (lstrClsVersion.Buffer)
2611     {
2612         ExFreePoolWithTag(lstrClsVersion.Buffer, TAG_STRING);
2613     }
2614 
2615    return hwnd;
2616 }
2617 
2618 
2619 BOOLEAN co_UserDestroyWindow(PVOID Object)
2620 {
2621    HWND hWnd;
2622    PWND pwndTemp;
2623    PTHREADINFO ti;
2624    MSG msg;
2625    PWND Window = Object;
2626 
2627    ASSERT_REFS_CO(Window); // FIXME: Temp HACK?
2628 
2629    hWnd = Window->head.h;
2630    ti = PsGetCurrentThreadWin32Thread();
2631 
2632    TRACE("co_UserDestroyWindow(Window = 0x%p, hWnd = 0x%p)\n", Window, hWnd);
2633 
2634    /* Check for owner thread */
2635    if ( Window->head.pti != PsGetCurrentThreadWin32Thread())
2636    {
2637        /* Check if we are destroying the desktop window */
2638        if (! ((Window->head.rpdesk->dwDTFlags & DF_DESTROYED) && Window == Window->head.rpdesk->pDeskInfo->spwnd))
2639        {
2640            EngSetLastError(ERROR_ACCESS_DENIED);
2641            return FALSE;
2642        }
2643    }
2644 
2645    /* If window was created successfully and it is hooked */
2646    if ((Window->state2 & WNDS2_WMCREATEMSGPROCESSED))
2647    {
2648       if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0))
2649       {
2650          ERR("Destroy Window WH_CBT Call Hook return!\n");
2651          return FALSE;
2652       }
2653    }
2654 
2655    if (Window->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME])
2656    {
2657       if ((Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2658       {
2659          if (Window->spwndOwner)
2660          {
2661             //ERR("DestroyWindow Owner out.\n");
2662             UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE);
2663          }
2664       }
2665    }
2666 
2667    /* Inform the parent */
2668    if (Window->style & WS_CHILD)
2669    {
2670       IntSendParentNotify(Window, WM_DESTROY);
2671    }
2672 
2673    if (!Window->spwndOwner && !IntGetParent(Window))
2674    {
2675       co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM) hWnd, 0);
2676    }
2677 
2678    /* Hide the window */
2679    if (Window->style & WS_VISIBLE)
2680    {
2681       if (Window->style & WS_CHILD)
2682       {
2683          /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
2684          co_WinPosShowWindow(Window, SW_HIDE);
2685       }
2686       else
2687       {
2688          co_WinPosSetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_HIDEWINDOW );
2689       }
2690    }
2691 
2692    /* Adjust last active */
2693    if ((pwndTemp = Window->spwndOwner))
2694    {
2695       while (pwndTemp->spwndOwner)
2696          pwndTemp = pwndTemp->spwndOwner;
2697 
2698       if (pwndTemp->spwndLastActive == Window)
2699          pwndTemp->spwndLastActive = Window->spwndOwner;
2700    }
2701 
2702    if (Window->spwndParent && IntIsWindow(UserHMGetHandle(Window)))
2703    {
2704       if ((Window->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
2705       {
2706          if (!IntIsTopLevelWindow(Window))
2707          {
2708             //ERR("DestroyWindow Parent out.\n");
2709             UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE);
2710          }
2711       }
2712    }
2713 
2714    if (Window->head.pti->MessageQueue->spwndActive == Window)
2715       Window->head.pti->MessageQueue->spwndActive = NULL;
2716    if (Window->head.pti->MessageQueue->spwndFocus == Window)
2717       Window->head.pti->MessageQueue->spwndFocus = NULL;
2718    if (Window->head.pti->MessageQueue->spwndActivePrev == Window)
2719       Window->head.pti->MessageQueue->spwndActivePrev = NULL;
2720    if (Window->head.pti->MessageQueue->spwndCapture == Window)
2721       Window->head.pti->MessageQueue->spwndCapture = NULL;
2722 
2723    /*
2724     * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
2725     */
2726 
2727    if ((ti != NULL) && (ti->pDeskInfo != NULL))
2728    {
2729       if (ti->pDeskInfo->hShellWindow == hWnd)
2730       {
2731          ERR("Destroying the ShellWindow!\n");
2732          ti->pDeskInfo->hShellWindow = NULL;
2733       }
2734    }
2735 
2736    IntEngWindowChanged(Window, WOC_DELETE);
2737 
2738    if (!IntIsWindow(UserHMGetHandle(Window)))
2739    {
2740       return TRUE;
2741    }
2742 
2743     /* Recursively destroy owned windows */
2744     if (!(Window->style & WS_CHILD))
2745     {
2746         HWND* List;
2747         HWND* phWnd;
2748         PWND pWnd;
2749 
2750         List = IntWinListOwnedPopups(Window);
2751         if (List)
2752         {
2753             for (phWnd = List; *phWnd; ++phWnd)
2754             {
2755                 pWnd = ValidateHwndNoErr(*phWnd);
2756                 if (pWnd == NULL)
2757                     continue;
2758                 ASSERT(pWnd->spwndOwner == Window);
2759                 ASSERT(pWnd != Window);
2760 
2761                 pWnd->spwndOwner = NULL;
2762                 if (IntWndBelongsToThread(pWnd, PsGetCurrentThreadWin32Thread()))
2763                 {
2764                     USER_REFERENCE_ENTRY Ref;
2765                     UserRefObjectCo(pWnd, &Ref); // Temp HACK?
2766                     co_UserDestroyWindow(pWnd);
2767                     UserDerefObjectCo(pWnd); // Temp HACK?
2768                 }
2769                 else
2770                 {
2771                     ERR("IntWndBelongsToThread(0x%p) is FALSE, ignoring.\n", pWnd);
2772                 }
2773             }
2774 
2775             ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2776         }
2777     }
2778 
2779     /* Generate mouse move message for the next window */
2780     msg.message = WM_MOUSEMOVE;
2781     msg.wParam = UserGetMouseButtonsState();
2782     msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2783     msg.pt = gpsi->ptCursor;
2784     co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2785 
2786    IntNotifyWinEvent(EVENT_OBJECT_DESTROY, Window, OBJID_WINDOW, CHILDID_SELF, 0);
2787 
2788    /* Send destroy messages */
2789    IntSendDestroyMsg(UserHMGetHandle(Window));
2790 
2791    if (!IntIsWindow(UserHMGetHandle(Window)))
2792    {
2793       return TRUE;
2794    }
2795 
2796    /* Destroy the window storage */
2797    co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
2798 
2799    return TRUE;
2800 }
2801 
2802 
2803 /*
2804  * @implemented
2805  */
2806 BOOLEAN APIENTRY
2807 NtUserDestroyWindow(HWND Wnd)
2808 {
2809    PWND Window;
2810    DECLARE_RETURN(BOOLEAN);
2811    BOOLEAN ret;
2812    USER_REFERENCE_ENTRY Ref;
2813 
2814    TRACE("Enter NtUserDestroyWindow\n");
2815    UserEnterExclusive();
2816 
2817    if (!(Window = UserGetWindowObject(Wnd)))
2818    {
2819       RETURN(FALSE);
2820    }
2821 
2822    UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy...
2823    ret = co_UserDestroyWindow(Window);
2824    UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy...
2825 
2826    RETURN(ret);
2827 
2828 CLEANUP:
2829    TRACE("Leave NtUserDestroyWindow, ret=%u\n", _ret_);
2830    UserLeave();
2831    END_CLEANUP;
2832 }
2833 
2834 
2835 static HWND FASTCALL
2836 IntFindWindow(PWND Parent,
2837               PWND ChildAfter,
2838               RTL_ATOM ClassAtom,
2839               PUNICODE_STRING WindowName)
2840 {
2841    BOOL CheckWindowName;
2842    HWND *List, *phWnd;
2843    HWND Ret = NULL;
2844    UNICODE_STRING CurrentWindowName;
2845 
2846    ASSERT(Parent);
2847 
2848    CheckWindowName = WindowName->Buffer != 0;
2849 
2850    if((List = IntWinListChildren(Parent)))
2851    {
2852       phWnd = List;
2853       if(ChildAfter)
2854       {
2855          /* skip handles before and including ChildAfter */
2856          while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2857             ;
2858       }
2859 
2860       /* search children */
2861       while(*phWnd)
2862       {
2863          PWND Child;
2864          if(!(Child = UserGetWindowObject(*(phWnd++))))
2865          {
2866             continue;
2867          }
2868 
2869          /* Do not send WM_GETTEXT messages in the kernel mode version!
2870             The user mode version however calls GetWindowText() which will
2871             send WM_GETTEXT messages to windows belonging to its processes */
2872          if (!ClassAtom || Child->pcls->atomNVClassName == ClassAtom)
2873          {
2874              // FIXME: LARGE_STRING truncated
2875              CurrentWindowName.Buffer = Child->strName.Buffer;
2876              CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT);
2877              CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT);
2878              if(!CheckWindowName ||
2879                 (Child->strName.Length < 0xFFFF &&
2880                  !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
2881              {
2882                 Ret = Child->head.h;
2883                 break;
2884              }
2885          }
2886       }
2887       ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2888    }
2889 
2890    return Ret;
2891 }
2892 
2893 /*
2894  * FUNCTION:
2895  *   Searches a window's children for a window with the specified
2896  *   class and name
2897  * ARGUMENTS:
2898  *   hwndParent     = The window whose childs are to be searched.
2899  *       NULL = desktop
2900  *       HWND_MESSAGE = message-only windows
2901  *
2902  *   hwndChildAfter = Search starts after this child window.
2903  *       NULL = start from beginning
2904  *
2905  *   ucClassName    = Class name to search for
2906  *       Reguired parameter.
2907  *
2908  *   ucWindowName   = Window name
2909  *       ->Buffer == NULL = don't care
2910  *
2911  * RETURNS:
2912  *   The HWND of the window if it was found, otherwise NULL
2913  */
2914 /*
2915  * @implemented
2916  */
2917 HWND APIENTRY
2918 NtUserFindWindowEx(HWND hwndParent,
2919                    HWND hwndChildAfter,
2920                    PUNICODE_STRING ucClassName,
2921                    PUNICODE_STRING ucWindowName,
2922                    DWORD dwUnknown)
2923 {
2924    PWND Parent, ChildAfter;
2925    UNICODE_STRING ClassName = {0}, WindowName = {0};
2926    HWND Desktop, Ret = NULL;
2927    BOOL DoMessageWnd = FALSE;
2928    RTL_ATOM ClassAtom = (RTL_ATOM)0;
2929    DECLARE_RETURN(HWND);
2930 
2931    TRACE("Enter NtUserFindWindowEx\n");
2932    UserEnterShared();
2933 
2934    if (ucClassName != NULL || ucWindowName != NULL)
2935    {
2936        _SEH2_TRY
2937        {
2938            if (ucClassName != NULL)
2939            {
2940                ClassName = ProbeForReadUnicodeString(ucClassName);
2941                if (ClassName.Length != 0)
2942                {
2943                    ProbeForRead(ClassName.Buffer,
2944                                 ClassName.Length,
2945                                 sizeof(WCHAR));
2946                }
2947                else if (!IS_ATOM(ClassName.Buffer))
2948                {
2949                    EngSetLastError(ERROR_INVALID_PARAMETER);
2950                    _SEH2_LEAVE;
2951                }
2952 
2953                if (!IntGetAtomFromStringOrAtom(&ClassName,
2954                                                &ClassAtom))
2955                {
2956                    EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS);
2957                    _SEH2_LEAVE;
2958                }
2959            }
2960 
2961            if (ucWindowName != NULL)
2962            {
2963                WindowName = ProbeForReadUnicodeString(ucWindowName);
2964                if (WindowName.Length != 0)
2965                {
2966                    ProbeForRead(WindowName.Buffer,
2967                                 WindowName.Length,
2968                                 sizeof(WCHAR));
2969                }
2970            }
2971        }
2972        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2973        {
2974            SetLastNtError(_SEH2_GetExceptionCode());
2975            _SEH2_YIELD(RETURN(NULL));
2976        }
2977        _SEH2_END;
2978 
2979        if (ucClassName != NULL)
2980        {
2981            if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
2982                !IS_ATOM(ClassName.Buffer))
2983            {
2984                EngSetLastError(ERROR_INVALID_PARAMETER);
2985                RETURN(NULL);
2986            }
2987            else if (ClassAtom == (RTL_ATOM)0)
2988            {
2989                /* LastError code was set by IntGetAtomFromStringOrAtom */
2990                RETURN(NULL);
2991            }
2992        }
2993    }
2994 
2995    Desktop = IntGetCurrentThreadDesktopWindow();
2996 
2997    if(hwndParent == NULL)
2998    {
2999       hwndParent = Desktop;
3000       DoMessageWnd = TRUE;
3001    }
3002    else if(hwndParent == HWND_MESSAGE)
3003    {
3004      hwndParent = IntGetMessageWindow();
3005    }
3006 
3007    if(!(Parent = UserGetWindowObject(hwndParent)))
3008    {
3009       RETURN( NULL);
3010    }
3011 
3012    ChildAfter = NULL;
3013    if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
3014    {
3015       RETURN( NULL);
3016    }
3017 
3018    _SEH2_TRY
3019    {
3020        if(Parent->head.h == Desktop)
3021        {
3022           HWND *List, *phWnd;
3023           PWND TopLevelWindow;
3024           BOOLEAN CheckWindowName;
3025           BOOLEAN WindowMatches;
3026           BOOLEAN ClassMatches;
3027 
3028           /* windows searches through all top-level windows if the parent is the desktop
3029              window */
3030 
3031           if((List = IntWinListChildren(Parent)))
3032           {
3033              phWnd = List;
3034 
3035              if(ChildAfter)
3036              {
3037                 /* skip handles before and including ChildAfter */
3038                 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
3039                    ;
3040              }
3041 
3042              CheckWindowName = WindowName.Buffer != 0;
3043 
3044              /* search children */
3045              while(*phWnd)
3046              {
3047                  UNICODE_STRING ustr;
3048 
3049                 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
3050                 {
3051                    continue;
3052                 }
3053 
3054                 /* Do not send WM_GETTEXT messages in the kernel mode version!
3055                    The user mode version however calls GetWindowText() which will
3056                    send WM_GETTEXT messages to windows belonging to its processes */
3057                 ustr.Buffer = TopLevelWindow->strName.Buffer;
3058                 ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated
3059                 ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT);
3060                 WindowMatches = !CheckWindowName ||
3061                                 (TopLevelWindow->strName.Length < 0xFFFF &&
3062                                  !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
3063                 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
3064                                ClassAtom == TopLevelWindow->pcls->atomNVClassName;
3065 
3066                 if (WindowMatches && ClassMatches)
3067                 {
3068                    Ret = TopLevelWindow->head.h;
3069                    break;
3070                 }
3071 
3072                 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
3073                 {
3074                    /* window returns the handle of the top-level window, in case it found
3075                       the child window */
3076                    Ret = TopLevelWindow->head.h;
3077                    break;
3078                 }
3079 
3080              }
3081              ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
3082           }
3083        }
3084        else
3085        {
3086           TRACE("FindWindowEx: Not Desktop Parent!\n");
3087           Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
3088        }
3089 
3090        if (Ret == NULL && DoMessageWnd)
3091        {
3092           PWND MsgWindows;
3093 
3094           if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
3095           {
3096              Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
3097           }
3098        }
3099    }
3100    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3101    {
3102        SetLastNtError(_SEH2_GetExceptionCode());
3103        Ret = NULL;
3104    }
3105    _SEH2_END;
3106 
3107    RETURN( Ret);
3108 
3109 CLEANUP:
3110    TRACE("Leave NtUserFindWindowEx, ret %p\n", _ret_);
3111    UserLeave();
3112    END_CLEANUP;
3113 }
3114 
3115 
3116 /*
3117  * @implemented
3118  */
3119 PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type)
3120 {
3121    PWND WndAncestor, Parent;
3122 
3123    if (Wnd->head.h == IntGetDesktopWindow())
3124    {
3125       return NULL;
3126    }
3127 
3128    switch (Type)
3129    {
3130       case GA_PARENT:
3131          {
3132             WndAncestor = Wnd->spwndParent;
3133             break;
3134          }
3135 
3136       case GA_ROOT:
3137          {
3138             WndAncestor = Wnd;
3139             Parent = NULL;
3140 
3141             for(;;)
3142             {
3143                if(!(Parent = WndAncestor->spwndParent))
3144                {
3145                   break;
3146                }
3147                if(IntIsDesktopWindow(Parent))
3148                {
3149                   break;
3150                }
3151 
3152                WndAncestor = Parent;
3153             }
3154             break;
3155          }
3156 
3157       case GA_ROOTOWNER:
3158          {
3159             WndAncestor = Wnd;
3160 
3161             for (;;)
3162             {
3163                Parent = IntGetParent(WndAncestor);
3164 
3165                if (!Parent)
3166                {
3167                   break;
3168                }
3169 
3170                WndAncestor = Parent;
3171             }
3172             break;
3173          }
3174 
3175       default:
3176          {
3177             return NULL;
3178          }
3179    }
3180 
3181    return WndAncestor;
3182 }
3183 
3184 /*
3185  * @implemented
3186  */
3187 HWND APIENTRY
3188 NtUserGetAncestor(HWND hWnd, UINT Type)
3189 {
3190    PWND Window, Ancestor;
3191    DECLARE_RETURN(HWND);
3192 
3193    TRACE("Enter NtUserGetAncestor\n");
3194    UserEnterExclusive();
3195 
3196    if (!(Window = UserGetWindowObject(hWnd)))
3197    {
3198       RETURN(NULL);
3199    }
3200 
3201    Ancestor = UserGetAncestor(Window, Type);
3202    /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3203 
3204    RETURN(Ancestor ? Ancestor->head.h : NULL);
3205 
3206 CLEANUP:
3207    TRACE("Leave NtUserGetAncestor, ret=%p\n", _ret_);
3208    UserLeave();
3209    END_CLEANUP;
3210 }
3211 
3212 ////
3213 //// ReactOS work around! Keep it the sames as in Combo.c and Controls.h
3214 ////
3215 /* combo state struct */
3216 typedef struct
3217 {
3218    HWND           self;
3219    HWND           owner;
3220    UINT           dwStyle;
3221    HWND           hWndEdit;
3222    HWND           hWndLBox;
3223    UINT           wState;
3224    HFONT          hFont;
3225    RECT           textRect;
3226    RECT           buttonRect;
3227    RECT           droppedRect;
3228    INT            droppedIndex;
3229    INT            fixedOwnerDrawHeight;
3230    INT            droppedWidth;   /* last two are not used unless set */
3231    INT            editHeight;     /* explicitly */
3232    LONG           UIState;
3233 } HEADCOMBO,*LPHEADCOMBO;
3234 
3235 // Window Extra data container.
3236 typedef struct _WND2CBOX
3237 {
3238   WND;
3239   LPHEADCOMBO pCBox;
3240 } WND2CBOX, *PWND2CBOX;
3241 
3242 #define CBF_BUTTONDOWN          0x0002
3243 ////
3244 ////
3245 ////
3246 BOOL
3247 APIENTRY
3248 NtUserGetComboBoxInfo(
3249    HWND hWnd,
3250    PCOMBOBOXINFO pcbi)
3251 {
3252    PWND Wnd;
3253    PPROCESSINFO ppi;
3254    BOOL NotSameppi = FALSE;
3255    BOOL Ret = TRUE;
3256    DECLARE_RETURN(BOOL);
3257 
3258    TRACE("Enter NtUserGetComboBoxInfo\n");
3259    UserEnterShared();
3260 
3261    if (!(Wnd = UserGetWindowObject(hWnd)))
3262    {
3263       RETURN( FALSE );
3264    }
3265    _SEH2_TRY
3266    {
3267         ProbeForWrite(pcbi, sizeof(COMBOBOXINFO), 1);
3268    }
3269    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3270    {
3271        SetLastNtError(_SEH2_GetExceptionCode());
3272        _SEH2_YIELD(RETURN(FALSE));
3273    }
3274    _SEH2_END;
3275 
3276    if (pcbi->cbSize < sizeof(COMBOBOXINFO))
3277    {
3278       EngSetLastError(ERROR_INVALID_PARAMETER);
3279       RETURN(FALSE);
3280    }
3281 
3282    // Pass the user pointer, it was already probed.
3283    if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_COMBOBOX]) && Wnd->fnid != FNID_COMBOBOX)
3284    {
3285       RETURN( (BOOL) co_IntSendMessage( Wnd->head.h, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
3286    }
3287 
3288    ppi = PsGetCurrentProcessWin32Process();
3289    NotSameppi = ppi != Wnd->head.pti->ppi;
3290    if (NotSameppi)
3291    {
3292       KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3293    }
3294 
3295    _SEH2_TRY
3296    {
3297       LPHEADCOMBO lphc = ((PWND2CBOX)Wnd)->pCBox;
3298       pcbi->rcItem = lphc->textRect;
3299       pcbi->rcButton = lphc->buttonRect;
3300       pcbi->stateButton = 0;
3301       if (lphc->wState & CBF_BUTTONDOWN)
3302          pcbi->stateButton |= STATE_SYSTEM_PRESSED;
3303       if (RECTL_bIsEmptyRect(&lphc->buttonRect))
3304          pcbi->stateButton |= STATE_SYSTEM_INVISIBLE;
3305       pcbi->hwndCombo = lphc->self;
3306       pcbi->hwndItem = lphc->hWndEdit;
3307       pcbi->hwndList = lphc->hWndLBox;
3308    }
3309    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3310    {
3311       Ret = FALSE;
3312       SetLastNtError(_SEH2_GetExceptionCode());
3313    }
3314    _SEH2_END;
3315 
3316    RETURN( Ret);
3317 
3318 CLEANUP:
3319    if (NotSameppi) KeDetachProcess();
3320    TRACE("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
3321    UserLeave();
3322    END_CLEANUP;
3323 }
3324 
3325 ////
3326 //// ReactOS work around! Keep it the sames as in Listbox.c
3327 ////
3328 /* Listbox structure */
3329 typedef struct
3330 {
3331     HWND        self;           /* Our own window handle */
3332     HWND        owner;          /* Owner window to send notifications to */
3333     UINT        style;          /* Window style */
3334     INT         width;          /* Window width */
3335     INT         height;         /* Window height */
3336     VOID       *items;          /* Array of items */
3337     INT         nb_items;       /* Number of items */
3338     INT         top_item;       /* Top visible item */
3339     INT         selected_item;  /* Selected item */
3340     INT         focus_item;     /* Item that has the focus */
3341     INT         anchor_item;    /* Anchor item for extended selection */
3342     INT         item_height;    /* Default item height */
3343     INT         page_size;      /* Items per listbox page */
3344     INT         column_width;   /* Column width for multi-column listboxes */
3345 } LB_DESCR;
3346 
3347 // Window Extra data container.
3348 typedef struct _WND2LB
3349 {
3350   WND;
3351   LB_DESCR * pLBiv;
3352 } WND2LB, *PWND2LB;
3353 ////
3354 ////
3355 ////
3356 DWORD
3357 APIENTRY
3358 NtUserGetListBoxInfo(
3359    HWND hWnd)
3360 {
3361    PWND Wnd;
3362    PPROCESSINFO ppi;
3363    BOOL NotSameppi = FALSE;
3364    DWORD Ret = 0;
3365    DECLARE_RETURN(DWORD);
3366 
3367    TRACE("Enter NtUserGetListBoxInfo\n");
3368    UserEnterShared();
3369 
3370    if (!(Wnd = UserGetWindowObject(hWnd)))
3371    {
3372       RETURN( 0 );
3373    }
3374 
3375    if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_LISTBOX]) && Wnd->fnid != FNID_LISTBOX)
3376    {
3377       RETURN( (DWORD) co_IntSendMessage( Wnd->head.h, LB_GETLISTBOXINFO, 0, 0 ));
3378    }
3379 
3380    // wine lisbox:test_GetListBoxInfo lb_getlistboxinfo = 0, should not send a message!
3381    ppi = PsGetCurrentProcessWin32Process();
3382    NotSameppi = ppi != Wnd->head.pti->ppi;
3383    if (NotSameppi)
3384    {
3385       KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3386    }
3387 
3388    _SEH2_TRY
3389    {
3390       LB_DESCR *descr = ((PWND2LB)Wnd)->pLBiv;
3391       // See Controls ListBox.c:LB_GETLISTBOXINFO must match...
3392       if (descr->style & LBS_MULTICOLUMN) //// ReactOS
3393          Ret = descr->page_size * descr->column_width;
3394       else
3395          Ret = descr->page_size;
3396    }
3397    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3398    {
3399       Ret = 0;
3400       SetLastNtError(_SEH2_GetExceptionCode());
3401    }
3402    _SEH2_END;
3403 
3404    RETURN( Ret);
3405 
3406 CLEANUP:
3407    if (NotSameppi) KeDetachProcess();
3408    TRACE("Leave NtUserGetListBoxInfo, ret=%lu\n", _ret_);
3409    UserLeave();
3410    END_CLEANUP;
3411 }
3412 
3413 /*
3414  * NtUserSetParent
3415  *
3416  * The NtUserSetParent function changes the parent window of the specified
3417  * child window.
3418  *
3419  * Remarks
3420  *    The new parent window and the child window must belong to the same
3421  *    application. If the window identified by the hWndChild parameter is
3422  *    visible, the system performs the appropriate redrawing and repainting.
3423  *    For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3424  *    or WS_POPUP window styles of the window whose parent is being changed.
3425  *
3426  * Status
3427  *    @implemented
3428  */
3429 
3430 HWND APIENTRY
3431 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
3432 {
3433    DECLARE_RETURN(HWND);
3434 
3435    TRACE("Enter NtUserSetParent\n");
3436    UserEnterExclusive();
3437 
3438    /*
3439       Check Parent first from user space, set it here.
3440     */
3441    if (!hWndNewParent)
3442    {
3443       hWndNewParent = IntGetDesktopWindow();
3444    }
3445    else if (hWndNewParent == HWND_MESSAGE)
3446    {
3447       hWndNewParent = IntGetMessageWindow();
3448    }
3449 
3450    RETURN( co_UserSetParent(hWndChild, hWndNewParent));
3451 
3452 CLEANUP:
3453    TRACE("Leave NtUserSetParent, ret=%p\n", _ret_);
3454    UserLeave();
3455    END_CLEANUP;
3456 }
3457 
3458 /*
3459  * UserGetShellWindow
3460  *
3461  * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3462  *
3463  * Status
3464  *    @implemented
3465  */
3466 HWND FASTCALL UserGetShellWindow(VOID)
3467 {
3468    PWINSTATION_OBJECT WinStaObject;
3469    HWND Ret;
3470 
3471    NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3472                      UserMode,
3473                      0,
3474                      &WinStaObject,
3475                      0);
3476 
3477    if (!NT_SUCCESS(Status))
3478    {
3479       SetLastNtError(Status);
3480       return( (HWND)0);
3481    }
3482 
3483    Ret = (HWND)WinStaObject->ShellWindow;
3484 
3485    ObDereferenceObject(WinStaObject);
3486    return( Ret);
3487 }
3488 
3489 /*
3490  * NtUserSetShellWindowEx
3491  *
3492  * This is undocumented function to set global shell window. The global
3493  * shell window has special handling of window position.
3494  *
3495  * Status
3496  *    @implemented
3497  */
3498 BOOL APIENTRY
3499 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
3500 {
3501    PWINSTATION_OBJECT WinStaObject;
3502    PWND WndShell, WndListView;
3503    DECLARE_RETURN(BOOL);
3504    USER_REFERENCE_ENTRY Ref;
3505    NTSTATUS Status;
3506    PTHREADINFO ti;
3507 
3508    TRACE("Enter NtUserSetShellWindowEx\n");
3509    UserEnterExclusive();
3510 
3511    if (!(WndShell = UserGetWindowObject(hwndShell)))
3512    {
3513       RETURN(FALSE);
3514    }
3515 
3516    if (!(WndListView = UserGetWindowObject(hwndListView)))
3517    {
3518       RETURN(FALSE);
3519    }
3520 
3521    Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3522                      UserMode,
3523                      0,
3524                      &WinStaObject,
3525                      0);
3526 
3527    if (!NT_SUCCESS(Status))
3528    {
3529       SetLastNtError(Status);
3530       RETURN( FALSE);
3531    }
3532 
3533    /*
3534     * Test if we are permitted to change the shell window.
3535     */
3536    if (WinStaObject->ShellWindow)
3537    {
3538       ObDereferenceObject(WinStaObject);
3539       RETURN( FALSE);
3540    }
3541 
3542    /*
3543     * Move shell window into background.
3544     */
3545    if (hwndListView && hwndListView != hwndShell)
3546    {
3547       /*
3548        * Disabled for now to get Explorer working.
3549        * -- Filip, 01/nov/2003
3550        */
3551 #if 0
3552       co_WinPosSetWindowPos(WndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3553 #endif
3554 
3555       if (WndListView->ExStyle & WS_EX_TOPMOST)
3556       {
3557          ObDereferenceObject(WinStaObject);
3558          RETURN( FALSE);
3559       }
3560    }
3561 
3562    if (WndShell->ExStyle & WS_EX_TOPMOST)
3563    {
3564       ObDereferenceObject(WinStaObject);
3565       RETURN( FALSE);
3566    }
3567 
3568    UserRefObjectCo(WndShell, &Ref);
3569    WndShell->state2 |= WNDS2_BOTTOMMOST;
3570    co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3571 
3572    WinStaObject->ShellWindow = hwndShell;
3573    WinStaObject->ShellListView = hwndListView;
3574 
3575    ti = GetW32ThreadInfo();
3576    if (ti->pDeskInfo)
3577    {
3578        ti->pDeskInfo->hShellWindow = hwndShell;
3579        ti->pDeskInfo->spwndShell = WndShell;
3580        ti->pDeskInfo->spwndBkGnd = WndListView;
3581        ti->pDeskInfo->ppiShellProcess = ti->ppi;
3582    }
3583 
3584    UserRegisterHotKey(WndShell, SC_TASKLIST, MOD_CONTROL, VK_ESCAPE);
3585 
3586    UserDerefObjectCo(WndShell);
3587 
3588    ObDereferenceObject(WinStaObject);
3589    RETURN( TRUE);
3590 
3591 CLEANUP:
3592    TRACE("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_);
3593    UserLeave();
3594    END_CLEANUP;
3595 }
3596 
3597 // Fixes wine Win test_window_styles and todo tests...
3598 static BOOL FASTCALL
3599 IntCheckFrameEdge(ULONG Style, ULONG ExStyle)
3600 {
3601    if (ExStyle & WS_EX_DLGMODALFRAME)
3602       return TRUE;
3603    else if (!(ExStyle & WS_EX_STATICEDGE) && (Style & (WS_DLGFRAME | WS_THICKFRAME)))
3604       return TRUE;
3605    else
3606       return FALSE;
3607 }
3608 
3609 static LONG_PTR
3610 co_IntSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi, ULONG Size, BOOL bAlter)
3611 {
3612    PWND Window, Parent;
3613    PWINSTATION_OBJECT WindowStation;
3614    LONG_PTR OldValue;
3615    STYLESTRUCT Style;
3616 
3617    if (!(Window = UserGetWindowObject(hWnd)))
3618    {
3619       return( 0);
3620    }
3621 
3622    if ((INT)Index >= 0)
3623    {
3624       if ((Index + Size) > Window->cbwndExtra)
3625       {
3626          EngSetLastError(ERROR_INVALID_INDEX);
3627          return( 0);
3628       }
3629 
3630 #ifdef _WIN64
3631       if (Size == sizeof(LONG))
3632       {
3633          OldValue = *((LONG *)((PCHAR)(Window + 1) + Index));
3634          *((LONG*)((PCHAR)(Window + 1) + Index)) = (LONG)NewValue;
3635       }
3636       else
3637 #endif
3638       {
3639          OldValue = *((LONG_PTR *)((PCHAR)(Window + 1) + Index));
3640          /*
3641          if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW)
3642          {
3643             OldValue = (LONG_PTR)IntSetWindowProc( Wnd, (WNDPROC)NewValue, Ansi);
3644             if (!OldValue) return 0;
3645          }
3646          */
3647          *((LONG_PTR*)((PCHAR)(Window + 1) + Index)) = NewValue;
3648       }
3649 
3650    }
3651    else
3652    {
3653 #ifdef _WIN64
3654       if (Size == sizeof(LONG))
3655       {
3656          if ((Index != GWL_STYLE) &&
3657              (Index != GWL_EXSTYLE) &&
3658              (Index != GWL_ID) &&
3659              (Index != GWL_USERDATA))
3660          {
3661             ERR("NtUserSetWindowLong(): Index requires pointer size: %lu\n", Index);
3662             EngSetLastError(ERROR_INVALID_INDEX);
3663             return 0;
3664          }
3665       }
3666 #endif
3667 
3668       switch (Index)
3669       {
3670          case GWL_EXSTYLE: // LONG
3671             OldValue = (LONG) Window->ExStyle;
3672             Style.styleOld = OldValue;
3673             Style.styleNew = NewValue;
3674 
3675             co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
3676 
3677             /*
3678              * Remove extended window style bit WS_EX_TOPMOST for shell windows.
3679              */
3680             WindowStation = Window->head.pti->rpdesk->rpwinstaParent;
3681             if(WindowStation)
3682             {
3683                if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
3684                   Style.styleNew &= ~WS_EX_TOPMOST;
3685             }
3686             /* WS_EX_WINDOWEDGE depends on some other styles */
3687             if (IntCheckFrameEdge(Window->style, NewValue))
3688                Style.styleNew |= WS_EX_WINDOWEDGE;
3689             else
3690                Style.styleNew &= ~WS_EX_WINDOWEDGE;
3691 
3692             if (!(Window->ExStyle & WS_EX_LAYERED))
3693             {
3694                SetLayeredStatus(Window, 0);
3695             }
3696 
3697             Window->ExStyle = (DWORD)Style.styleNew;
3698 
3699             co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
3700             break;
3701 
3702          case GWL_STYLE: // LONG
3703             OldValue = (LONG) Window->style;
3704             Style.styleOld = OldValue;
3705             Style.styleNew = NewValue;
3706 
3707             if (!bAlter)
3708                 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
3709 
3710             /* WS_CLIPSIBLINGS can't be reset on top-level windows */
3711             if (UserIsDesktopWindow(Window->spwndParent)) Style.styleNew |= WS_CLIPSIBLINGS;
3712             /* WS_MINIMIZE can't be reset */
3713             if (OldValue & WS_MINIMIZE) Style.styleNew |= WS_MINIMIZE;
3714             /* Fixes wine FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change WS_EX_WINDOWEDGE too */
3715             if (IntCheckFrameEdge(NewValue, Window->ExStyle))
3716                Window->ExStyle |= WS_EX_WINDOWEDGE;
3717             else
3718                Window->ExStyle &= ~WS_EX_WINDOWEDGE;
3719 
3720             if ((OldValue & (WS_CHILD | WS_POPUP)) == WS_CHILD)
3721             {
3722                if ((NewValue & (WS_CHILD | WS_POPUP)) != WS_CHILD)
3723                {
3724                   //// From child to non-child it should be null already.
3725                   ERR("IDMenu going null! %d\n",Window->IDMenu);
3726                   Window->IDMenu = 0; // Window->spmenu = 0;
3727                }
3728             }
3729             else
3730             {
3731                if ((NewValue & (WS_CHILD | WS_POPUP)) == WS_CHILD)
3732                {
3733                   PMENU pMenu = UserGetMenuObject(UlongToHandle(Window->IDMenu));
3734                   Window->state &= ~WNDS_HASMENU;
3735                   if (pMenu)
3736                   {
3737                      ERR("IDMenu released 0x%p\n",pMenu);
3738                      // ROS may not hold a lock after setting menu to window. But it should!
3739                      //IntReleaseMenuObject(pMenu);
3740                   }
3741                }
3742             }
3743 
3744             if ((Style.styleOld ^ Style.styleNew) & WS_VISIBLE)
3745             {
3746                if (Style.styleOld & WS_VISIBLE) Window->head.pti->cVisWindows--;
3747                if (Style.styleNew & WS_VISIBLE) Window->head.pti->cVisWindows++;
3748                DceResetActiveDCEs( Window );
3749             }
3750             Window->style = (DWORD)Style.styleNew;
3751 
3752             if (!bAlter)
3753                 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
3754             break;
3755 
3756          case GWLP_WNDPROC: // LONG_PTR
3757          {
3758             if ( Window->head.pti->ppi != PsGetCurrentProcessWin32Process() ||
3759                  Window->fnid & FNID_FREED)
3760             {
3761                EngSetLastError(ERROR_ACCESS_DENIED);
3762                return( 0);
3763             }
3764             OldValue = (LONG_PTR)IntSetWindowProc(Window,
3765                                                   (WNDPROC)NewValue,
3766                                                   Ansi);
3767             break;
3768          }
3769 
3770          case GWLP_HINSTANCE: // LONG_PTR
3771             OldValue = (LONG_PTR) Window->hModule;
3772             Window->hModule = (HINSTANCE) NewValue;
3773             break;
3774 
3775          case GWLP_HWNDPARENT: // LONG_PTR
3776             Parent = Window->spwndParent;
3777             if (Parent && (Parent->head.h == IntGetDesktopWindow()))
3778                OldValue = (LONG_PTR) IntSetOwner(Window->head.h, (HWND) NewValue);
3779             else
3780                OldValue = (LONG_PTR) co_UserSetParent(Window->head.h, (HWND) NewValue);
3781             break;
3782 
3783          case GWLP_ID: // LONG
3784             OldValue = (LONG) Window->IDMenu;
3785             Window->IDMenu = (UINT) NewValue;
3786             break;
3787 
3788          case GWLP_USERDATA: // LONG or LONG_PTR
3789             OldValue = Window->dwUserData;
3790             Window->dwUserData = NewValue;
3791             break;
3792 
3793          default:
3794             ERR("NtUserSetWindowLong(): Unsupported index %lu\n", Index);
3795             EngSetLastError(ERROR_INVALID_INDEX);
3796             OldValue = 0;
3797             break;
3798       }
3799    }
3800 
3801    return( OldValue);
3802 }
3803 
3804 LONG FASTCALL
3805 co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3806 {
3807     return (LONG)co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG), FALSE);
3808 }
3809 
3810 LONG_PTR FASTCALL
3811 co_UserSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi)
3812 {
3813     return co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG_PTR), FALSE);
3814 }
3815 
3816 /*
3817  * NtUserSetWindowLong
3818  *
3819  * The NtUserSetWindowLong function changes an attribute of the specified
3820  * window. The function also sets the 32-bit (long) value at the specified
3821  * offset into the extra window memory.
3822  *
3823  * Status
3824  *    @implemented
3825  */
3826 
3827 LONG APIENTRY
3828 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3829 {
3830    LONG ret;
3831 
3832    UserEnterExclusive();
3833 
3834    if (hWnd == IntGetDesktopWindow())
3835    {
3836       EngSetLastError(STATUS_ACCESS_DENIED);
3837       UserLeave();
3838       return 0;
3839    }
3840 
3841    ret = (LONG)co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG), FALSE);
3842 
3843    UserLeave();
3844 
3845    return ret;
3846 }
3847 
3848 #ifdef _WIN64
3849 LONG_PTR APIENTRY
3850 NtUserSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi)
3851 {
3852     LONG_PTR ret;
3853 
3854     UserEnterExclusive();
3855 
3856     if (hWnd == IntGetDesktopWindow())
3857     {
3858         EngSetLastError(STATUS_ACCESS_DENIED);
3859         UserLeave();
3860         return 0;
3861     }
3862 
3863     ret = co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG_PTR), FALSE);
3864 
3865     UserLeave();
3866 
3867     return ret;
3868 }
3869 #endif // _WIN64
3870 
3871 DWORD APIENTRY
3872 NtUserAlterWindowStyle(HWND hWnd, DWORD Index, LONG NewValue)
3873 {
3874    LONG ret;
3875 
3876    UserEnterExclusive();
3877 
3878    if (hWnd == IntGetDesktopWindow())
3879    {
3880       EngSetLastError(STATUS_ACCESS_DENIED);
3881       UserLeave();
3882       return 0;
3883    }
3884 
3885    ret = co_IntSetWindowLongPtr(hWnd, Index, NewValue, FALSE, sizeof(LONG), TRUE);
3886 
3887    UserLeave();
3888 
3889    return ret;
3890 }
3891 
3892 
3893 /*
3894  * NtUserSetWindowWord
3895  *
3896  * Legacy function similar to NtUserSetWindowLong.
3897  *
3898  * Status
3899  *    @implemented
3900  */
3901 
3902 WORD APIENTRY
3903 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue)
3904 {
3905    PWND Window;
3906    WORD OldValue;
3907    DECLARE_RETURN(WORD);
3908 
3909    TRACE("Enter NtUserSetWindowWord\n");
3910    UserEnterExclusive();
3911 
3912    if (hWnd == IntGetDesktopWindow())
3913    {
3914       EngSetLastError(STATUS_ACCESS_DENIED);
3915       RETURN( 0);
3916    }
3917 
3918    if (!(Window = UserGetWindowObject(hWnd)))
3919    {
3920       RETURN( 0);
3921    }
3922 
3923    switch (Index)
3924    {
3925       case GWL_ID:
3926       case GWL_HINSTANCE:
3927       case GWL_HWNDPARENT:
3928          RETURN( (WORD)co_UserSetWindowLong(UserHMGetHandle(Window), Index, (UINT)NewValue, TRUE));
3929       default:
3930          if (Index < 0)
3931          {
3932             EngSetLastError(ERROR_INVALID_INDEX);
3933             RETURN( 0);
3934          }
3935    }
3936 
3937    if ((ULONG)Index > (Window->cbwndExtra - sizeof(WORD)))
3938    {
3939       EngSetLastError(ERROR_INVALID_PARAMETER);
3940       RETURN( 0);
3941    }
3942 
3943    OldValue = *((WORD *)((PCHAR)(Window + 1) + Index));
3944    *((WORD *)((PCHAR)(Window + 1) + Index)) = NewValue;
3945 
3946    RETURN( OldValue);
3947 
3948 CLEANUP:
3949    TRACE("Leave NtUserSetWindowWord, ret=%u\n", _ret_);
3950    UserLeave();
3951    END_CLEANUP;
3952 }
3953 
3954 /*
3955  QueryWindow based on KJK::Hyperion and James Tabor.
3956 
3957  0 = QWUniqueProcessId
3958  1 = QWUniqueThreadId
3959  2 = QWActiveWindow
3960  3 = QWFocusWindow
3961  4 = QWIsHung            Implements IsHungAppWindow found
3962                                 by KJK::Hyperion.
3963 
3964  9 = QWKillWindow        When I called this with hWnd ==
3965                            DesktopWindow, it shutdown the system
3966                            and rebooted.
3967 */
3968 /*
3969  * @implemented
3970  */
3971 DWORD_PTR APIENTRY
3972 NtUserQueryWindow(HWND hWnd, DWORD Index)
3973 {
3974 /* Console Leader Process CID Window offsets */
3975 #define GWLP_CONSOLE_LEADER_PID 0
3976 #define GWLP_CONSOLE_LEADER_TID 4
3977 
3978    PWND pWnd;
3979    DWORD_PTR Result;
3980    DECLARE_RETURN(UINT);
3981 
3982    TRACE("Enter NtUserQueryWindow\n");
3983    UserEnterShared();
3984 
3985    if (!(pWnd = UserGetWindowObject(hWnd)))
3986    {
3987       RETURN( 0);
3988    }
3989 
3990    switch(Index)
3991    {
3992       case QUERY_WINDOW_UNIQUE_PROCESS_ID:
3993       {
3994          if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
3995               (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) )
3996          {
3997             // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_PID)
3998             Result = (DWORD_PTR)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_PID)));
3999          }
4000          else
4001          {
4002             Result = (DWORD_PTR)IntGetWndProcessId(pWnd);
4003          }
4004          break;
4005       }
4006 
4007       case QUERY_WINDOW_UNIQUE_THREAD_ID:
4008       {
4009          if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
4010               (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) )
4011          {
4012             // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_TID)
4013             Result = (DWORD_PTR)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_TID)));
4014          }
4015          else
4016          {
4017             Result = (DWORD_PTR)IntGetWndThreadId(pWnd);
4018          }
4019          break;
4020       }
4021 
4022       case QUERY_WINDOW_ACTIVE:
4023          Result = (DWORD_PTR)(pWnd->head.pti->MessageQueue->spwndActive ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndActive) : 0);
4024          break;
4025 
4026       case QUERY_WINDOW_FOCUS:
4027          Result = (DWORD_PTR)(pWnd->head.pti->MessageQueue->spwndFocus ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndFocus) : 0);
4028          break;
4029 
4030       case QUERY_WINDOW_ISHUNG:
4031          Result = (DWORD_PTR)MsqIsHung(pWnd->head.pti);
4032          break;
4033 
4034       case QUERY_WINDOW_REAL_ID:
4035          Result = (DWORD_PTR)pWnd->head.pti->pEThread->Cid.UniqueProcess;
4036          break;
4037 
4038       case QUERY_WINDOW_FOREGROUND:
4039          Result = (pWnd->head.pti->MessageQueue == gpqForeground);
4040          break;
4041 
4042       default:
4043          Result = 0;
4044          break;
4045    }
4046 
4047    RETURN( Result);
4048 
4049 CLEANUP:
4050    TRACE("Leave NtUserQueryWindow, ret=%u\n", _ret_);
4051    UserLeave();
4052    END_CLEANUP;
4053 }
4054 
4055 /*
4056  * @implemented
4057  */
4058 UINT APIENTRY
4059 NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe)
4060 {
4061    UNICODE_STRING SafeMessageName;
4062    NTSTATUS Status;
4063    UINT Ret;
4064    DECLARE_RETURN(UINT);
4065 
4066    TRACE("Enter NtUserRegisterWindowMessage\n");
4067    UserEnterExclusive();
4068 
4069    if(MessageNameUnsafe == NULL)
4070    {
4071       EngSetLastError(ERROR_INVALID_PARAMETER);
4072       RETURN( 0);
4073    }
4074 
4075    Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe);
4076    if(!NT_SUCCESS(Status))
4077    {
4078       SetLastNtError(Status);
4079       RETURN( 0);
4080    }
4081 
4082    Ret = (UINT)IntAddAtom(SafeMessageName.Buffer);
4083    if (SafeMessageName.Buffer)
4084       ExFreePoolWithTag(SafeMessageName.Buffer, TAG_STRING);
4085    RETURN( Ret);
4086 
4087 CLEANUP:
4088    TRACE("Leave NtUserRegisterWindowMessage, ret=%u\n", _ret_);
4089    UserLeave();
4090    END_CLEANUP;
4091 }
4092 
4093 /*
4094  * @implemented
4095  */
4096 BOOL APIENTRY
4097 NtUserSetWindowFNID(HWND hWnd,
4098                     WORD fnID)
4099 {
4100    PWND Wnd;
4101    DECLARE_RETURN(BOOL);
4102 
4103    TRACE("Enter NtUserSetWindowFNID\n");
4104    UserEnterExclusive();
4105 
4106    if (!(Wnd = UserGetWindowObject(hWnd)))
4107    {
4108       RETURN( FALSE);
4109    }
4110 
4111    if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
4112    {
4113       EngSetLastError(ERROR_ACCESS_DENIED);
4114       RETURN( FALSE);
4115    }
4116 
4117    // From user land we only set these.
4118    if (fnID != FNID_DESTROY)
4119    {
4120       /* HACK: The minimum should be FNID_BUTTON, but menu code relies on this */
4121       if (fnID < FNID_FIRST || fnID > FNID_GHOST ||
4122           Wnd->fnid != 0)
4123       {
4124          EngSetLastError(ERROR_INVALID_PARAMETER);
4125          RETURN( FALSE);
4126       }
4127    }
4128 
4129    Wnd->fnid |= fnID;
4130    RETURN( TRUE);
4131 
4132 CLEANUP:
4133    TRACE("Leave NtUserSetWindowFNID\n");
4134    UserLeave();
4135    END_CLEANUP;
4136 }
4137 
4138 BOOL APIENTRY
4139 DefSetText(PWND Wnd, PCWSTR WindowText)
4140 {
4141    UNICODE_STRING UnicodeString;
4142    BOOL Ret = FALSE;
4143 
4144    RtlInitUnicodeString(&UnicodeString, WindowText);
4145 
4146    if (UnicodeString.Length != 0)
4147    {
4148       if (Wnd->strName.MaximumLength > 0 &&
4149           UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
4150       {
4151          ASSERT(Wnd->strName.Buffer != NULL);
4152 
4153          Wnd->strName.Length = UnicodeString.Length;
4154          Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4155          RtlCopyMemory(Wnd->strName.Buffer,
4156                               UnicodeString.Buffer,
4157                               UnicodeString.Length);
4158       }
4159       else
4160       {
4161          PWCHAR buf;
4162          Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4163          buf = Wnd->strName.Buffer;
4164          Wnd->strName.Buffer = NULL;
4165          if (buf != NULL)
4166          {
4167             DesktopHeapFree(Wnd->head.rpdesk, buf);
4168          }
4169 
4170          Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
4171                                                    UnicodeString.Length + sizeof(UNICODE_NULL));
4172          if (Wnd->strName.Buffer != NULL)
4173          {
4174             Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4175             RtlCopyMemory(Wnd->strName.Buffer,
4176                                  UnicodeString.Buffer,
4177                                  UnicodeString.Length);
4178             Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4179             Wnd->strName.Length = UnicodeString.Length;
4180          }
4181          else
4182          {
4183             EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4184             goto Exit;
4185          }
4186       }
4187    }
4188    else
4189    {
4190       Wnd->strName.Length = 0;
4191       if (Wnd->strName.Buffer != NULL)
4192           Wnd->strName.Buffer[0] = L'\0';
4193    }
4194 
4195    // FIXME: HAX! Windows does not do this in here!
4196    // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4197    // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4198    /* Send shell notifications */
4199    if (!Wnd->spwndOwner && !IntGetParent(Wnd))
4200    {
4201       co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) UserHMGetHandle(Wnd), FALSE); // FIXME Flashing?
4202    }
4203 
4204    Ret = TRUE;
4205 Exit:
4206    if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
4207    return Ret;
4208 }
4209 
4210 /*
4211  * NtUserDefSetText
4212  *
4213  * Undocumented function that is called from DefWindowProc to set
4214  * window text.
4215  *
4216  * Status
4217  *    @implemented
4218  */
4219 BOOL APIENTRY
4220 NtUserDefSetText(HWND hWnd, PLARGE_STRING WindowText)
4221 {
4222    PWND Wnd;
4223    LARGE_STRING SafeText;
4224    UNICODE_STRING UnicodeString;
4225    BOOL Ret = TRUE;
4226 
4227    TRACE("Enter NtUserDefSetText\n");
4228 
4229    if (WindowText != NULL)
4230    {
4231       _SEH2_TRY
4232       {
4233          SafeText = ProbeForReadLargeString(WindowText);
4234       }
4235       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4236       {
4237          Ret = FALSE;
4238          SetLastNtError(_SEH2_GetExceptionCode());
4239       }
4240       _SEH2_END;
4241 
4242       if (!Ret)
4243          return FALSE;
4244    }
4245    else
4246       return TRUE;
4247 
4248    UserEnterExclusive();
4249 
4250    if(!(Wnd = UserGetWindowObject(hWnd)))
4251    {
4252       UserLeave();
4253       return FALSE;
4254    }
4255 
4256    // ReactOS uses Unicode and not mixed. Up/Down converting will take time.
4257    // Brought to you by: The Wine Project! Dysfunctional Thought Processes!
4258    // Now we know what the bAnsi is for.
4259    RtlInitUnicodeString(&UnicodeString, NULL);
4260    if (SafeText.Buffer)
4261    {
4262       _SEH2_TRY
4263       {
4264          if (SafeText.bAnsi)
4265             ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(CHAR));
4266          else
4267             ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(WCHAR));
4268          Ret = RtlLargeStringToUnicodeString(&UnicodeString, &SafeText);
4269       }
4270       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4271       {
4272          Ret = FALSE;
4273          SetLastNtError(_SEH2_GetExceptionCode());
4274       }
4275       _SEH2_END;
4276       if (!Ret) goto Exit;
4277    }
4278 
4279    if (UnicodeString.Length != 0)
4280    {
4281       if (Wnd->strName.MaximumLength > 0 &&
4282           UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
4283       {
4284          ASSERT(Wnd->strName.Buffer != NULL);
4285 
4286          Wnd->strName.Length = UnicodeString.Length;
4287          Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4288          RtlCopyMemory(Wnd->strName.Buffer,
4289                               UnicodeString.Buffer,
4290                               UnicodeString.Length);
4291       }
4292       else
4293       {
4294          PWCHAR buf;
4295          Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4296          buf = Wnd->strName.Buffer;
4297          Wnd->strName.Buffer = NULL;
4298          if (buf != NULL)
4299          {
4300             DesktopHeapFree(Wnd->head.rpdesk, buf);
4301          }
4302 
4303          Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
4304                                                    UnicodeString.Length + sizeof(UNICODE_NULL));
4305          if (Wnd->strName.Buffer != NULL)
4306          {
4307             Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4308             RtlCopyMemory(Wnd->strName.Buffer,
4309                                  UnicodeString.Buffer,
4310                                  UnicodeString.Length);
4311             Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4312             Wnd->strName.Length = UnicodeString.Length;
4313          }
4314          else
4315          {
4316             EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4317             Ret = FALSE;
4318             goto Exit;
4319          }
4320       }
4321    }
4322    else
4323    {
4324       Wnd->strName.Length = 0;
4325       if (Wnd->strName.Buffer != NULL)
4326           Wnd->strName.Buffer[0] = L'\0';
4327    }
4328 
4329    // FIXME: HAX! Windows does not do this in here!
4330    // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4331    // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4332    /* Send shell notifications */
4333    if (!Wnd->spwndOwner && !IntGetParent(Wnd))
4334    {
4335       co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) hWnd, FALSE); // FIXME Flashing?
4336    }
4337 
4338    Ret = TRUE;
4339 Exit:
4340    if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
4341    TRACE("Leave NtUserDefSetText, ret=%i\n", Ret);
4342    UserLeave();
4343    return Ret;
4344 }
4345 
4346 /*
4347  * NtUserInternalGetWindowText
4348  *
4349  * Status
4350  *    @implemented
4351  */
4352 
4353 INT APIENTRY
4354 NtUserInternalGetWindowText(HWND hWnd, LPWSTR lpString, INT nMaxCount)
4355 {
4356    PWND Wnd;
4357    NTSTATUS Status;
4358    INT Result;
4359    DECLARE_RETURN(INT);
4360 
4361    TRACE("Enter NtUserInternalGetWindowText\n");
4362    UserEnterShared();
4363 
4364    if(lpString && (nMaxCount <= 1))
4365    {
4366       EngSetLastError(ERROR_INVALID_PARAMETER);
4367       RETURN( 0);
4368    }
4369 
4370    if(!(Wnd = UserGetWindowObject(hWnd)))
4371    {
4372       RETURN( 0);
4373    }
4374 
4375    Result = Wnd->strName.Length / sizeof(WCHAR);
4376    if(lpString)
4377    {
4378       const WCHAR Terminator = L'\0';
4379       INT Copy;
4380       WCHAR *Buffer = (WCHAR*)lpString;
4381 
4382       Copy = min(nMaxCount - 1, Result);
4383       if(Copy > 0)
4384       {
4385          Status = MmCopyToCaller(Buffer, Wnd->strName.Buffer, Copy * sizeof(WCHAR));
4386          if(!NT_SUCCESS(Status))
4387          {
4388             SetLastNtError(Status);
4389             RETURN( 0);
4390          }
4391          Buffer += Copy;
4392       }
4393 
4394       Status = MmCopyToCaller(Buffer, &Terminator, sizeof(WCHAR));
4395       if(!NT_SUCCESS(Status))
4396       {
4397          SetLastNtError(Status);
4398          RETURN( 0);
4399       }
4400 
4401       Result = Copy;
4402    }
4403 
4404    RETURN( Result);
4405 
4406 CLEANUP:
4407    TRACE("Leave NtUserInternalGetWindowText, ret=%i\n",_ret_);
4408    UserLeave();
4409    END_CLEANUP;
4410 }
4411 
4412 /*
4413   API Call
4414 */
4415 BOOL
4416 FASTCALL
4417 IntShowOwnedPopups(PWND OwnerWnd, BOOL fShow )
4418 {
4419    int count = 0;
4420    PWND pWnd;
4421    HWND *win_array;
4422 
4423 //   ASSERT(OwnerWnd);
4424 
4425    TRACE("Enter ShowOwnedPopups Show: %s\n", (fShow ? "TRUE" : "FALSE"));
4426 
4427    /* NOTE: Popups are not children */
4428    win_array = IntWinListOwnedPopups(OwnerWnd);
4429 
4430    if (!win_array)
4431       return TRUE;
4432 
4433    while (win_array[count])
4434       count++;
4435    while (--count >= 0)
4436    {
4437       if (!(pWnd = ValidateHwndNoErr( win_array[count] )))
4438          continue;
4439       if (pWnd->spwndOwner != OwnerWnd)
4440          continue;
4441 
4442       if (fShow)
4443       {
4444          if (pWnd->state & WNDS_HIDDENPOPUP)
4445          {
4446             /* In Windows, ShowOwnedPopups(TRUE) generates
4447              * WM_SHOWWINDOW messages with SW_PARENTOPENING,
4448              * regardless of the state of the owner
4449              */
4450             co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
4451             pWnd->state &= ~WNDS_HIDDENPOPUP;
4452             continue;
4453          }
4454       }
4455       else
4456       {
4457          if (pWnd->style & WS_VISIBLE)
4458          {
4459             /* In Windows, ShowOwnedPopups(FALSE) generates
4460              * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
4461              * regardless of the state of the owner
4462              */
4463             co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
4464             pWnd->state |= WNDS_HIDDENPOPUP;
4465             continue;
4466          }
4467       }
4468    }
4469    ExFreePoolWithTag(win_array, USERTAG_WINDOWLIST);
4470    TRACE("Leave ShowOwnedPopups\n");
4471    return TRUE;
4472 }
4473 
4474 /* EOF */
4475