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