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