2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
5 * FILE: subsystems/win32/win32k/ntuser/window.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
10 DBG_DEFAULT_CHANNEL(UserWnd
);
12 INT gNestedWindowLimit
= 50;
14 /* HELPER FUNCTIONS ***********************************************************/
16 BOOL FASTCALL
UserUpdateUiState(PWND Wnd
, WPARAM wParam
)
18 WORD Action
= LOWORD(wParam
);
19 WORD Flags
= HIWORD(wParam
);
21 if (Flags
& ~(UISF_HIDEFOCUS
| UISF_HIDEACCEL
| UISF_ACTIVE
))
23 EngSetLastError(ERROR_INVALID_PARAMETER
);
30 EngSetLastError(ERROR_INVALID_PARAMETER
);
34 if (Flags
& UISF_HIDEFOCUS
)
35 Wnd
->HideFocus
= TRUE
;
36 if (Flags
& UISF_HIDEACCEL
)
37 Wnd
->HideAccel
= TRUE
;
41 if (Flags
& UISF_HIDEFOCUS
)
42 Wnd
->HideFocus
= FALSE
;
43 if (Flags
& UISF_HIDEACCEL
)
44 Wnd
->HideAccel
= FALSE
;
51 PWND FASTCALL
IntGetWindowObject(HWND hWnd
)
55 if (!hWnd
) return NULL
;
57 Window
= UserGetWindowObject(hWnd
);
59 Window
->head
.cLockObj
++;
64 PWND FASTCALL
VerifyWnd(PWND pWnd
)
69 if (!pWnd
) return NULL
;
73 hWnd
= UserHMGetHandle(pWnd
);
75 State2
= pWnd
->state2
;
77 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
79 _SEH2_YIELD(return NULL
);
83 if ( UserObjectInDestroy(hWnd
) ||
84 State
& WNDS_DESTROYED
||
85 State2
& WNDS2_INDESTROY
)
91 PWND FASTCALL
ValidateHwndNoErr(HWND hWnd
)
93 if (hWnd
) return (PWND
)UserGetObjectNoErr(gHandleTable
, hWnd
, TYPE_WINDOW
);
98 PWND FASTCALL
UserGetWindowObject(HWND hWnd
)
104 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
108 Window
= (PWND
)UserGetObject(gHandleTable
, hWnd
, TYPE_WINDOW
);
109 if (!Window
|| 0 != (Window
->state
& WNDS_DESTROYED
))
111 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
119 IntSetStyle( PWND pwnd
, ULONG set_bits
, ULONG clear_bits
)
121 ULONG styleOld
, styleNew
;
122 styleOld
= pwnd
->style
;
123 styleNew
= (pwnd
->style
| set_bits
) & ~clear_bits
;
124 if (styleNew
== styleOld
) return styleNew
;
125 pwnd
->style
= styleNew
;
126 if ((styleOld
^ styleNew
) & WS_VISIBLE
) DceResetActiveDCEs( pwnd
);
133 * The function determines whether the specified window handle identifies
134 * an existing window.
138 * Handle to the window to test.
141 * If the window handle identifies an existing window, the return value
142 * is TRUE. If the window handle does not identify an existing window,
143 * the return value is FALSE.
147 IntIsWindow(HWND hWnd
)
151 if (!(Window
= UserGetWindowObject(hWnd
)))
160 IntIsWindowVisible(PWND Wnd
)
165 if (!(Wnd
->style
& WS_VISIBLE
))
170 if (Wnd
->spwndParent
!= NULL
)
171 Wnd
= Wnd
->spwndParent
;
180 IntGetParent(PWND Wnd
)
182 if (Wnd
->style
& WS_POPUP
)
184 return Wnd
->spwndOwner
;
186 else if (Wnd
->style
& WS_CHILD
)
188 return Wnd
->spwndParent
;
196 IntEnableWindow( HWND hWnd
, BOOL bEnable
)
202 if(!(pWnd
= UserGetWindowObject(hWnd
)))
207 /* check if updating is needed */
208 bIsDisabled
= !!(pWnd
->style
& WS_DISABLED
);
209 Update
= bIsDisabled
;
213 IntSetStyle( pWnd
, 0, WS_DISABLED
);
217 Update
= !bIsDisabled
;
219 co_IntSendMessage( hWnd
, WM_CANCELMODE
, 0, 0);
221 /* Remove keyboard focus from that window if it had focus */
222 if (hWnd
== IntGetThreadFocusWindow())
224 TRACE("IntEnableWindow SF NULL\n");
225 co_UserSetFocus(NULL
);
227 IntSetStyle( pWnd
, WS_DISABLED
, 0 );
232 IntNotifyWinEvent(EVENT_OBJECT_STATECHANGE
, pWnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
233 co_IntSendMessage(hWnd
, WM_ENABLE
, (LPARAM
)bEnable
, 0);
235 // Return nonzero if it was disabled, or zero if it wasn't:
242 * Compile a list of all child window handles from given window.
245 * This function is similar to Wine WIN_ListChildren. The caller
246 * must free the returned list with ExFreePool.
250 IntWinListChildren(PWND Window
)
254 UINT Index
, NumChildren
= 0;
256 if (!Window
) return NULL
;
258 for (Child
= Window
->spwndChild
; Child
; Child
= Child
->spwndNext
)
261 List
= ExAllocatePoolWithTag(PagedPool
, (NumChildren
+ 1) * sizeof(HWND
), USERTAG_WINDOWLIST
);
264 ERR("Failed to allocate memory for children array\n");
265 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
268 for (Child
= Window
->spwndChild
, Index
= 0;
270 Child
= Child
->spwndNext
, ++Index
)
271 List
[Index
] = Child
->head
.h
;
278 IntGetNonChildAncestor(PWND pWnd
)
282 while(pWnd
&& ((pWnd
->style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
))
283 pWnd
= pWnd
->spwndParent
;
289 IntIsTopLevelWindow(PWND pWnd
)
291 if ( pWnd
->spwndParent
&&
292 pWnd
->spwndParent
== co_GetDesktopWindow(pWnd
) ) return TRUE
;
297 IntValidateOwnerDepth(PWND Wnd
, PWND Owner
)
302 if ( !Owner
) return gNestedWindowLimit
>= Depth
;
303 if (Owner
== Wnd
) break;
304 Owner
= Owner
->spwndOwner
;
310 /***********************************************************************
313 static void IntSendDestroyMsg(HWND hWnd
)
321 if (GetGUIThreadInfo(GetCurrentThreadId(), &info
))
323 if (hWnd
== info
.hwndCaret
)
330 Window
= UserGetWindowObject(hWnd
);
333 // USER_REFERENCE_ENTRY Ref;
334 // UserRefObjectCo(Window, &Ref);
336 if (!Window
->spwndOwner
&& !IntGetParent(Window
))
338 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED
, (WPARAM
) hWnd
, 0);
341 // UserDerefObjectCo(Window);
344 /* The window could already be destroyed here */
347 * Send the WM_DESTROY to the window.
350 co_IntSendMessage(hWnd
, WM_DESTROY
, 0, 0);
353 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
354 * make sure that the window still exists when we come back.
363 if (!(pWndArray
= WIN_ListChildren( hwnd
)))
366 /* start from the end (FIXME: is this needed?) */
367 for (i
= 0; pWndArray
[i
]; i
++)
372 if (IsWindow( pWndArray
[i
] ))
373 WIN_SendDestroyMsg( pWndArray
[i
] );
375 HeapFree(GetProcessHeap(), 0, pWndArray
);
379 TRACE("destroyed itself while in WM_DESTROY!\n");
385 UserFreeWindowInfo(PTHREADINFO ti
, PWND Wnd
)
387 PCLIENTINFO ClientInfo
= GetWin32ClientInfo();
391 if (ClientInfo
->CallbackWnd
.pWnd
== DesktopHeapAddressToUser(Wnd
))
393 ClientInfo
->CallbackWnd
.hWnd
= NULL
;
394 ClientInfo
->CallbackWnd
.pWnd
= NULL
;
397 if (Wnd
->strName
.Buffer
!= NULL
)
399 Wnd
->strName
.Length
= 0;
400 Wnd
->strName
.MaximumLength
= 0;
401 DesktopHeapFree(Wnd
->head
.rpdesk
,
402 Wnd
->strName
.Buffer
);
403 Wnd
->strName
.Buffer
= NULL
;
406 // DesktopHeapFree(Wnd->head.rpdesk, Wnd);
407 // WindowObject->Wnd = NULL;
410 /***********************************************************************
413 * Destroy storage associated to a window. "Internals" p.358
415 * This is the "functional" DestroyWindows function ei. all stuff
416 * done in CreateWindow is undone here and not in DestroyWindow:-P
419 static LRESULT
co_UserFreeWindow(PWND Window
,
420 PPROCESSINFO ProcessData
,
421 PTHREADINFO ThreadData
,
422 BOOLEAN SendMessages
)
428 BOOLEAN BelongsToThreadData
;
432 if(Window
->state2
& WNDS2_INDESTROY
)
434 TRACE("Tried to call IntDestroyWindow() twice\n");
437 Window
->state2
|= WNDS2_INDESTROY
;
438 Window
->style
&= ~WS_VISIBLE
;
440 IntNotifyWinEvent(EVENT_OBJECT_DESTROY
, Window
, OBJID_WINDOW
, CHILDID_SELF
, 0);
442 /* remove the window already at this point from the thread window list so we
443 don't get into trouble when destroying the thread windows while we're still
444 in IntDestroyWindow() */
445 RemoveEntryList(&Window
->ThreadListEntry
);
447 BelongsToThreadData
= IntWndBelongsToThread(Window
, ThreadData
);
449 IntDeRegisterShellHookWindow(Window
->head
.h
);
453 /* Send destroy messages */
454 IntSendDestroyMsg(Window
->head
.h
);
457 /* free child windows */
458 Children
= IntWinListChildren(Window
);
461 for (ChildHandle
= Children
; *ChildHandle
; ++ChildHandle
)
463 if ((Child
= IntGetWindowObject(*ChildHandle
)))
465 if(!IntWndBelongsToThread(Child
, ThreadData
))
467 /* send WM_DESTROY messages to windows not belonging to the same thread */
468 IntSendDestroyMsg(Child
->head
.h
);
471 co_UserFreeWindow(Child
, ProcessData
, ThreadData
, SendMessages
);
473 UserDereferenceObject(Child
);
476 ExFreePoolWithTag(Children
, USERTAG_WINDOWLIST
);
482 * Clear the update region to make sure no WM_PAINT messages will be
483 * generated for this window while processing the WM_NCDESTROY.
485 co_UserRedrawWindow(Window
, NULL
, 0,
486 RDW_VALIDATE
| RDW_NOFRAME
| RDW_NOERASE
|
487 RDW_NOINTERNALPAINT
| RDW_NOCHILDREN
);
488 if(BelongsToThreadData
)
489 co_IntSendMessage(Window
->head
.h
, WM_NCDESTROY
, 0, 0);
492 DestroyTimersForWindow(ThreadData
, Window
);
494 /* Unregister hot keys */
495 UnregisterWindowHotKeys (Window
);
497 /* flush the message queue */
498 MsqRemoveWindowMessagesFromQueue(Window
);
500 NT_ASSERT(Window
->head
.pti
);
501 IntDereferenceMessageQueue(Window
->head
.pti
->MessageQueue
);
503 /* from now on no messages can be sent to this window anymore */
504 Window
->state
|= WNDS_DESTROYED
;
505 Window
->fnid
|= FNID_FREED
;
507 /* don't remove the WINDOWSTATUS_DESTROYING bit */
509 /* reset shell window handles */
510 if(ThreadData
->rpdesk
)
512 if (Window
->head
.h
== ThreadData
->rpdesk
->rpwinstaParent
->ShellWindow
)
513 ThreadData
->rpdesk
->rpwinstaParent
->ShellWindow
= NULL
;
515 if (Window
->head
.h
== ThreadData
->rpdesk
->rpwinstaParent
->ShellListView
)
516 ThreadData
->rpdesk
->rpwinstaParent
->ShellListView
= NULL
;
519 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
523 WinPosCheckInternalPos(Window
->head
.h
);
524 if (Window
->head
.h
== GetCapture())
529 /* free resources associated with the window */
530 TIMER_RemoveWindowTimers(Window
->head
.h
);
533 if ( ((Window
->style
& (WS_CHILD
|WS_POPUP
)) != WS_CHILD
) &&
535 (Menu
= UserGetMenuObject((HMENU
)Window
->IDMenu
)))
537 IntDestroyMenuObject(Menu
, TRUE
, TRUE
);
541 if(Window
->SystemMenu
542 && (Menu
= UserGetMenuObject(Window
->SystemMenu
)))
544 IntDestroyMenuObject(Menu
, TRUE
, TRUE
);
545 Window
->SystemMenu
= (HMENU
)0;
548 DceFreeWindowDCE(Window
); /* Always do this to catch orphaned DCs */
551 WINPROC_FreeProc(Window
->winproc
, WIN_PROC_WINDOW
);
552 CLASS_RemoveWindow(Window
->Class
);
555 IntUnlinkWindow(Window
);
557 UserReferenceObject(Window
);
558 UserDeleteObject(Window
->head
.h
, TYPE_WINDOW
);
560 IntDestroyScrollBars(Window
);
562 /* dereference the class */
563 IntDereferenceClass(Window
->pcls
,
564 Window
->head
.pti
->pDeskInfo
,
565 Window
->head
.pti
->ppi
);
570 IntGdiSetRegionOwner(Window
->hrgnClip
, GDI_OBJ_HMGR_POWNED
);
571 GreDeleteObject(Window
->hrgnClip
);
572 Window
->hrgnClip
= NULL
;
575 // ASSERT(Window != NULL);
576 UserFreeWindowInfo(Window
->head
.pti
, Window
);
578 UserDereferenceObject(Window
);
580 UserClipboardFreeWindow(Window
);
586 // Same as User32:IntGetWndProc.
589 IntGetWindowProc(PWND pWnd
,
594 WNDPROC gcpd
, Ret
= 0;
596 ASSERT(UserIsEnteredExclusive() == TRUE
);
600 if (pWnd
->state
& WNDS_SERVERSIDEWINDOWPROC
)
602 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
604 if (GETPFNSERVER(i
) == pWnd
->lpfnWndProc
)
607 Ret
= GETPFNCLIENTA(i
);
609 Ret
= GETPFNCLIENTW(i
);
615 if (Class
->fnid
== FNID_EDIT
)
616 Ret
= pWnd
->lpfnWndProc
;
619 Ret
= pWnd
->lpfnWndProc
;
621 if (Class
->fnid
<= FNID_GHOST
&& Class
->fnid
>= FNID_BUTTON
)
625 if (GETPFNCLIENTW(Class
->fnid
) == pWnd
->lpfnWndProc
)
626 Ret
= GETPFNCLIENTA(Class
->fnid
);
630 if (GETPFNCLIENTA(Class
->fnid
) == pWnd
->lpfnWndProc
)
631 Ret
= GETPFNCLIENTW(Class
->fnid
);
634 if ( Ret
!= pWnd
->lpfnWndProc
)
637 if ( Ansi
== !!(pWnd
->state
& WNDS_ANSIWINDOWPROC
) )
640 gcpd
= (WNDPROC
)UserGetCPD(
642 (Ansi
? UserGetCPDA2U
: UserGetCPDU2A
)|UserGetCPDWindow
,
645 return (gcpd
? gcpd
: Ret
);
649 IntSetWindowProc(PWND pWnd
,
654 PCALLPROCDATA CallProc
;
656 WNDPROC Ret
, chWndProc
= NULL
;
658 // Retrieve previous window proc.
659 Ret
= IntGetWindowProc(pWnd
, Ansi
);
663 if (IsCallProcHandle(NewWndProc
))
665 CallProc
= UserGetObject(gHandleTable
, NewWndProc
, TYPE_CALLPROC
);
667 { // Reset new WndProc.
668 NewWndProc
= CallProc
->pfnClientPrevious
;
669 // Reset Ansi from CallProc handle. This is expected with wine "deftest".
670 Ansi
= !!(CallProc
->wType
& UserGetCPDU2A
);
673 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
674 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
676 if (GETPFNCLIENTW(i
) == NewWndProc
)
678 chWndProc
= GETPFNSERVER(i
);
681 if (GETPFNCLIENTA(i
) == NewWndProc
)
683 chWndProc
= GETPFNSERVER(i
);
687 // If match, set/reset to Server Side and clear ansi.
690 pWnd
->lpfnWndProc
= chWndProc
;
691 pWnd
->Unicode
= TRUE
;
692 pWnd
->state
&= ~WNDS_ANSIWINDOWPROC
;
693 pWnd
->state
|= WNDS_SERVERSIDEWINDOWPROC
;
697 pWnd
->Unicode
= !Ansi
;
698 // Handle the state change in here.
700 pWnd
->state
|= WNDS_ANSIWINDOWPROC
;
702 pWnd
->state
&= ~WNDS_ANSIWINDOWPROC
;
704 if (pWnd
->state
& WNDS_SERVERSIDEWINDOWPROC
)
705 pWnd
->state
&= ~WNDS_SERVERSIDEWINDOWPROC
;
707 if (!NewWndProc
) NewWndProc
= pWnd
->lpfnWndProc
;
709 if (Class
->fnid
<= FNID_GHOST
&& Class
->fnid
>= FNID_BUTTON
)
713 if (GETPFNCLIENTW(Class
->fnid
) == NewWndProc
)
714 chWndProc
= GETPFNCLIENTA(Class
->fnid
);
718 if (GETPFNCLIENTA(Class
->fnid
) == NewWndProc
)
719 chWndProc
= GETPFNCLIENTW(Class
->fnid
);
722 // Now set the new window proc.
723 pWnd
->lpfnWndProc
= (chWndProc
? chWndProc
: NewWndProc
);
734 PMENU_OBJECT OldMenu
, NewMenu
= NULL
;
736 if ((Wnd
->style
& (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
738 ERR("SetMenu: Invalid handle 0x%p!\n",UserHMGetHandle(Wnd
));
739 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
743 *Changed
= (Wnd
->IDMenu
!= (UINT
) Menu
);
751 OldMenu
= IntGetMenuObject((HMENU
) Wnd
->IDMenu
);
752 ASSERT(NULL
== OldMenu
|| OldMenu
->MenuInfo
.Wnd
== Wnd
->head
.h
);
761 NewMenu
= IntGetMenuObject(Menu
);
766 IntReleaseMenuObject(OldMenu
);
768 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
771 if (NULL
!= NewMenu
->MenuInfo
.Wnd
)
773 /* Can't use the same menu for two windows */
776 IntReleaseMenuObject(OldMenu
);
778 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
784 Wnd
->IDMenu
= (UINT
) Menu
;
787 NewMenu
->MenuInfo
.Wnd
= Wnd
->head
.h
;
788 IntReleaseMenuObject(NewMenu
);
792 OldMenu
->MenuInfo
.Wnd
= NULL
;
793 IntReleaseMenuObject(OldMenu
);
800 /* INTERNAL ******************************************************************/
804 co_DestroyThreadWindows(struct _ETHREAD
*Thread
)
809 USER_REFERENCE_ENTRY Ref
;
810 WThread
= (PTHREADINFO
)Thread
->Tcb
.Win32Thread
;
812 while (!IsListEmpty(&WThread
->WindowListHead
))
814 Current
= WThread
->WindowListHead
.Flink
;
815 Wnd
= CONTAINING_RECORD(Current
, WND
, ThreadListEntry
);
817 TRACE("thread cleanup: while destroy wnds, wnd=0x%x\n",Wnd
);
819 /* Window removes itself from the list */
822 * FIXME: It is critical that the window removes itself! If now, we will loop
826 //ASSERT(co_UserDestroyWindow(Wnd));
828 UserRefObjectCo(Wnd
, &Ref
); // FIXME: Temp HACK??
829 if (!co_UserDestroyWindow(Wnd
))
831 ERR("Unable to destroy window 0x%x at thread cleanup... This is _VERY_ bad!\n", Wnd
);
833 UserDerefObjectCo(Wnd
); // FIXME: Temp HACK??
837 PMENU_OBJECT FASTCALL
838 IntGetSystemMenu(PWND Window
, BOOL bRevert
, BOOL RetMenu
)
840 PMENU_OBJECT Menu
, NewMenu
= NULL
, SysMenu
= NULL
, ret
= NULL
;
841 PTHREADINFO W32Thread
;
842 HMENU hNewMenu
, hSysMenu
;
843 ROSMENUITEMINFO ItemInfo
;
847 W32Thread
= PsGetCurrentThreadWin32Thread();
849 if(!W32Thread
->rpdesk
)
852 if(Window
->SystemMenu
)
854 Menu
= UserGetMenuObject(Window
->SystemMenu
);
857 IntDestroyMenuObject(Menu
, TRUE
, TRUE
);
858 Window
->SystemMenu
= (HMENU
)0;
862 if(W32Thread
->rpdesk
->rpwinstaParent
->SystemMenuTemplate
)
864 /* Clone system menu */
865 Menu
= UserGetMenuObject(W32Thread
->rpdesk
->rpwinstaParent
->SystemMenuTemplate
);
869 NewMenu
= IntCloneMenu(Menu
);
872 Window
->SystemMenu
= NewMenu
->MenuInfo
.Self
;
873 NewMenu
->MenuInfo
.Flags
|= MF_SYSMENU
;
874 NewMenu
->MenuInfo
.Wnd
= Window
->head
.h
;
876 //IntReleaseMenuObject(NewMenu);
881 hSysMenu
= UserCreateMenu(FALSE
);
882 if (NULL
== hSysMenu
)
886 SysMenu
= IntGetMenuObject(hSysMenu
);
889 UserDestroyMenu(hSysMenu
);
892 SysMenu
->MenuInfo
.Flags
|= MF_SYSMENU
;
893 SysMenu
->MenuInfo
.Wnd
= Window
->head
.h
;
894 hNewMenu
= co_IntLoadSysMenuTemplate();
897 IntReleaseMenuObject(SysMenu
);
898 UserDestroyMenu(hSysMenu
);
901 Menu
= IntGetMenuObject(hNewMenu
);
904 IntReleaseMenuObject(SysMenu
);
905 UserDestroyMenu(hSysMenu
);
909 NewMenu
= IntCloneMenu(Menu
);
912 NewMenu
->MenuInfo
.Flags
|= MF_SYSMENU
| MF_POPUP
;
913 IntReleaseMenuObject(NewMenu
);
914 UserSetMenuDefaultItem(NewMenu
, SC_CLOSE
, FALSE
);
916 ItemInfo
.cbSize
= sizeof(MENUITEMINFOW
);
917 ItemInfo
.fMask
= MIIM_FTYPE
| MIIM_STRING
| MIIM_STATE
| MIIM_SUBMENU
;
918 ItemInfo
.fType
= MF_POPUP
;
919 ItemInfo
.fState
= MFS_ENABLED
;
920 ItemInfo
.dwTypeData
= NULL
;
922 ItemInfo
.hSubMenu
= NewMenu
->MenuInfo
.Self
;
923 IntInsertMenuItem(SysMenu
, (UINT
) -1, TRUE
, &ItemInfo
);
925 Window
->SystemMenu
= SysMenu
->MenuInfo
.Self
;
929 IntDestroyMenuObject(Menu
, FALSE
, TRUE
);
938 if(Window
->SystemMenu
)
939 return IntGetMenuObject((HMENU
)Window
->SystemMenu
);
947 IntIsChildWindow(PWND Parent
, PWND BaseWindow
)
952 while (Window
&& ((Window
->style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
))
954 if (Window
== Parent
)
959 Window
= Window
->spwndParent
;
966 Link the window into siblings list
967 children and parent are kept in place.
972 PWND WndInsertAfter
/* set to NULL if top sibling */
975 if ((Wnd
->spwndPrev
= WndInsertAfter
))
977 /* link after WndInsertAfter */
978 if ((Wnd
->spwndNext
= WndInsertAfter
->spwndNext
))
979 Wnd
->spwndNext
->spwndPrev
= Wnd
;
981 Wnd
->spwndPrev
->spwndNext
= Wnd
;
986 if ((Wnd
->spwndNext
= Wnd
->spwndParent
->spwndChild
))
987 Wnd
->spwndNext
->spwndPrev
= Wnd
;
989 Wnd
->spwndParent
->spwndChild
= Wnd
;
994 Note: Wnd->spwndParent can be null if it is the desktop.
996 VOID FASTCALL
IntLinkHwnd(PWND Wnd
, HWND hWndPrev
)
998 if (hWndPrev
== HWND_NOTOPMOST
)
1000 if (!(Wnd
->ExStyle
& WS_EX_TOPMOST
) &&
1001 (Wnd
->ExStyle2
& WS_EX2_LINKED
)) return; /* nothing to do */
1002 Wnd
->ExStyle
&= ~WS_EX_TOPMOST
;
1003 hWndPrev
= HWND_TOP
; /* fallback to the HWND_TOP case */
1006 IntUnlinkWindow(Wnd
); /* unlink it from the previous location */
1008 if (hWndPrev
== HWND_BOTTOM
)
1010 /* Link in the bottom of the list */
1011 PWND WndInsertAfter
;
1013 WndInsertAfter
= Wnd
->spwndParent
->spwndChild
;
1014 while( WndInsertAfter
&& WndInsertAfter
->spwndNext
)
1015 WndInsertAfter
= WndInsertAfter
->spwndNext
;
1017 IntLinkWindow(Wnd
, WndInsertAfter
);
1018 Wnd
->ExStyle
&= ~WS_EX_TOPMOST
;
1020 else if (hWndPrev
== HWND_TOPMOST
)
1022 /* Link in the top of the list */
1023 IntLinkWindow(Wnd
, NULL
);
1025 Wnd
->ExStyle
|= WS_EX_TOPMOST
;
1027 else if (hWndPrev
== HWND_TOP
)
1029 /* Link it after the last topmost window */
1030 PWND WndInsertBefore
;
1032 WndInsertBefore
= Wnd
->spwndParent
->spwndChild
;
1034 if (!(Wnd
->ExStyle
& WS_EX_TOPMOST
)) /* put it above the first non-topmost window */
1036 while (WndInsertBefore
!= NULL
&& WndInsertBefore
->spwndNext
!= NULL
)
1038 if (!(WndInsertBefore
->ExStyle
& WS_EX_TOPMOST
)) break;
1039 if (WndInsertBefore
== Wnd
->spwndOwner
) /* keep it above owner */
1041 Wnd
->ExStyle
|= WS_EX_TOPMOST
;
1044 WndInsertBefore
= WndInsertBefore
->spwndNext
;
1048 IntLinkWindow(Wnd
, WndInsertBefore
? WndInsertBefore
->spwndPrev
: NULL
);
1052 /* Link it after hWndPrev */
1053 PWND WndInsertAfter
;
1055 WndInsertAfter
= UserGetWindowObject(hWndPrev
);
1056 /* Are we called with an erroneous handle */
1057 if(WndInsertAfter
== NULL
)
1059 /* Link in a default position */
1060 IntLinkHwnd(Wnd
, HWND_TOP
);
1064 IntLinkWindow(Wnd
, WndInsertAfter
);
1066 /* Fix the WS_EX_TOPMOST flag */
1067 if (!(WndInsertAfter
->ExStyle
& WS_EX_TOPMOST
))
1069 Wnd
->ExStyle
&= ~WS_EX_TOPMOST
;
1073 if(WndInsertAfter
->spwndNext
&&
1074 WndInsertAfter
->spwndNext
->ExStyle
& WS_EX_TOPMOST
)
1076 Wnd
->ExStyle
|= WS_EX_TOPMOST
;
1080 Wnd
->ExStyle2
|= WS_EX2_LINKED
;
1084 IntProcessOwnerSwap(PWND Wnd
, PWND WndNewOwner
, PWND WndOldOwner
)
1088 if (Wnd
->head
.pti
!= WndOldOwner
->head
.pti
)
1091 Wnd
->head
.pti
== WndNewOwner
->head
.pti
||
1092 WndOldOwner
->head
.pti
!= WndNewOwner
->head
.pti
)
1094 ERR("ProcessOwnerSwap Old out.\n");
1095 //UserAttachThreadInput(Wnd->head.pti, WndOldOwner->head.pti, FALSE);
1101 if (Wnd
->head
.pti
!= WndNewOwner
->head
.pti
)
1104 WndOldOwner
->head
.pti
!= WndNewOwner
->head
.pti
)
1106 ERR("ProcessOwnerSwap New in.\n");
1107 //UserAttachThreadInput(Wnd->head.pti, WndNewOwner->head.pti, TRUE);
1111 // FIXME: System Tray checks.
1115 IntSetOwner(HWND hWnd
, HWND hWndNewOwner
)
1117 PWND Wnd
, WndOldOwner
, WndNewOwner
;
1120 Wnd
= IntGetWindowObject(hWnd
);
1124 WndOldOwner
= Wnd
->spwndOwner
;
1126 ret
= WndOldOwner
? UserHMGetHandle(WndOldOwner
) : 0;
1127 WndNewOwner
= UserGetWindowObject(hWndNewOwner
);
1129 if (!WndNewOwner
&& hWndNewOwner
)
1131 EngSetLastError(ERROR_INVALID_PARAMETER
);
1136 IntProcessOwnerSwap(Wnd
, WndNewOwner
, WndOldOwner
);
1138 if (IntValidateOwnerDepth(Wnd
, WndNewOwner
))
1142 Wnd
->spwndOwner
= WndNewOwner
;
1146 Wnd
->spwndOwner
= NULL
;
1151 IntProcessOwnerSwap(Wnd
, WndOldOwner
, WndNewOwner
);
1152 EngSetLastError(ERROR_INVALID_PARAMETER
);
1156 UserDereferenceObject(Wnd
);
1161 co_IntSetParent(PWND Wnd
, PWND WndNewParent
)
1163 PWND WndOldParent
, pWndExam
;
1166 int swFlags
= SWP_NOSIZE
|SWP_NOZORDER
;
1169 ASSERT(WndNewParent
);
1170 ASSERT_REFS_CO(Wnd
);
1171 ASSERT_REFS_CO(WndNewParent
);
1173 if (Wnd
== Wnd
->head
.rpdesk
->spwndMessage
)
1175 EngSetLastError(ERROR_ACCESS_DENIED
);
1179 /* Some applications try to set a child as a parent */
1180 if (IntIsChildWindow(Wnd
, WndNewParent
))
1182 EngSetLastError( ERROR_INVALID_PARAMETER
);
1186 pWndExam
= WndNewParent
; // Load parent Window to examine.
1187 // Now test for set parent to parent hit.
1190 if (Wnd
== pWndExam
)
1192 EngSetLastError(ERROR_INVALID_PARAMETER
);
1195 pWndExam
= pWndExam
->spwndParent
;
1199 * Windows hides the window first, then shows it again
1200 * including the WM_SHOWWINDOW messages and all
1202 WasVisible
= co_WinPosShowWindow(Wnd
, SW_HIDE
);
1204 /* Window must belong to current process */
1205 if (Wnd
->head
.pti
->ppi
!= PsGetCurrentProcessWin32Process())
1208 WndOldParent
= Wnd
->spwndParent
;
1210 if ( WndOldParent
&&
1211 WndOldParent
->ExStyle
& WS_EX_LAYOUTRTL
)
1212 pt
.x
= Wnd
->rcWindow
.right
;
1214 pt
.x
= Wnd
->rcWindow
.left
;
1215 pt
.y
= Wnd
->rcWindow
.top
;
1217 if (WndOldParent
) UserReferenceObject(WndOldParent
); /* Caller must deref */
1219 if (WndNewParent
!= WndOldParent
)
1221 /* Unlink the window from the siblings list */
1222 IntUnlinkWindow(Wnd
);
1223 Wnd
->ExStyle2
&= ~WS_EX2_LINKED
;
1225 /* Set the new parent */
1226 Wnd
->spwndParent
= WndNewParent
;
1228 if ( Wnd
->style
& WS_CHILD
&&
1230 Wnd
->spwndOwner
->ExStyle
& WS_EX_TOPMOST
)
1232 ERR("SetParent Top Most from Pop up!\n");
1233 Wnd
->ExStyle
|= WS_EX_TOPMOST
;
1236 /* Link the window with its new siblings */
1238 ((0 == (Wnd
->ExStyle
& WS_EX_TOPMOST
) &&
1239 WndNewParent
== UserGetDesktopWindow() ) ? HWND_TOP
: HWND_TOPMOST
) );
1243 if ((Wnd
->style
& (WS_CHILD
|WS_POPUP
)) == WS_CHILD
)
1245 if ( Wnd
->spwndParent
!= co_GetDesktopWindow(Wnd
))
1247 if (Wnd
->head
.pti
!= WndOldParent
->head
.pti
)
1249 ERR("SetParent Old out.\n");
1250 //UserAttachThreadInput(Wnd->head.pti, WndOldParent->head.pti, FALSE);
1253 if ( WndNewParent
!= co_GetDesktopWindow(Wnd
))
1255 if (Wnd
->head
.pti
!= WndNewParent
->head
.pti
)
1257 ERR("SetParent New in.\n");
1258 //UserAttachThreadInput(Wnd->head.pti, WndNewParent->head.pti, TRUE);
1263 if (WndOldParent
== UserGetMessageWindow() || WndNewParent
== UserGetMessageWindow())
1264 swFlags
|= SWP_NOACTIVATE
;
1266 IntNotifyWinEvent(EVENT_OBJECT_PARENTCHANGE
, Wnd
,OBJID_WINDOW
, CHILDID_SELF
, WEF_SETBYWNDPTI
);
1268 * SetParent additionally needs to make hwnd the top window
1269 * in the z-order and send the expected WM_WINDOWPOSCHANGING and
1270 * WM_WINDOWPOSCHANGED notification messages.
1272 co_WinPosSetWindowPos( Wnd
,
1273 (0 == (Wnd
->ExStyle
& WS_EX_TOPMOST
) ? HWND_TOP
: HWND_TOPMOST
),
1274 pt
.x
, pt
.y
, 0, 0, swFlags
);
1276 if (WasVisible
) co_WinPosShowWindow(Wnd
, SW_SHOWNORMAL
);
1278 return WndOldParent
;
1282 co_UserSetParent(HWND hWndChild
, HWND hWndNewParent
)
1284 PWND Wnd
= NULL
, WndParent
= NULL
, WndOldParent
;
1285 HWND hWndOldParent
= NULL
;
1286 USER_REFERENCE_ENTRY Ref
, ParentRef
;
1288 if (IntIsBroadcastHwnd(hWndChild
) || IntIsBroadcastHwnd(hWndNewParent
))
1290 EngSetLastError(ERROR_INVALID_PARAMETER
);
1294 if (hWndChild
== IntGetDesktopWindow())
1296 EngSetLastError(ERROR_ACCESS_DENIED
);
1302 if (!(WndParent
= UserGetWindowObject(hWndNewParent
)))
1309 if (!(WndParent
= UserGetWindowObject(IntGetDesktopWindow())))
1315 if (!(Wnd
= UserGetWindowObject(hWndChild
)))
1320 UserRefObjectCo(Wnd
, &Ref
);
1321 UserRefObjectCo(WndParent
, &ParentRef
);
1322 //ERR("Enter co_IntSetParent\n");
1323 WndOldParent
= co_IntSetParent(Wnd
, WndParent
);
1324 //ERR("Leave co_IntSetParent\n");
1325 UserDerefObjectCo(WndParent
);
1326 UserDerefObjectCo(Wnd
);
1330 hWndOldParent
= WndOldParent
->head
.h
;
1331 UserDereferenceObject(WndOldParent
);
1334 return( hWndOldParent
);
1338 IntSetSystemMenu(PWND Window
, PMENU_OBJECT Menu
)
1340 PMENU_OBJECT OldMenu
;
1341 if(Window
->SystemMenu
)
1343 OldMenu
= IntGetMenuObject(Window
->SystemMenu
);
1346 OldMenu
->MenuInfo
.Flags
&= ~ MF_SYSMENU
;
1347 IntReleaseMenuObject(OldMenu
);
1353 /* FIXME: Check window style, propably return FALSE? */
1354 Window
->SystemMenu
= Menu
->MenuInfo
.Self
;
1355 Menu
->MenuInfo
.Flags
|= MF_SYSMENU
;
1358 Window
->SystemMenu
= (HMENU
)0;
1363 /* Unlink the window from siblings. children and parent are kept in place. */
1365 IntUnlinkWindow(PWND Wnd
)
1368 Wnd
->spwndNext
->spwndPrev
= Wnd
->spwndPrev
;
1371 Wnd
->spwndPrev
->spwndNext
= Wnd
->spwndNext
;
1373 if (Wnd
->spwndParent
&& Wnd
->spwndParent
->spwndChild
== Wnd
)
1374 Wnd
->spwndParent
->spwndChild
= Wnd
->spwndNext
;
1376 Wnd
->spwndPrev
= Wnd
->spwndNext
= NULL
;
1379 /* FUNCTIONS *****************************************************************/
1382 * As best as I can figure, this function is used by EnumWindows,
1383 * EnumChildWindows, EnumDesktopWindows, & EnumThreadWindows.
1385 * It's supposed to build a list of HWNDs to return to the caller.
1386 * We can figure out what kind of list by what parameters are
1394 NtUserBuildHwndList(
1407 return ERROR_INVALID_PARAMETER
;
1409 if (hwndParent
|| !dwThreadId
)
1412 PWND Parent
, Window
;
1416 if(hDesktop
== NULL
&& !(Desktop
= IntGetActiveDesktop()))
1418 return ERROR_INVALID_HANDLE
;
1423 Status
= IntValidateDesktopHandle(hDesktop
,
1427 if(!NT_SUCCESS(Status
))
1429 return ERROR_INVALID_HANDLE
;
1432 hwndParent
= Desktop
->DesktopWindow
;
1439 if((Parent
= UserGetWindowObject(hwndParent
)) &&
1440 (Window
= Parent
->spwndChild
))
1442 BOOL bGoDown
= TRUE
;
1444 Status
= STATUS_SUCCESS
;
1449 if(dwCount
++ < *pBufSize
&& pWnd
)
1453 ProbeForWrite(pWnd
, sizeof(HWND
), 1);
1454 *pWnd
= Window
->head
.h
;
1457 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1459 Status
= _SEH2_GetExceptionCode();
1462 if(!NT_SUCCESS(Status
))
1464 SetLastNtError(Status
);
1468 if (Window
->spwndChild
&& bChildren
)
1470 Window
= Window
->spwndChild
;
1475 if (Window
->spwndNext
)
1477 Window
= Window
->spwndNext
;
1481 Window
= Window
->spwndParent
;
1482 if (Window
== Parent
)
1491 ObDereferenceObject(Desktop
);
1494 else // Build EnumThreadWindows list!
1497 PTHREADINFO W32Thread
;
1498 PLIST_ENTRY Current
;
1501 Status
= PsLookupThreadByThreadId((HANDLE
)dwThreadId
, &Thread
);
1502 if (!NT_SUCCESS(Status
))
1504 ERR("Thread Id is not valid!\n");
1505 return ERROR_INVALID_PARAMETER
;
1507 if (!(W32Thread
= (PTHREADINFO
)Thread
->Tcb
.Win32Thread
))
1509 ObDereferenceObject(Thread
);
1510 ERR("Thread is not initialized!\n");
1511 return ERROR_INVALID_PARAMETER
;
1514 Current
= W32Thread
->WindowListHead
.Flink
;
1515 while (Current
!= &(W32Thread
->WindowListHead
))
1517 Window
= CONTAINING_RECORD(Current
, WND
, ThreadListEntry
);
1520 if (dwCount
< *pBufSize
&& pWnd
)
1524 ProbeForWrite(pWnd
, sizeof(HWND
), 1);
1525 *pWnd
= Window
->head
.h
;
1528 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1530 Status
= _SEH2_GetExceptionCode();
1533 if (!NT_SUCCESS(Status
))
1535 ERR("Failure to build window list!\n");
1536 SetLastNtError(Status
);
1541 Current
= Window
->ThreadListEntry
.Flink
;
1544 ObDereferenceObject(Thread
);
1547 *pBufSize
= dwCount
;
1548 return STATUS_SUCCESS
;
1551 static void IntSendParentNotify( PWND pWindow
, UINT msg
)
1553 if ( (pWindow
->style
& (WS_CHILD
| WS_POPUP
)) == WS_CHILD
&&
1554 !(pWindow
->style
& WS_EX_NOPARENTNOTIFY
))
1556 if (pWindow
->spwndParent
&& pWindow
->spwndParent
!= UserGetDesktopWindow())
1558 USER_REFERENCE_ENTRY Ref
;
1559 UserRefObjectCo(pWindow
->spwndParent
, &Ref
);
1560 co_IntSendMessage( pWindow
->spwndParent
->head
.h
,
1562 MAKEWPARAM( msg
, pWindow
->IDMenu
),
1563 (LPARAM
)pWindow
->head
.h
);
1564 UserDerefObjectCo(pWindow
->spwndParent
);
1570 IntFixWindowCoordinates(CREATESTRUCTW
* Cs
, PWND ParentWindow
, DWORD
* dwShowMode
)
1572 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1574 /* default positioning for overlapped windows */
1575 if(!(Cs
->style
& (WS_POPUP
| WS_CHILD
)))
1578 PRTL_USER_PROCESS_PARAMETERS ProcessParams
;
1580 pMonitor
= UserGetPrimaryMonitor();
1582 /* Check if we don't have a monitor attached yet */
1583 if(pMonitor
== NULL
)
1591 ProcessParams
= PsGetCurrentProcess()->Peb
->ProcessParameters
;
1593 if (IS_DEFAULT(Cs
->x
))
1595 if (!IS_DEFAULT(Cs
->y
)) *dwShowMode
= Cs
->y
;
1597 if(ProcessParams
->WindowFlags
& STARTF_USEPOSITION
)
1599 Cs
->x
= ProcessParams
->StartingX
;
1600 Cs
->y
= ProcessParams
->StartingY
;
1604 Cs
->x
= pMonitor
->cWndStack
* (UserGetSystemMetrics(SM_CXSIZE
) + UserGetSystemMetrics(SM_CXFRAME
));
1605 Cs
->y
= pMonitor
->cWndStack
* (UserGetSystemMetrics(SM_CYSIZE
) + UserGetSystemMetrics(SM_CYFRAME
));
1606 if (Cs
->x
> ((pMonitor
->rcWork
.right
- pMonitor
->rcWork
.left
) / 4) ||
1607 Cs
->y
> ((pMonitor
->rcWork
.bottom
- pMonitor
->rcWork
.top
) / 4))
1609 /* reset counter and position */
1612 pMonitor
->cWndStack
= 0;
1614 pMonitor
->cWndStack
++;
1618 if (IS_DEFAULT(Cs
->cx
))
1620 if (ProcessParams
->WindowFlags
& STARTF_USEPOSITION
)
1622 Cs
->cx
= ProcessParams
->CountX
;
1623 Cs
->cy
= ProcessParams
->CountY
;
1627 Cs
->cx
= (pMonitor
->rcWork
.right
- pMonitor
->rcWork
.left
) * 3 / 4;
1628 Cs
->cy
= (pMonitor
->rcWork
.bottom
- pMonitor
->rcWork
.top
) * 3 / 4;
1631 /* neither x nor cx are default. Check the y values .
1632 * In the trace we see Outlook and Outlook Express using
1633 * cy set to CW_USEDEFAULT when opening the address book.
1635 else if (IS_DEFAULT(Cs
->cy
))
1637 TRACE("Strange use of CW_USEDEFAULT in nHeight\n");
1638 Cs
->cy
= (pMonitor
->rcWork
.bottom
- pMonitor
->rcWork
.top
) * 3 / 4;
1643 /* if CW_USEDEFAULT is set for non-overlapped windows, both values are set to zero */
1644 if(IS_DEFAULT(Cs
->x
))
1649 if(IS_DEFAULT(Cs
->cx
))
1659 /* Allocates and initializes a window */
1660 PWND FASTCALL
IntCreateWindow(CREATESTRUCTW
* Cs
,
1661 PLARGE_STRING WindowName
,
1666 PDESKTOP pdeskCreated
)
1670 PTHREADINFO pti
= NULL
;
1671 PMENU_OBJECT SystemMenu
;
1673 BOOL bUnicodeWindow
;
1675 pti
= pdeskCreated
? gptiDesktopThread
: GetW32ThreadInfo();
1677 if (!(Cs
->dwExStyle
& WS_EX_LAYOUTRTL
))
1681 if ( (Cs
->style
& (WS_CHILD
|WS_POPUP
)) == WS_CHILD
&&
1682 ParentWindow
->ExStyle
& WS_EX_LAYOUTRTL
&&
1683 !(ParentWindow
->ExStyle
& WS_EX_NOINHERITLAYOUT
) )
1684 Cs
->dwExStyle
|= WS_EX_LAYOUTRTL
;
1688 * Note from MSDN <http://msdn.microsoft.com/en-us/library/aa913269.aspx>:
1690 * Dialog boxes and message boxes do not inherit layout, so you must
1691 * set the layout explicitly.
1693 if ( Class
->fnid
!= FNID_DIALOG
)
1695 if (pti
->ppi
->dwLayout
& LAYOUT_RTL
)
1697 Cs
->dwExStyle
|= WS_EX_LAYOUTRTL
;
1703 /* Automatically add WS_EX_WINDOWEDGE */
1704 if ((Cs
->dwExStyle
& WS_EX_DLGMODALFRAME
) ||
1705 ((!(Cs
->dwExStyle
& WS_EX_STATICEDGE
)) &&
1706 (Cs
->style
& (WS_DLGFRAME
| WS_THICKFRAME
))))
1707 Cs
->dwExStyle
|= WS_EX_WINDOWEDGE
;
1709 Cs
->dwExStyle
&= ~WS_EX_WINDOWEDGE
;
1711 /* Is it a unicode window? */
1712 bUnicodeWindow
=!(Cs
->dwExStyle
& WS_EX_SETANSICREATOR
);
1713 Cs
->dwExStyle
&= ~WS_EX_SETANSICREATOR
;
1715 /* Allocate the new window */
1716 pWnd
= (PWND
) UserCreateObject( gHandleTable
,
1717 pdeskCreated
? pdeskCreated
: pti
->rpdesk
,
1721 sizeof(WND
) + Class
->cbwndExtra
);
1728 TRACE("Created window object with handle %X\n", hWnd
);
1730 if (pdeskCreated
&& pdeskCreated
->DesktopWindow
== NULL
)
1731 { /* HACK: Helper for win32csr/desktopbg.c */
1732 /* If there is no desktop window yet, we must be creating it */
1733 TRACE("CreateWindow setting desktop.\n");
1734 pdeskCreated
->DesktopWindow
= hWnd
;
1735 pdeskCreated
->pDeskInfo
->spwnd
= pWnd
;
1739 * Fill out the structure describing it.
1741 /* Remember, pWnd->head is setup in object.c ... */
1742 pWnd
->spwndParent
= ParentWindow
;
1743 pWnd
->spwndOwner
= OwnerWindow
;
1745 pWnd
->spwndLastActive
= pWnd
;
1746 pWnd
->state2
|= WNDS2_WIN40COMPAT
; // FIXME!!!
1748 pWnd
->hModule
= Cs
->hInstance
;
1749 pWnd
->style
= Cs
->style
& ~WS_VISIBLE
;
1750 pWnd
->ExStyle
= Cs
->dwExStyle
;
1751 pWnd
->cbwndExtra
= pWnd
->pcls
->cbwndExtra
;
1752 pWnd
->pActCtx
= acbiBuffer
;
1753 pWnd
->InternalPos
.MaxPos
.x
= pWnd
->InternalPos
.MaxPos
.y
= -1;
1754 pWnd
->InternalPos
.IconPos
.x
= pWnd
->InternalPos
.IconPos
.y
= -1;
1756 IntReferenceMessageQueue(pWnd
->head
.pti
->MessageQueue
);
1757 if (pWnd
->spwndParent
!= NULL
&& Cs
->hwndParent
!= 0)
1759 pWnd
->HideFocus
= pWnd
->spwndParent
->HideFocus
;
1760 pWnd
->HideAccel
= pWnd
->spwndParent
->HideAccel
;
1763 if (pWnd
->pcls
->CSF_flags
& CSF_SERVERSIDEPROC
)
1764 pWnd
->state
|= WNDS_SERVERSIDEWINDOWPROC
;
1766 /* BugBoy Comments: Comment below say that System classes are always created
1767 as UNICODE. In windows, creating a window with the ANSI version of CreateWindow
1768 sets the window to ansi as verified by testing with IsUnicodeWindow API.
1770 No where can I see in code or through testing does the window change back
1771 to ANSI after being created as UNICODE in ROS. I didnt do more testing to
1772 see what problems this would cause. */
1774 // Set WndProc from Class.
1775 pWnd
->lpfnWndProc
= pWnd
->pcls
->lpfnWndProc
;
1777 // GetWindowProc, test for non server side default classes and set WndProc.
1778 if ( pWnd
->pcls
->fnid
<= FNID_GHOST
&& pWnd
->pcls
->fnid
>= FNID_BUTTON
)
1782 if (GETPFNCLIENTA(pWnd
->pcls
->fnid
) == pWnd
->lpfnWndProc
)
1783 pWnd
->lpfnWndProc
= GETPFNCLIENTW(pWnd
->pcls
->fnid
);
1787 if (GETPFNCLIENTW(pWnd
->pcls
->fnid
) == pWnd
->lpfnWndProc
)
1788 pWnd
->lpfnWndProc
= GETPFNCLIENTA(pWnd
->pcls
->fnid
);
1792 // If not an Unicode caller, set Ansi creator bit.
1793 if (!bUnicodeWindow
) pWnd
->state
|= WNDS_ANSICREATOR
;
1795 // Clone Class Ansi/Unicode proc type.
1796 if (pWnd
->pcls
->CSF_flags
& CSF_ANSIPROC
)
1798 pWnd
->state
|= WNDS_ANSIWINDOWPROC
;
1799 pWnd
->Unicode
= FALSE
;
1803 * It seems there can be both an Ansi creator and Unicode Class Window
1804 * WndProc, unless the following overriding conditions occur:
1806 if ( !bUnicodeWindow
&&
1807 ( Class
->atomClassName
== gpsi
->atomSysClass
[ICLS_BUTTON
] ||
1808 Class
->atomClassName
== gpsi
->atomSysClass
[ICLS_COMBOBOX
] ||
1809 Class
->atomClassName
== gpsi
->atomSysClass
[ICLS_COMBOLBOX
] ||
1810 Class
->atomClassName
== gpsi
->atomSysClass
[ICLS_DIALOG
] ||
1811 Class
->atomClassName
== gpsi
->atomSysClass
[ICLS_EDIT
] ||
1812 Class
->atomClassName
== gpsi
->atomSysClass
[ICLS_IME
] ||
1813 Class
->atomClassName
== gpsi
->atomSysClass
[ICLS_LISTBOX
] ||
1814 Class
->atomClassName
== gpsi
->atomSysClass
[ICLS_MDICLIENT
] ||
1815 Class
->atomClassName
== gpsi
->atomSysClass
[ICLS_STATIC
] ) )
1816 { // Override Class and set the window Ansi WndProc.
1817 pWnd
->state
|= WNDS_ANSIWINDOWPROC
;
1818 pWnd
->Unicode
= FALSE
;
1821 { // Set the window Unicode WndProc.
1822 pWnd
->state
&= ~WNDS_ANSIWINDOWPROC
;
1823 pWnd
->Unicode
= TRUE
;
1827 /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx,
1828 then my testing shows that windows (2k and XP) creates a CallProc for it immediately
1829 Dont understand why it does this. */
1830 if (Class
->atomClassName
== gpsi
->atomSysClass
[ICLS_EDIT
])
1832 PCALLPROCDATA CallProc
;
1833 CallProc
= CreateCallProc(NULL
, pWnd
->lpfnWndProc
, pWnd
->Unicode
, pWnd
->head
.pti
->ppi
);
1837 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1838 ERR("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %x\n",hWnd
);
1842 UserAddCallProcToClass(pWnd
->pcls
, CallProc
);
1846 InitializeListHead(&pWnd
->PropListHead
);
1848 if ( WindowName
->Buffer
!= NULL
&& WindowName
->Length
> 0 )
1850 pWnd
->strName
.Buffer
= DesktopHeapAlloc(pWnd
->head
.rpdesk
,
1851 WindowName
->Length
+ sizeof(UNICODE_NULL
));
1852 if (pWnd
->strName
.Buffer
== NULL
)
1857 RtlCopyMemory(pWnd
->strName
.Buffer
, WindowName
->Buffer
, WindowName
->Length
);
1858 pWnd
->strName
.Buffer
[WindowName
->Length
/ sizeof(WCHAR
)] = L
'\0';
1859 pWnd
->strName
.Length
= WindowName
->Length
;
1860 pWnd
->strName
.MaximumLength
= WindowName
->Length
+ sizeof(UNICODE_NULL
);
1863 /* Correct the window style. */
1864 if ((pWnd
->style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
)
1866 pWnd
->style
|= WS_CLIPSIBLINGS
;
1867 if (!(pWnd
->style
& WS_POPUP
))
1869 pWnd
->style
|= WS_CAPTION
;
1873 /* WS_EX_WINDOWEDGE depends on some other styles */
1874 if (pWnd
->ExStyle
& WS_EX_DLGMODALFRAME
)
1875 pWnd
->ExStyle
|= WS_EX_WINDOWEDGE
;
1876 else if (pWnd
->style
& (WS_DLGFRAME
| WS_THICKFRAME
))
1878 if (!((pWnd
->ExStyle
& WS_EX_STATICEDGE
) &&
1879 (pWnd
->style
& (WS_CHILD
| WS_POPUP
))))
1880 pWnd
->ExStyle
|= WS_EX_WINDOWEDGE
;
1883 pWnd
->ExStyle
&= ~WS_EX_WINDOWEDGE
;
1885 if (!(pWnd
->style
& (WS_CHILD
| WS_POPUP
)))
1886 pWnd
->state
|= WNDS_SENDSIZEMOVEMSGS
;
1888 /* Create system menu */
1889 if ((Cs
->style
& WS_SYSMENU
)) // && (dwStyle & WS_CAPTION) == WS_CAPTION)
1891 SystemMenu
= IntGetSystemMenu(pWnd
, TRUE
, TRUE
);
1894 pWnd
->SystemMenu
= SystemMenu
->MenuInfo
.Self
;
1895 IntReleaseMenuObject(SystemMenu
);
1899 /* Set the window menu */
1900 if ((Cs
->style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
)
1903 IntSetMenu(pWnd
, Cs
->hMenu
, &MenuChanged
);
1904 else if (pWnd
->pcls
->lpszMenuName
) // Take it from the parent.
1906 UNICODE_STRING MenuName
;
1909 if (IS_INTRESOURCE(pWnd
->pcls
->lpszMenuName
))
1911 MenuName
.Length
= 0;
1912 MenuName
.MaximumLength
= 0;
1913 MenuName
.Buffer
= pWnd
->pcls
->lpszMenuName
;
1917 RtlInitUnicodeString( &MenuName
, pWnd
->pcls
->lpszMenuName
);
1919 hMenu
= co_IntCallLoadMenu( pWnd
->pcls
->hModule
, &MenuName
);
1920 if (hMenu
) IntSetMenu(pWnd
, hMenu
, &MenuChanged
);
1924 pWnd
->IDMenu
= (UINT
) Cs
->hMenu
;
1927 if ( ParentWindow
&&
1928 ParentWindow
!= ParentWindow
->head
.rpdesk
->spwndMessage
&&
1929 ParentWindow
!= ParentWindow
->head
.rpdesk
->pDeskInfo
->spwnd
)
1931 PWND Owner
= IntGetNonChildAncestor(ParentWindow
);
1933 if (!IntValidateOwnerDepth(pWnd
, Owner
))
1935 EngSetLastError(ERROR_INVALID_PARAMETER
);
1938 if ( pWnd
->spwndOwner
&&
1939 pWnd
->spwndOwner
->ExStyle
& WS_EX_TOPMOST
)
1941 pWnd
->ExStyle
|= WS_EX_TOPMOST
;
1943 if ( pWnd
->spwndOwner
&&
1944 Class
->atomClassName
!= gpsi
->atomSysClass
[ICLS_IME
] &&
1945 pti
!= pWnd
->spwndOwner
->head
.pti
)
1947 ERR("CreateWindow Owner in.\n");
1948 //UserAttachThreadInput(pti, pWnd->spwndOwner->head.pti, TRUE);
1952 /* Insert the window into the thread's window list. */
1953 InsertTailList (&pti
->WindowListHead
, &pWnd
->ThreadListEntry
);
1955 /* Handle "CS_CLASSDC", it is tested first. */
1956 if ( (pWnd
->pcls
->style
& CS_CLASSDC
) && !(pWnd
->pcls
->pdce
) )
1957 { /* One DCE per class to have CLASS. */
1958 pWnd
->pcls
->pdce
= DceAllocDCE( pWnd
, DCE_CLASS_DC
);
1960 else if ( pWnd
->pcls
->style
& CS_OWNDC
)
1961 { /* Allocate a DCE for this window. */
1962 DceAllocDCE(pWnd
, DCE_WINDOW_DC
);
1968 ERR("IntCreateWindow Allocation Error.\n");
1969 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
1972 UserDereferenceObject(pWnd
);
1980 co_UserCreateWindowEx(CREATESTRUCTW
* Cs
,
1981 PUNICODE_STRING ClassName
,
1982 PLARGE_STRING WindowName
,
1986 PWND Window
= NULL
, ParentWindow
= NULL
, OwnerWindow
;
1987 HWND hWnd
, hWndParent
, hWndOwner
, hwndInsertAfter
;
1988 PWINSTATION_OBJECT WinSta
;
1991 POINT MaxSize
, MaxPos
, MinTrack
, MaxTrack
;
1992 CBT_CREATEWNDW
* pCbtCreate
;
1994 USER_REFERENCE_ENTRY ParentRef
, Ref
;
1996 DWORD dwShowMode
= SW_SHOW
;
1997 CREATESTRUCTW
*pCsw
= NULL
;
1998 PVOID pszClass
= NULL
, pszName
= NULL
;
2001 /* Get the current window station and reference it */
2002 pti
= GetW32ThreadInfo();
2003 if (pti
== NULL
|| pti
->rpdesk
== NULL
)
2005 ERR("Thread is not attached to a desktop! Cannot create window!\n");
2006 return NULL
; // There is nothing to cleanup.
2008 WinSta
= pti
->rpdesk
->rpwinstaParent
;
2009 ObReferenceObjectByPointer(WinSta
, KernelMode
, ExWindowStationObjectType
, 0);
2014 /* Get the class and reference it */
2015 Class
= IntGetAndReferenceClass(ClassName
, Cs
->hInstance
, FALSE
);
2018 ERR("Failed to find class %wZ\n", ClassName
);
2022 /* Now find the parent and the owner window */
2023 hWndParent
= IntGetDesktopWindow();
2026 if (Cs
->hwndParent
== HWND_MESSAGE
)
2028 Cs
->hwndParent
= hWndParent
= IntGetMessageWindow();
2030 else if (Cs
->hwndParent
)
2032 if ((Cs
->style
& (WS_CHILD
|WS_POPUP
)) != WS_CHILD
)
2033 hWndOwner
= Cs
->hwndParent
;
2035 hWndParent
= Cs
->hwndParent
;
2037 else if ((Cs
->style
& (WS_CHILD
|WS_POPUP
)) == WS_CHILD
)
2039 ERR("Cannot create a child window without a parrent!\n");
2040 EngSetLastError(ERROR_TLW_WITH_WSCHILD
);
2041 goto cleanup
; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
2044 ParentWindow
= hWndParent
? UserGetWindowObject(hWndParent
): NULL
;
2045 OwnerWindow
= hWndOwner
? UserGetWindowObject(hWndOwner
): NULL
;
2047 /* FIXME: Is this correct? */
2049 OwnerWindow
= UserGetAncestor(OwnerWindow
, GA_ROOT
);
2051 /* Fix the position and the size of the window */
2054 UserRefObjectCo(ParentWindow
, &ParentRef
);
2055 IntFixWindowCoordinates(Cs
, ParentWindow
, &dwShowMode
);
2058 /* Allocate and initialize the new window */
2059 Window
= IntCreateWindow(Cs
,
2068 ERR("IntCreateWindow failed!\n");
2072 hWnd
= UserHMGetHandle(Window
);
2073 hwndInsertAfter
= HWND_TOP
;
2075 UserRefObjectCo(Window
, &Ref
);
2076 UserDereferenceObject(Window
);
2077 ObDereferenceObject(WinSta
);
2079 //// Check for a hook to eliminate overhead. ////
2080 if ( ISITHOOKED(WH_CBT
) || (pti
->rpdesk
->pDeskInfo
->fsHooks
& HOOKID_TO_FLAG(WH_CBT
)) )
2082 // Allocate the calling structures Justin Case this goes Global.
2083 pCsw
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(CREATESTRUCTW
), TAG_HOOK
);
2084 pCbtCreate
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(CBT_CREATEWNDW
), TAG_HOOK
);
2085 if (!pCsw
|| !pCbtCreate
)
2087 ERR("UserHeapAlloc() failed!\n");
2091 /* Fill the new CREATESTRUCTW */
2092 RtlCopyMemory(pCsw
, Cs
, sizeof(CREATESTRUCTW
));
2093 pCsw
->style
= Window
->style
; /* HCBT_CREATEWND needs the real window style */
2095 // Based on the assumption this is from "unicode source" user32, ReactOS, answer is yes.
2096 if (!IS_ATOM(ClassName
->Buffer
))
2098 if (Window
->state
& WNDS_ANSICREATOR
)
2100 ANSI_STRING AnsiString
;
2101 AnsiString
.MaximumLength
= (USHORT
)RtlUnicodeStringToAnsiSize(ClassName
)+sizeof(CHAR
);
2102 pszClass
= UserHeapAlloc(AnsiString
.MaximumLength
);
2105 ERR("UserHeapAlloc() failed!\n");
2108 RtlZeroMemory(pszClass
, AnsiString
.MaximumLength
);
2109 AnsiString
.Buffer
= (PCHAR
)pszClass
;
2110 RtlUnicodeStringToAnsiString(&AnsiString
, ClassName
, FALSE
);
2114 UNICODE_STRING UnicodeString
;
2115 UnicodeString
.MaximumLength
= ClassName
->Length
+ sizeof(UNICODE_NULL
);
2116 pszClass
= UserHeapAlloc(UnicodeString
.MaximumLength
);
2119 ERR("UserHeapAlloc() failed!\n");
2122 RtlZeroMemory(pszClass
, UnicodeString
.MaximumLength
);
2123 UnicodeString
.Buffer
= (PWSTR
)pszClass
;
2124 RtlCopyUnicodeString(&UnicodeString
, ClassName
);
2126 pCsw
->lpszClass
= UserHeapAddressToUser(pszClass
);
2128 if (WindowName
->Length
)
2130 UNICODE_STRING Name
;
2131 Name
.Buffer
= WindowName
->Buffer
;
2132 Name
.Length
= (USHORT
)min(WindowName
->Length
, MAXUSHORT
); // FIXME: LARGE_STRING truncated
2133 Name
.MaximumLength
= (USHORT
)min(WindowName
->MaximumLength
, MAXUSHORT
);
2135 if (Window
->state
& WNDS_ANSICREATOR
)
2137 ANSI_STRING AnsiString
;
2138 AnsiString
.MaximumLength
= (USHORT
)RtlUnicodeStringToAnsiSize(&Name
) + sizeof(CHAR
);
2139 pszName
= UserHeapAlloc(AnsiString
.MaximumLength
);
2142 ERR("UserHeapAlloc() failed!\n");
2145 RtlZeroMemory(pszName
, AnsiString
.MaximumLength
);
2146 AnsiString
.Buffer
= (PCHAR
)pszName
;
2147 RtlUnicodeStringToAnsiString(&AnsiString
, &Name
, FALSE
);
2151 UNICODE_STRING UnicodeString
;
2152 UnicodeString
.MaximumLength
= Name
.Length
+ sizeof(UNICODE_NULL
);
2153 pszName
= UserHeapAlloc(UnicodeString
.MaximumLength
);
2156 ERR("UserHeapAlloc() failed!\n");
2159 RtlZeroMemory(pszName
, UnicodeString
.MaximumLength
);
2160 UnicodeString
.Buffer
= (PWSTR
)pszName
;
2161 RtlCopyUnicodeString(&UnicodeString
, &Name
);
2163 pCsw
->lpszName
= UserHeapAddressToUser(pszName
);
2166 pCbtCreate
->lpcs
= pCsw
;
2167 pCbtCreate
->hwndInsertAfter
= hwndInsertAfter
;
2169 //// Call the WH_CBT hook ////
2170 Result
= co_HOOK_CallHooks(WH_CBT
, HCBT_CREATEWND
, (WPARAM
) hWnd
, (LPARAM
) pCbtCreate
);
2173 ERR("WH_CBT HCBT_CREATEWND hook failed! 0x%x\n", Result
);
2176 // Write back changes.
2181 hwndInsertAfter
= pCbtCreate
->hwndInsertAfter
;
2184 /* NCCREATE and WM_NCCALCSIZE need the original values */
2185 Cs
->lpszName
= (LPCWSTR
) WindowName
;
2186 Cs
->lpszClass
= (LPCWSTR
) ClassName
;
2188 /* Send the WM_GETMINMAXINFO message */
2192 if ((Cs
->style
& WS_THICKFRAME
) || !(Cs
->style
& (WS_POPUP
| WS_CHILD
)))
2194 co_WinPosGetMinMaxInfo(Window
, &MaxSize
, &MaxPos
, &MinTrack
, &MaxTrack
);
2195 if (Size
.cx
> MaxTrack
.x
) Size
.cx
= MaxTrack
.x
;
2196 if (Size
.cy
> MaxTrack
.y
) Size
.cy
= MaxTrack
.y
;
2197 if (Size
.cx
< MinTrack
.x
) Size
.cx
= MinTrack
.x
;
2198 if (Size
.cy
< MinTrack
.y
) Size
.cy
= MinTrack
.y
;
2201 Window
->rcWindow
.left
= Cs
->x
;
2202 Window
->rcWindow
.top
= Cs
->y
;
2203 Window
->rcWindow
.right
= Cs
->x
+ Size
.cx
;
2204 Window
->rcWindow
.bottom
= Cs
->y
+ Size
.cy
;
2205 if (0 != (Window
->style
& WS_CHILD
) && ParentWindow
)
2207 // ERR("co_UserCreateWindowEx(): Offset rcWindow\n");
2208 RECTL_vOffsetRect(&Window
->rcWindow
,
2209 ParentWindow
->rcClient
.left
,
2210 ParentWindow
->rcClient
.top
);
2212 Window
->rcClient
= Window
->rcWindow
;
2214 /* Link the window */
2215 if (NULL
!= ParentWindow
)
2217 /* Link the window into the siblings list */
2218 if ((Cs
->style
& (WS_CHILD
|WS_MAXIMIZE
)) == WS_CHILD
)
2219 IntLinkHwnd(Window
, HWND_BOTTOM
);
2221 IntLinkHwnd(Window
, hwndInsertAfter
);
2224 if ((Window
->style
& (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
2226 if ( !IntIsTopLevelWindow(Window
) )
2228 if (pti
!= Window
->spwndParent
->head
.pti
)
2230 ERR("CreateWindow Parent in.\n");
2231 //UserAttachThreadInput(pti, Window->spwndParent->head.pti, TRUE);
2236 /* Send the NCCREATE message */
2237 Result
= co_IntSendMessage(UserHMGetHandle(Window
), WM_NCCREATE
, 0, (LPARAM
) Cs
);
2240 ERR("co_UserCreateWindowEx(): NCCREATE message failed\n");
2244 /* Send the WM_NCCALCSIZE message */
2245 MaxPos
.x
= Window
->rcWindow
.left
;
2246 MaxPos
.y
= Window
->rcWindow
.top
;
2248 Result
= co_WinPosGetNonClientSize(Window
, &Window
->rcWindow
, &Window
->rcClient
);
2250 RECTL_vOffsetRect(&Window
->rcWindow
, MaxPos
.x
- Window
->rcWindow
.left
,
2251 MaxPos
.y
- Window
->rcWindow
.top
);
2254 /* Send the WM_CREATE message. */
2255 Result
= co_IntSendMessage(UserHMGetHandle(Window
), WM_CREATE
, 0, (LPARAM
) Cs
);
2256 if (Result
== (LRESULT
)-1)
2258 ERR("co_UserCreateWindowEx(): WM_CREATE message failed\n");
2262 /* Send the EVENT_OBJECT_CREATE event */
2263 IntNotifyWinEvent(EVENT_OBJECT_CREATE
, Window
, OBJID_WINDOW
, CHILDID_SELF
, 0);
2265 /* By setting the flag below it can be examined to determine if the window
2266 was created successfully and a valid pwnd was passed back to caller since
2267 from here the function has to succeed. */
2268 Window
->state2
|= WNDS2_WMCREATEMSGPROCESSED
;
2270 /* Send the WM_SIZE and WM_MOVE messages. */
2271 if (!(Window
->state
& WNDS_SENDSIZEMOVEMSGS
))
2273 co_WinPosSendSizeMove(Window
);
2276 /* Show or maybe minimize or maximize the window. */
2278 style
= IntSetStyle( Window
, 0, WS_MAXIMIZE
| WS_MINIMIZE
);
2279 if (style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
2282 UINT SwFlag
= (style
& WS_MINIMIZE
) ? SW_MINIMIZE
: SW_MAXIMIZE
;
2284 SwFlag
= co_WinPosMinMaximize(Window
, SwFlag
, &NewPos
);
2285 SwFlag
|= SWP_NOZORDER
|SWP_FRAMECHANGED
; /* Frame always gets changed */
2286 if (!(style
& WS_VISIBLE
) || (style
& WS_CHILD
) || UserGetActiveWindow()) SwFlag
|= SWP_NOACTIVATE
;
2287 co_WinPosSetWindowPos(Window
, 0, NewPos
.left
, NewPos
.top
,
2288 NewPos
.right
, NewPos
.bottom
, SwFlag
);
2291 /* Send the WM_PARENTNOTIFY message */
2292 IntSendParentNotify(Window
, WM_CREATE
);
2294 /* Notify the shell that a new window was created */
2295 if ((!hWndParent
) && (!hWndOwner
))
2297 co_IntShellHookNotify(HSHELL_WINDOWCREATED
, (WPARAM
)hWnd
, 0);
2300 /* Initialize and show the window's scrollbars */
2301 if (Window
->style
& WS_VSCROLL
)
2303 co_UserShowScrollBar(Window
, SB_VERT
, FALSE
, TRUE
);
2305 if (Window
->style
& WS_HSCROLL
)
2307 co_UserShowScrollBar(Window
, SB_HORZ
, TRUE
, FALSE
);
2310 /* Show the new window */
2311 if (Cs
->style
& WS_VISIBLE
)
2313 if (Window
->style
& WS_MAXIMIZE
)
2314 dwShowMode
= SW_SHOW
;
2315 else if (Window
->style
& WS_MINIMIZE
)
2316 dwShowMode
= SW_SHOWMINIMIZED
;
2318 co_WinPosShowWindow(Window
, dwShowMode
);
2320 if (Window
->ExStyle
& WS_EX_MDICHILD
)
2322 ASSERT(ParentWindow
);
2325 co_IntSendMessage(UserHMGetHandle(ParentWindow
), WM_MDIREFRESHMENU
, 0, 0);
2326 /* ShowWindow won't activate child windows */
2327 co_WinPosSetWindowPos(Window
, HWND_TOP
, 0, 0, 0, 0, SWP_SHOWWINDOW
| SWP_NOMOVE
| SWP_NOSIZE
);
2331 TRACE("co_UserCreateWindowEx(): Created window %X\n", hWnd
);
2337 TRACE("co_UserCreateWindowEx(): Error Created window!\n");
2338 /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */
2340 co_UserDestroyWindow(Window
);
2342 IntDereferenceClass(Class
, pti
->pDeskInfo
, pti
->ppi
);
2345 if (pCsw
) ExFreePoolWithTag(pCsw
, TAG_HOOK
);
2346 if (pCbtCreate
) ExFreePoolWithTag(pCbtCreate
, TAG_HOOK
);
2347 if (pszName
) UserHeapFree(pszName
);
2348 if (pszClass
) UserHeapFree(pszClass
);
2352 UserDerefObjectCo(Window
);
2354 if (ParentWindow
) UserDerefObjectCo(ParentWindow
);
2361 ProbeAndCaptureLargeString(
2362 OUT PLARGE_STRING plstrSafe
,
2363 IN PLARGE_STRING plstrUnsafe
)
2365 LARGE_STRING lstrTemp
;
2366 PVOID pvBuffer
= NULL
;
2370 /* Probe and copy the string */
2371 ProbeForRead(plstrUnsafe
, sizeof(LARGE_STRING
), sizeof(ULONG
));
2372 lstrTemp
= *plstrUnsafe
;
2374 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2377 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2381 if (lstrTemp
.Length
!= 0)
2383 /* Allocate a buffer from paged pool */
2384 pvBuffer
= ExAllocatePoolWithTag(PagedPool
, lstrTemp
.Length
, TAG_STRING
);
2387 return STATUS_NO_MEMORY
;
2392 /* Probe and copy the buffer */
2393 ProbeForRead(lstrTemp
.Buffer
, lstrTemp
.Length
, sizeof(WCHAR
));
2394 RtlCopyMemory(pvBuffer
, lstrTemp
.Buffer
, lstrTemp
.Length
);
2396 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2398 /* Cleanup and fail */
2399 ExFreePoolWithTag(pvBuffer
, TAG_STRING
);
2400 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2405 /* Set the output string */
2406 plstrSafe
->Buffer
= pvBuffer
;
2407 plstrSafe
->Length
= lstrTemp
.Length
;
2408 plstrSafe
->MaximumLength
= lstrTemp
.Length
;
2410 return STATUS_SUCCESS
;
2414 * \todo Allow passing plstrClassName as ANSI.
2418 NtUserCreateWindowEx(
2420 PLARGE_STRING plstrClassName
,
2421 PLARGE_STRING plstrClsVersion
,
2422 PLARGE_STRING plstrWindowName
,
2430 HINSTANCE hInstance
,
2436 LARGE_STRING lstrWindowName
;
2437 LARGE_STRING lstrClassName
;
2438 UNICODE_STRING ustrClassName
;
2443 lstrWindowName
.Buffer
= NULL
;
2444 lstrClassName
.Buffer
= NULL
;
2446 ASSERT(plstrWindowName
);
2448 /* Copy the window name to kernel mode */
2449 Status
= ProbeAndCaptureLargeString(&lstrWindowName
, plstrWindowName
);
2450 if (!NT_SUCCESS(Status
))
2452 ERR("NtUserCreateWindowEx: failed to capture plstrWindowName\n");
2453 SetLastNtError(Status
);
2457 plstrWindowName
= &lstrWindowName
;
2459 /* Check if the class is an atom */
2460 if (IS_ATOM(plstrClassName
))
2462 /* It is, pass the atom in the UNICODE_STRING */
2463 ustrClassName
.Buffer
= (PVOID
)plstrClassName
;
2464 ustrClassName
.Length
= 0;
2465 ustrClassName
.MaximumLength
= 0;
2469 /* It's not, capture the class name */
2470 Status
= ProbeAndCaptureLargeString(&lstrClassName
, plstrClassName
);
2471 if (!NT_SUCCESS(Status
))
2473 ERR("NtUserCreateWindowEx: failed to capture plstrClassName\n");
2474 /* Set last error, cleanup and return */
2475 SetLastNtError(Status
);
2479 /* We pass it on as a UNICODE_STRING */
2480 ustrClassName
.Buffer
= lstrClassName
.Buffer
;
2481 ustrClassName
.Length
= (USHORT
)min(lstrClassName
.Length
, MAXUSHORT
); // FIXME: LARGE_STRING truncated
2482 ustrClassName
.MaximumLength
= (USHORT
)min(lstrClassName
.MaximumLength
, MAXUSHORT
);
2485 /* Fill the CREATESTRUCTW */
2486 /* we will keep here the original parameters */
2488 Cs
.lpCreateParams
= lpParam
;
2489 Cs
.hInstance
= hInstance
;
2491 Cs
.hwndParent
= hWndParent
;
2496 Cs
.lpszName
= (LPCWSTR
) plstrWindowName
->Buffer
;
2497 if (IS_ATOM(plstrClassName
))
2498 Cs
.lpszClass
= (LPCWSTR
) plstrClassName
;
2500 Cs
.lpszClass
= (LPCWSTR
) plstrClassName
->Buffer
;
2501 Cs
.dwExStyle
= dwExStyle
;
2503 UserEnterExclusive();
2505 /* Call the internal function */
2506 pwnd
= co_UserCreateWindowEx(&Cs
, &ustrClassName
, plstrWindowName
, acbiBuffer
);
2510 ERR("co_UserCreateWindowEx failed!\n");
2512 hwnd
= pwnd
? UserHMGetHandle(pwnd
) : NULL
;
2517 if (lstrWindowName
.Buffer
)
2519 ExFreePoolWithTag(lstrWindowName
.Buffer
, TAG_STRING
);
2521 if (lstrClassName
.Buffer
)
2523 ExFreePoolWithTag(lstrClassName
.Buffer
, TAG_STRING
);
2530 BOOLEAN FASTCALL
co_UserDestroyWindow(PWND Window
)
2537 ASSERT_REFS_CO(Window
); // FIXME: Temp HACK?
2539 hWnd
= Window
->head
.h
;
2540 ti
= PsGetCurrentThreadWin32Thread();
2542 TRACE("co_UserDestroyWindow \n");
2544 /* Check for owner thread */
2545 if ( Window
->head
.pti
!= PsGetCurrentThreadWin32Thread())
2547 /* Check if we are destroying the desktop window */
2548 if (! ((Window
->head
.rpdesk
->dwDTFlags
& DF_DESTROYED
) && Window
== Window
->head
.rpdesk
->pDeskInfo
->spwnd
))
2550 EngSetLastError(ERROR_ACCESS_DENIED
);
2555 /* If window was created successfully and it is hooked */
2556 if ((Window
->state2
& WNDS2_WMCREATEMSGPROCESSED
))
2558 if (co_HOOK_CallHooks(WH_CBT
, HCBT_DESTROYWND
, (WPARAM
) hWnd
, 0))
2560 ERR("Destroy Window WH_CBT Call Hook return!\n");
2565 if (Window
->pcls
->atomClassName
!= gpsi
->atomSysClass
[ICLS_IME
])
2567 if ((Window
->style
& (WS_POPUP
|WS_CHILD
)) != WS_CHILD
)
2569 if (Window
->spwndOwner
)
2571 ERR("DestroyWindow Owner out.\n");
2572 //UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE);
2577 /* Inform the parent */
2578 if (Window
->style
& WS_CHILD
)
2580 IntSendParentNotify(Window
, WM_DESTROY
);
2583 /* Look whether the focus is within the tree of windows we will
2586 if (!co_WinPosShowWindow(Window
, SW_HIDE
))
2588 if (ti
->MessageQueue
->spwndActive
== Window
&& ti
->MessageQueue
== IntGetFocusMessageQueue())
2590 co_WinPosActivateOtherWindow(Window
);
2594 // Adjust last active.
2595 if ((pwndTemp
= Window
->spwndOwner
))
2597 while (pwndTemp
->spwndOwner
)
2598 pwndTemp
= pwndTemp
->spwndOwner
;
2600 if (pwndTemp
->spwndLastActive
== Window
)
2601 pwndTemp
->spwndLastActive
= Window
->spwndOwner
;
2604 if (Window
->spwndParent
&& IntIsWindow(Window
->head
.h
))
2606 if ((Window
->style
& (WS_POPUP
| WS_CHILD
)) == WS_CHILD
)
2608 if (!IntIsTopLevelWindow(Window
))
2610 ERR("DestroyWindow Parent out.\n");
2611 //UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE);
2616 if (Window
->head
.pti
->MessageQueue
->spwndActive
== Window
)
2617 Window
->head
.pti
->MessageQueue
->spwndActive
= NULL
;
2618 if (Window
->head
.pti
->MessageQueue
->spwndFocus
== Window
)
2619 Window
->head
.pti
->MessageQueue
->spwndFocus
= NULL
;
2620 if (Window
->head
.pti
->MessageQueue
->spwndActivePrev
== Window
)
2621 Window
->head
.pti
->MessageQueue
->spwndActivePrev
= NULL
;
2622 if (Window
->head
.pti
->MessageQueue
->spwndCapture
== Window
)
2623 Window
->head
.pti
->MessageQueue
->spwndCapture
= NULL
;
2626 * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
2629 if ((ti
!= NULL
) && (ti
->pDeskInfo
!= NULL
))
2631 if (ti
->pDeskInfo
->hShellWindow
== hWnd
)
2633 ERR("Destroying the ShellWindow!\n");
2634 ti
->pDeskInfo
->hShellWindow
= NULL
;
2638 IntEngWindowChanged(Window
, WOC_DELETE
);
2640 if (!IntIsWindow(Window
->head
.h
))
2645 /* Recursively destroy owned windows */
2647 if (! (Window
->style
& WS_CHILD
))
2651 BOOL GotOne
= FALSE
;
2654 PWND Child
, Desktop
;
2656 Desktop
= IntIsDesktopWindow(Window
) ? Window
:
2657 UserGetWindowObject(IntGetDesktopWindow());
2658 Children
= IntWinListChildren(Desktop
);
2662 for (ChildHandle
= Children
; *ChildHandle
; ++ChildHandle
)
2664 Child
= UserGetWindowObject(*ChildHandle
);
2667 if (Child
->spwndOwner
!= Window
)
2672 if (IntWndBelongsToThread(Child
, PsGetCurrentThreadWin32Thread()))
2674 USER_REFERENCE_ENTRY ChildRef
;
2675 UserRefObjectCo(Child
, &ChildRef
); // Temp HACK?
2676 co_UserDestroyWindow(Child
);
2677 UserDerefObjectCo(Child
); // Temp HACK?
2683 if (Child
->spwndOwner
!= NULL
)
2685 Child
->spwndOwner
= NULL
;
2689 ExFreePoolWithTag(Children
, USERTAG_WINDOWLIST
);
2698 /* Generate mouse move message for the next window */
2699 msg
.message
= WM_MOUSEMOVE
;
2700 msg
.wParam
= UserGetMouseButtonsState();
2701 msg
.lParam
= MAKELPARAM(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
2702 msg
.pt
= gpsi
->ptCursor
;
2703 co_MsqInsertMouseMessage(&msg
, 0, 0, TRUE
);
2705 if (!IntIsWindow(Window
->head
.h
))
2710 /* Destroy the window storage */
2711 co_UserFreeWindow(Window
, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE
);
2721 NtUserDestroyWindow(HWND Wnd
)
2724 DECLARE_RETURN(BOOLEAN
);
2726 USER_REFERENCE_ENTRY Ref
;
2728 TRACE("Enter NtUserDestroyWindow\n");
2729 UserEnterExclusive();
2731 if (!(Window
= UserGetWindowObject(Wnd
)))
2736 UserRefObjectCo(Window
, &Ref
); // FIXME: Dunno if win should be reffed during destroy...
2737 ret
= co_UserDestroyWindow(Window
);
2738 UserDerefObjectCo(Window
); // FIXME: Dunno if win should be reffed during destroy...
2743 TRACE("Leave NtUserDestroyWindow, ret=%i\n",_ret_
);
2749 static HWND FASTCALL
2750 IntFindWindow(PWND Parent
,
2753 PUNICODE_STRING WindowName
)
2755 BOOL CheckWindowName
;
2758 UNICODE_STRING CurrentWindowName
;
2762 CheckWindowName
= WindowName
->Buffer
!= 0;
2764 if((List
= IntWinListChildren(Parent
)))
2769 /* skip handles before and including ChildAfter */
2770 while(*phWnd
&& (*(phWnd
++) != ChildAfter
->head
.h
))
2774 /* search children */
2778 if(!(Child
= UserGetWindowObject(*(phWnd
++))))
2783 /* Do not send WM_GETTEXT messages in the kernel mode version!
2784 The user mode version however calls GetWindowText() which will
2785 send WM_GETTEXT messages to windows belonging to its processes */
2786 if (!ClassAtom
|| Child
->pcls
->atomClassName
== ClassAtom
)
2788 // FIXME: LARGE_STRING truncated
2789 CurrentWindowName
.Buffer
= Child
->strName
.Buffer
;
2790 CurrentWindowName
.Length
= (USHORT
)min(Child
->strName
.Length
, MAXUSHORT
);
2791 CurrentWindowName
.MaximumLength
= (USHORT
)min(Child
->strName
.MaximumLength
, MAXUSHORT
);
2792 if(!CheckWindowName
||
2793 (Child
->strName
.Length
< 0xFFFF &&
2794 !RtlCompareUnicodeString(WindowName
, &CurrentWindowName
, TRUE
)))
2796 Ret
= Child
->head
.h
;
2801 ExFreePoolWithTag(List
, USERTAG_WINDOWLIST
);
2809 * Searches a window's children for a window with the specified
2812 * hwndParent = The window whose childs are to be searched.
2814 * HWND_MESSAGE = message-only windows
2816 * hwndChildAfter = Search starts after this child window.
2817 * NULL = start from beginning
2819 * ucClassName = Class name to search for
2820 * Reguired parameter.
2822 * ucWindowName = Window name
2823 * ->Buffer == NULL = don't care
2826 * The HWND of the window if it was found, otherwise NULL
2832 NtUserFindWindowEx(HWND hwndParent
,
2833 HWND hwndChildAfter
,
2834 PUNICODE_STRING ucClassName
,
2835 PUNICODE_STRING ucWindowName
,
2838 PWND Parent
, ChildAfter
;
2839 UNICODE_STRING ClassName
= {0}, WindowName
= {0};
2840 HWND Desktop
, Ret
= NULL
;
2841 BOOL DoMessageWnd
= FALSE
;
2842 RTL_ATOM ClassAtom
= (RTL_ATOM
)0;
2843 DECLARE_RETURN(HWND
);
2845 TRACE("Enter NtUserFindWindowEx\n");
2848 if (ucClassName
!= NULL
|| ucWindowName
!= NULL
)
2852 if (ucClassName
!= NULL
)
2854 ClassName
= ProbeForReadUnicodeString(ucClassName
);
2855 if (ClassName
.Length
!= 0)
2857 ProbeForRead(ClassName
.Buffer
,
2861 else if (!IS_ATOM(ClassName
.Buffer
))
2863 EngSetLastError(ERROR_INVALID_PARAMETER
);
2867 if (!IntGetAtomFromStringOrAtom(&ClassName
,
2874 if (ucWindowName
!= NULL
)
2876 WindowName
= ProbeForReadUnicodeString(ucWindowName
);
2877 if (WindowName
.Length
!= 0)
2879 ProbeForRead(WindowName
.Buffer
,
2885 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2887 SetLastNtError(_SEH2_GetExceptionCode());
2888 _SEH2_YIELD(RETURN(NULL
));
2892 if (ucClassName
!= NULL
)
2894 if (ClassName
.Length
== 0 && ClassName
.Buffer
!= NULL
&&
2895 !IS_ATOM(ClassName
.Buffer
))
2897 EngSetLastError(ERROR_INVALID_PARAMETER
);
2900 else if (ClassAtom
== (RTL_ATOM
)0)
2902 /* LastError code was set by IntGetAtomFromStringOrAtom */
2908 Desktop
= IntGetCurrentThreadDesktopWindow();
2910 if(hwndParent
== NULL
)
2912 hwndParent
= Desktop
;
2913 DoMessageWnd
= TRUE
;
2915 else if(hwndParent
== HWND_MESSAGE
)
2917 hwndParent
= IntGetMessageWindow();
2920 if(!(Parent
= UserGetWindowObject(hwndParent
)))
2926 if(hwndChildAfter
&& !(ChildAfter
= UserGetWindowObject(hwndChildAfter
)))
2933 if(Parent
->head
.h
== Desktop
)
2936 PWND TopLevelWindow
;
2937 BOOLEAN CheckWindowName
;
2938 BOOLEAN WindowMatches
;
2939 BOOLEAN ClassMatches
;
2941 /* windows searches through all top-level windows if the parent is the desktop
2944 if((List
= IntWinListChildren(Parent
)))
2950 /* skip handles before and including ChildAfter */
2951 while(*phWnd
&& (*(phWnd
++) != ChildAfter
->head
.h
))
2955 CheckWindowName
= WindowName
.Buffer
!= 0;
2957 /* search children */
2960 UNICODE_STRING ustr
;
2962 if(!(TopLevelWindow
= UserGetWindowObject(*(phWnd
++))))
2967 /* Do not send WM_GETTEXT messages in the kernel mode version!
2968 The user mode version however calls GetWindowText() which will
2969 send WM_GETTEXT messages to windows belonging to its processes */
2970 ustr
.Buffer
= TopLevelWindow
->strName
.Buffer
;
2971 ustr
.Length
= (USHORT
)min(TopLevelWindow
->strName
.Length
, MAXUSHORT
); // FIXME:LARGE_STRING truncated
2972 ustr
.MaximumLength
= (USHORT
)min(TopLevelWindow
->strName
.MaximumLength
, MAXUSHORT
);
2973 WindowMatches
= !CheckWindowName
||
2974 (TopLevelWindow
->strName
.Length
< 0xFFFF &&
2975 !RtlCompareUnicodeString(&WindowName
, &ustr
, TRUE
));
2976 ClassMatches
= (ClassAtom
== (RTL_ATOM
)0) ||
2977 ClassAtom
== TopLevelWindow
->pcls
->atomClassName
;
2979 if (WindowMatches
&& ClassMatches
)
2981 Ret
= TopLevelWindow
->head
.h
;
2985 if (IntFindWindow(TopLevelWindow
, NULL
, ClassAtom
, &WindowName
))
2987 /* window returns the handle of the top-level window, in case it found
2989 Ret
= TopLevelWindow
->head
.h
;
2994 ExFreePoolWithTag(List
, USERTAG_WINDOWLIST
);
2999 ERR("FindWindowEx: Not Desktop Parent!\n");
3000 Ret
= IntFindWindow(Parent
, ChildAfter
, ClassAtom
, &WindowName
);
3003 if (Ret
== NULL
&& DoMessageWnd
)
3007 if((MsgWindows
= UserGetWindowObject(IntGetMessageWindow())))
3009 Ret
= IntFindWindow(MsgWindows
, ChildAfter
, ClassAtom
, &WindowName
);
3013 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3015 SetLastNtError(_SEH2_GetExceptionCode());
3023 TRACE("Leave NtUserFindWindowEx, ret %i\n",_ret_
);
3032 PWND FASTCALL
UserGetAncestor(PWND Wnd
, UINT Type
)
3034 PWND WndAncestor
, Parent
;
3036 if (Wnd
->head
.h
== IntGetDesktopWindow())
3045 WndAncestor
= Wnd
->spwndParent
;
3056 if(!(Parent
= WndAncestor
->spwndParent
))
3060 if(IntIsDesktopWindow(Parent
))
3065 WndAncestor
= Parent
;
3076 Parent
= IntGetParent(WndAncestor
);
3083 WndAncestor
= Parent
;
3101 NtUserGetAncestor(HWND hWnd
, UINT Type
)
3103 PWND Window
, Ancestor
;
3104 DECLARE_RETURN(HWND
);
3106 TRACE("Enter NtUserGetAncestor\n");
3107 UserEnterExclusive();
3109 if (!(Window
= UserGetWindowObject(hWnd
)))
3114 Ancestor
= UserGetAncestor(Window
, Type
);
3115 /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3117 RETURN(Ancestor
? Ancestor
->head
.h
: NULL
);
3120 TRACE("Leave NtUserGetAncestor, ret=%i\n",_ret_
);
3128 NtUserGetComboBoxInfo(
3133 DECLARE_RETURN(BOOL
);
3135 TRACE("Enter NtUserGetComboBoxInfo\n");
3138 if (!(Wnd
= UserGetWindowObject(hWnd
)))
3147 sizeof(COMBOBOXINFO
),
3151 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3153 SetLastNtError(_SEH2_GetExceptionCode());
3154 _SEH2_YIELD(RETURN(FALSE
));
3158 // Pass the user pointer, it was already probed.
3159 RETURN( (BOOL
) co_IntSendMessage( Wnd
->head
.h
, CB_GETCOMBOBOXINFO
, 0, (LPARAM
)pcbi
));
3162 TRACE("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_
);
3170 NtUserGetListBoxInfo(
3174 DECLARE_RETURN(DWORD
);
3176 TRACE("Enter NtUserGetListBoxInfo\n");
3179 if (!(Wnd
= UserGetWindowObject(hWnd
)))
3184 RETURN( (DWORD
) co_IntSendMessage( Wnd
->head
.h
, LB_GETLISTBOXINFO
, 0, 0 ));
3187 TRACE("Leave NtUserGetListBoxInfo, ret=%i\n",_ret_
);
3195 * The NtUserSetParent function changes the parent window of the specified
3199 * The new parent window and the child window must belong to the same
3200 * application. If the window identified by the hWndChild parameter is
3201 * visible, the system performs the appropriate redrawing and repainting.
3202 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3203 * or WS_POPUP window styles of the window whose parent is being changed.
3210 NtUserSetParent(HWND hWndChild
, HWND hWndNewParent
)
3212 DECLARE_RETURN(HWND
);
3214 TRACE("Enter NtUserSetParent\n");
3215 UserEnterExclusive();
3218 Check Parent first from user space, set it here.
3222 hWndNewParent
= IntGetDesktopWindow();
3224 else if (hWndNewParent
== HWND_MESSAGE
)
3226 hWndNewParent
= IntGetMessageWindow();
3229 RETURN( co_UserSetParent(hWndChild
, hWndNewParent
));
3232 TRACE("Leave NtUserSetParent, ret=%i\n",_ret_
);
3238 * UserGetShellWindow
3240 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3245 HWND FASTCALL
UserGetShellWindow(VOID
)
3247 PWINSTATION_OBJECT WinStaObject
;
3250 NTSTATUS Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
3255 if (!NT_SUCCESS(Status
))
3257 SetLastNtError(Status
);
3261 Ret
= (HWND
)WinStaObject
->ShellWindow
;
3263 ObDereferenceObject(WinStaObject
);
3268 * NtUserSetShellWindowEx
3270 * This is undocumented function to set global shell window. The global
3271 * shell window has special handling of window position.
3277 NtUserSetShellWindowEx(HWND hwndShell
, HWND hwndListView
)
3279 PWINSTATION_OBJECT WinStaObject
;
3280 PWND WndShell
, WndListView
;
3281 DECLARE_RETURN(BOOL
);
3282 USER_REFERENCE_ENTRY Ref
;
3286 TRACE("Enter NtUserSetShellWindowEx\n");
3287 UserEnterExclusive();
3289 if (!(WndShell
= UserGetWindowObject(hwndShell
)))
3294 if(!(WndListView
= UserGetWindowObject(hwndListView
)))
3299 Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
3304 if (!NT_SUCCESS(Status
))
3306 SetLastNtError(Status
);
3311 * Test if we are permitted to change the shell window.
3313 if (WinStaObject
->ShellWindow
)