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