reactos/reactos/subsystems/win32/win32k/ntuser/window.c
2007-10-30 01:24:47 +00:00

4811 lines
111 KiB
C

/*
* ReactOS W32 Subsystem
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PURPOSE: Windows
* FILE: subsys/win32k/ntuser/window.c
* PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
* REVISION HISTORY:
* 06-06-2001 CSH Created
*/
/* INCLUDES ******************************************************************/
#include <w32k.h>
#define NDEBUG
#include <debug.h>
/* dialog resources appear to pass this in 16 bits, handle them properly */
#define CW_USEDEFAULT16 (0x8000)
#define POINT_IN_RECT(p, r) (((r.bottom >= p.y) && (r.top <= p.y))&&((r.left <= p.x )&&( r.right >= p.x )))
/* PRIVATE FUNCTIONS **********************************************************/
/*
* InitWindowImpl
*
* Initialize windowing implementation.
*/
NTSTATUS FASTCALL
InitWindowImpl(VOID)
{
return STATUS_SUCCESS;
}
/*
* CleanupWindowImpl
*
* Cleanup windowing implementation.
*/
NTSTATUS FASTCALL
CleanupWindowImpl(VOID)
{
return STATUS_SUCCESS;
}
/* HELPER FUNCTIONS ***********************************************************/
PWINDOW_OBJECT FASTCALL IntGetWindowObject(HWND hWnd)
{
PWINDOW_OBJECT Window;
if (!hWnd) return NULL;
Window = UserGetWindowObject(hWnd);
if (Window)
{
ASSERT(USER_BODY_TO_HEADER(Window)->RefCount >= 0);
USER_BODY_TO_HEADER(Window)->RefCount++;
}
return Window;
}
/* temp hack */
PWINDOW_OBJECT FASTCALL UserGetWindowObject(HWND hWnd)
{
PW32THREADINFO ti;
PWINDOW_OBJECT Window;
if (PsGetCurrentProcess() != PsInitialSystemProcess)
{
ti = GetW32ThreadInfo();
if (ti == NULL)
{
SetLastWin32Error(ERROR_ACCESS_DENIED);
return NULL;
}
}
if (!hWnd)
{
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
return NULL;
}
Window = (PWINDOW_OBJECT)UserGetObject(gHandleTable, hWnd, otWindow);
if (!Window || 0 != (Window->Status & WINDOWSTATUS_DESTROYED))
{
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
return NULL;
}
ASSERT(USER_BODY_TO_HEADER(Window)->RefCount >= 0);
return Window;
}
/*
* IntIsWindow
*
* The function determines whether the specified window handle identifies
* an existing window.
*
* Parameters
* hWnd
* Handle to the window to test.
*
* Return Value
* If the window handle identifies an existing window, the return value
* is TRUE. If the window handle does not identify an existing window,
* the return value is FALSE.
*/
BOOL FASTCALL
IntIsWindow(HWND hWnd)
{
PWINDOW_OBJECT Window;
if (!(Window = UserGetWindowObject(hWnd)))
return FALSE;
return TRUE;
}
/*
Caller must NOT dereference retval!
But if caller want the returned value to persist spanning a co_ call,
it must reference the value (because the owner is not garanteed to
exist just because the owned window exist)!
*/
PWINDOW_OBJECT FASTCALL
IntGetParent(PWINDOW_OBJECT Wnd)
{
if (Wnd->Style & WS_POPUP)
{
return UserGetWindowObject(Wnd->hOwner);
}
else if (Wnd->Style & WS_CHILD)
{
return Wnd->Parent;
}
return NULL;
}
/*
Caller must NOT dereference retval!
But if caller want the returned value to persist spanning a co_ call,
it must reference the value (because the owner is not garanteed to
exist just because the owned window exist)!
*/
PWINDOW_OBJECT FASTCALL
IntGetOwner(PWINDOW_OBJECT Wnd)
{
return UserGetWindowObject(Wnd->hOwner);
}
/*
* IntWinListChildren
*
* Compile a list of all child window handles from given window.
*
* Remarks
* This function is similar to Wine WIN_ListChildren. The caller
* must free the returned list with ExFreePool.
*/
HWND* FASTCALL
IntWinListChildren(PWINDOW_OBJECT Window)
{
PWINDOW_OBJECT Child;
HWND *List;
UINT Index, NumChildren = 0;
for (Child = Window->FirstChild; Child; Child = Child->NextSibling)
++NumChildren;
List = ExAllocatePoolWithTag(PagedPool, (NumChildren + 1) * sizeof(HWND), TAG_WINLIST);
if(!List)
{
DPRINT1("Failed to allocate memory for children array\n");
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
for (Child = Window->FirstChild, Index = 0;
Child != NULL;
Child = Child->NextSibling, ++Index)
List[Index] = Child->hSelf;
List[Index] = NULL;
return List;
}
/***********************************************************************
* IntSendDestroyMsg
*/
static void IntSendDestroyMsg(HWND hWnd)
{
PWINDOW_OBJECT Window;
#if 0 /* FIXME */
GUITHREADINFO info;
if (GetGUIThreadInfo(GetCurrentThreadId(), &info))
{
if (hWnd == info.hwndCaret)
{
DestroyCaret();
}
}
#endif
Window = UserGetWindowObject(hWnd);
if (Window)
{
// USER_REFERENCE_ENTRY Ref;
// UserRefObjectCo(Window, &Ref);
if (!IntGetOwner(Window) && !IntGetParent(Window))
{
co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (LPARAM) hWnd);
}
// UserDerefObjectCo(Window);
}
/* The window could already be destroyed here */
/*
* Send the WM_DESTROY to the window.
*/
co_IntSendMessage(hWnd, WM_DESTROY, 0, 0);
/*
* This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
* make sure that the window still exists when we come back.
*/
#if 0 /* FIXME */
if (IsWindow(Wnd))
{
HWND* pWndArray;
int i;
if (!(pWndArray = WIN_ListChildren( hwnd )))
return;
/* start from the end (FIXME: is this needed?) */
for (i = 0; pWndArray[i]; i++)
;
while (--i >= 0)
{
if (IsWindow( pWndArray[i] ))
WIN_SendDestroyMsg( pWndArray[i] );
}
HeapFree(GetProcessHeap(), 0, pWndArray);
}
else
{
DPRINT("destroyed itself while in WM_DESTROY!\n");
}
#endif
}
/***********************************************************************
* IntDestroyWindow
*
* Destroy storage associated to a window. "Internals" p.358
*
* This is the "functional" DestroyWindows function ei. all stuff
* done in CreateWindow is undone here and not in DestroyWindow:-P
*/
static LRESULT co_UserFreeWindow(PWINDOW_OBJECT Window,
PW32PROCESS ProcessData,
PW32THREAD ThreadData,
BOOLEAN SendMessages)
{
HWND *Children;
HWND *ChildHandle;
PWINDOW_OBJECT Child;
PMENU_OBJECT Menu;
BOOLEAN BelongsToThreadData;
ASSERT(Window);
if(Window->Status & WINDOWSTATUS_DESTROYING)
{
DPRINT("Tried to call IntDestroyWindow() twice\n");
return 0;
}
Window->Status |= WINDOWSTATUS_DESTROYING;
Window->Style &= ~WS_VISIBLE;
/* remove the window already at this point from the thread window list so we
don't get into trouble when destroying the thread windows while we're still
in IntDestroyWindow() */
RemoveEntryList(&Window->ThreadListEntry);
BelongsToThreadData = IntWndBelongsToThread(Window, ThreadData);
IntDeRegisterShellHookWindow(Window->hSelf);
if(SendMessages)
{
/* Send destroy messages */
IntSendDestroyMsg(Window->hSelf);
}
/* free child windows */
Children = IntWinListChildren(Window);
if (Children)
{
for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
{
if ((Child = IntGetWindowObject(*ChildHandle)))
{
if(!IntWndBelongsToThread(Child, ThreadData))
{
/* send WM_DESTROY messages to windows not belonging to the same thread */
IntSendDestroyMsg(Child->hSelf);
}
else
co_UserFreeWindow(Child, ProcessData, ThreadData, SendMessages);
UserDerefObject(Child);
}
}
ExFreePool(Children);
}
if(SendMessages)
{
/*
* Clear the update region to make sure no WM_PAINT messages will be
* generated for this window while processing the WM_NCDESTROY.
*/
co_UserRedrawWindow(Window, NULL, 0,
RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE |
RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
if(BelongsToThreadData)
co_IntSendMessage(Window->hSelf, WM_NCDESTROY, 0, 0);
}
MsqRemoveTimersWindow(ThreadData->MessageQueue, Window->hSelf);
/* flush the message queue */
MsqRemoveWindowMessagesFromQueue(Window);
/* from now on no messages can be sent to this window anymore */
Window->Status |= WINDOWSTATUS_DESTROYED;
/* don't remove the WINDOWSTATUS_DESTROYING bit */
/* reset shell window handles */
if(ThreadData->Desktop)
{
if (Window->hSelf == ThreadData->Desktop->WindowStation->ShellWindow)
ThreadData->Desktop->WindowStation->ShellWindow = NULL;
if (Window->hSelf == ThreadData->Desktop->WindowStation->ShellListView)
ThreadData->Desktop->WindowStation->ShellListView = NULL;
}
/* Unregister hot keys */
UnregisterWindowHotKeys (Window);
/* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
#if 0 /* FIXME */
WinPosCheckInternalPos(Window->hSelf);
if (Window->hSelf == GetCapture())
{
ReleaseCapture();
}
/* free resources associated with the window */
TIMER_RemoveWindowTimers(Window->hSelf);
#endif
if (!(Window->Style & WS_CHILD) && Window->IDMenu
&& (Menu = UserGetMenuObject((HMENU)Window->IDMenu)))
{
IntDestroyMenuObject(Menu, TRUE, TRUE);
Window->IDMenu = 0;
}
if(Window->SystemMenu
&& (Menu = UserGetMenuObject(Window->SystemMenu)))
{
IntDestroyMenuObject(Menu, TRUE, TRUE);
Window->SystemMenu = (HMENU)0;
}
DceFreeWindowDCE(Window); /* Always do this to catch orphaned DCs */
#if 0 /* FIXME */
WINPROC_FreeProc(Window->winproc, WIN_PROC_WINDOW);
CLASS_RemoveWindow(Window->Class);
#endif
IntUnlinkWindow(Window);
UserRefObject(Window);
ObmDeleteObject(Window->hSelf, otWindow);
IntDestroyScrollBars(Window);
/* dereference the class */
IntDereferenceClass(Window->Class,
Window->ti->Desktop,
Window->ti->kpi);
Window->Class = NULL;
if(Window->WindowRegion)
{
NtGdiDeleteObject(Window->WindowRegion);
}
RtlFreeUnicodeString(&Window->WindowName);
UserDerefObject(Window);
IntClipboardFreeWindow(Window);
return 0;
}
VOID FASTCALL
IntGetWindowBorderMeasures(PWINDOW_OBJECT Window, UINT *cx, UINT *cy)
{
if(HAS_DLGFRAME(Window->Style, Window->ExStyle) && !(Window->Style & WS_MINIMIZE))
{
*cx = UserGetSystemMetrics(SM_CXDLGFRAME);
*cy = UserGetSystemMetrics(SM_CYDLGFRAME);
}
else
{
if(HAS_THICKFRAME(Window->Style, Window->ExStyle)&& !(Window->Style & WS_MINIMIZE))
{
*cx = UserGetSystemMetrics(SM_CXFRAME);
*cy = UserGetSystemMetrics(SM_CYFRAME);
}
else if(HAS_THINFRAME(Window->Style, Window->ExStyle))
{
*cx = UserGetSystemMetrics(SM_CXBORDER);
*cy = UserGetSystemMetrics(SM_CYBORDER);
}
else
{
*cx = *cy = 0;
}
}
}
static WNDPROC
IntGetWindowProc(IN PWINDOW_OBJECT Window,
IN BOOL Ansi)
{
ASSERT(UserIsEnteredExclusive() == TRUE);
if (Window->IsSystem)
{
return (Ansi ? Window->WndProcExtra : Window->WndProc);
}
else
{
if (!Ansi == Window->Unicode)
{
return Window->WndProc;
}
else
{
if (Window->CallProc != NULL)
{
return GetCallProcHandle(Window->CallProc);
}
else
{
PCALLPROC NewCallProc, CallProc;
NewCallProc = UserFindCallProc(Window->Class,
Window->WndProc,
Window->Unicode);
if (NewCallProc == NULL)
{
NewCallProc = CreateCallProc(Window->ti->Desktop,
Window->WndProc,
Window->Unicode,
Window->ti->kpi);
if (NewCallProc == NULL)
{
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
UserAddCallProcToClass(Window->Class,
NewCallProc);
}
CallProc = Window->CallProc;
Window->CallProc = NewCallProc;
return GetCallProcHandle((CallProc == NULL ? NewCallProc : CallProc));
}
}
}
}
BOOL FASTCALL
IntGetWindowInfo(PWINDOW_OBJECT Window, PWINDOWINFO pwi)
{
pwi->cbSize = sizeof(WINDOWINFO);
pwi->rcWindow = Window->WindowRect;
pwi->rcClient = Window->ClientRect;
pwi->dwStyle = Window->Style;
pwi->dwExStyle = Window->ExStyle;
pwi->dwWindowStatus = (UserGetForegroundWindow() == Window->hSelf); /* WS_ACTIVECAPTION */
IntGetWindowBorderMeasures(Window, &pwi->cxWindowBorders, &pwi->cyWindowBorders);
pwi->atomWindowType = (Window->Class ? Window->Class->Atom : 0);
pwi->wCreatorVersion = 0x400; /* FIXME - return a real version number */
return TRUE;
}
static BOOL FASTCALL
IntSetMenu(
PWINDOW_OBJECT Window,
HMENU Menu,
BOOL *Changed)
{
PMENU_OBJECT OldMenu, NewMenu = NULL;
if ((Window->Style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
{
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
return FALSE;
}
*Changed = (Window->IDMenu != (UINT) Menu);
if (! *Changed)
{
return TRUE;
}
if (Window->IDMenu)
{
OldMenu = IntGetMenuObject((HMENU) Window->IDMenu);
ASSERT(NULL == OldMenu || OldMenu->MenuInfo.Wnd == Window->hSelf);
}
else
{
OldMenu = NULL;
}
if (NULL != Menu)
{
NewMenu = IntGetMenuObject(Menu);
if (NULL == NewMenu)
{
if (NULL != OldMenu)
{
IntReleaseMenuObject(OldMenu);
}
SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
return FALSE;
}
if (NULL != NewMenu->MenuInfo.Wnd)
{
/* Can't use the same menu for two windows */
if (NULL != OldMenu)
{
IntReleaseMenuObject(OldMenu);
}
SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
return FALSE;
}
}
Window->IDMenu = (UINT) Menu;
if (NULL != NewMenu)
{
NewMenu->MenuInfo.Wnd = Window->hSelf;
IntReleaseMenuObject(NewMenu);
}
if (NULL != OldMenu)
{
OldMenu->MenuInfo.Wnd = NULL;
IntReleaseMenuObject(OldMenu);
}
return TRUE;
}
/* INTERNAL ******************************************************************/
VOID FASTCALL
co_DestroyThreadWindows(struct _ETHREAD *Thread)
{
PW32THREAD WThread;
PLIST_ENTRY Current;
PWINDOW_OBJECT Wnd;
USER_REFERENCE_ENTRY Ref;
WThread = (PW32THREAD)Thread->Tcb.Win32Thread;
while (!IsListEmpty(&WThread->WindowListHead))
{
Current = WThread->WindowListHead.Flink;
Wnd = CONTAINING_RECORD(Current, WINDOW_OBJECT, ThreadListEntry);
DPRINT("thread cleanup: while destroy wnds, wnd=0x%x\n",Wnd);
/* window removes itself from the list */
/*
fixme: it is critical that the window removes itself! if now, we will loop
here forever...
*/
//ASSERT(co_UserDestroyWindow(Wnd));
UserRefObjectCo(Wnd, &Ref);//faxme: temp hack??
if (!co_UserDestroyWindow(Wnd))
{
DPRINT1("Unable to destroy window 0x%x at thread cleanup... This is _VERY_ bad!\n", Wnd);
}
UserDerefObjectCo(Wnd);//faxme: temp hack??
}
}
/*!
* Internal function.
* Returns client window rectangle relative to the upper-left corner of client area.
*
* \note Does not check the validity of the parameters
*/
VOID FASTCALL
IntGetClientRect(PWINDOW_OBJECT Window, PRECT Rect)
{
ASSERT( Window );
ASSERT( Rect );
Rect->left = Rect->top = 0;
Rect->right = Window->ClientRect.right - Window->ClientRect.left;
Rect->bottom = Window->ClientRect.bottom - Window->ClientRect.top;
}
#if 0
HWND FASTCALL
IntGetFocusWindow(VOID)
{
PUSER_MESSAGE_QUEUE Queue;
PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
if( !pdo )
return NULL;
Queue = (PUSER_MESSAGE_QUEUE)pdo->ActiveMessageQueue;
if (Queue == NULL)
return(NULL);
else
return(Queue->FocusWindow);
}
#endif
PMENU_OBJECT FASTCALL
IntGetSystemMenu(PWINDOW_OBJECT Window, BOOL bRevert, BOOL RetMenu)
{
PMENU_OBJECT Menu, NewMenu = NULL, SysMenu = NULL, ret = NULL;
PW32THREAD W32Thread;
HMENU hNewMenu, hSysMenu;
ROSMENUITEMINFO ItemInfo;
if(bRevert)
{
W32Thread = PsGetCurrentThreadWin32Thread();
if(!W32Thread->Desktop)
return NULL;
if(Window->SystemMenu)
{
Menu = UserGetMenuObject(Window->SystemMenu);
if(Menu)
{
IntDestroyMenuObject(Menu, FALSE, TRUE);
Window->SystemMenu = (HMENU)0;
}
}
if(W32Thread->Desktop->WindowStation->SystemMenuTemplate)
{
/* clone system menu */
Menu = UserGetMenuObject(W32Thread->Desktop->WindowStation->SystemMenuTemplate);
if(!Menu)
return NULL;
NewMenu = IntCloneMenu(Menu);
if(NewMenu)
{
Window->SystemMenu = NewMenu->MenuInfo.Self;
NewMenu->MenuInfo.Flags |= MF_SYSMENU;
NewMenu->MenuInfo.Wnd = Window->hSelf;
ret = NewMenu;
//IntReleaseMenuObject(NewMenu);
}
}
else
{
hSysMenu = UserCreateMenu(FALSE);
if (NULL == hSysMenu)
{
return NULL;
}
SysMenu = IntGetMenuObject(hSysMenu);
if (NULL == SysMenu)
{
UserDestroyMenu(hSysMenu);
return NULL;
}
SysMenu->MenuInfo.Flags |= MF_SYSMENU;
SysMenu->MenuInfo.Wnd = Window->hSelf;
hNewMenu = co_IntLoadSysMenuTemplate();
if(!hNewMenu)
{
IntReleaseMenuObject(SysMenu);
UserDestroyMenu(hSysMenu);
return NULL;
}
Menu = IntGetMenuObject(hNewMenu);
if(!Menu)
{
IntReleaseMenuObject(SysMenu);
UserDestroyMenu(hSysMenu);
return NULL;
}
NewMenu = IntCloneMenu(Menu);
if(NewMenu)
{
NewMenu->MenuInfo.Flags |= MF_SYSMENU | MF_POPUP;
IntReleaseMenuObject(NewMenu);
UserSetMenuDefaultItem(NewMenu, SC_CLOSE, FALSE);
ItemInfo.cbSize = sizeof(MENUITEMINFOW);
ItemInfo.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_SUBMENU;
ItemInfo.fType = MF_POPUP;
ItemInfo.fState = MFS_ENABLED;
ItemInfo.dwTypeData = NULL;
ItemInfo.cch = 0;
ItemInfo.hSubMenu = NewMenu->MenuInfo.Self;
IntInsertMenuItem(SysMenu, (UINT) -1, TRUE, &ItemInfo);
Window->SystemMenu = SysMenu->MenuInfo.Self;
ret = SysMenu;
}
IntDestroyMenuObject(Menu, FALSE, TRUE);
}
if(RetMenu)
return ret;
else
return NULL;
}
else
{
if(Window->SystemMenu)
return IntGetMenuObject((HMENU)Window->SystemMenu);
else
return NULL;
}
}
BOOL FASTCALL
IntIsChildWindow(PWINDOW_OBJECT Parent, PWINDOW_OBJECT BaseWindow)
{
PWINDOW_OBJECT Window;
Window = BaseWindow;
while (Window)
{
if (Window == Parent)
{
return(TRUE);
}
if(!(Window->Style & WS_CHILD))
{
break;
}
Window = Window->Parent;
}
return(FALSE);
}
BOOL FASTCALL
IntIsWindowVisible(PWINDOW_OBJECT BaseWindow)
{
PWINDOW_OBJECT Window;
Window = BaseWindow;
while(Window)
{
if(!(Window->Style & WS_CHILD))
{
break;
}
if(!(Window->Style & WS_VISIBLE))
{
return FALSE;
}
Window = Window->Parent;
}
if(Window && Window->Style & WS_VISIBLE)
{
return TRUE;
}
return FALSE;
}
/* link the window into siblings and parent. children are kept in place. */
VOID FASTCALL
IntLinkWindow(
PWINDOW_OBJECT Wnd,
PWINDOW_OBJECT WndParent,
PWINDOW_OBJECT WndPrevSibling /* set to NULL if top sibling */
)
{
PWINDOW_OBJECT Parent;
Wnd->Parent = WndParent;
if ((Wnd->PrevSibling = WndPrevSibling))
{
/* link after WndPrevSibling */
if ((Wnd->NextSibling = WndPrevSibling->NextSibling))
Wnd->NextSibling->PrevSibling = Wnd;
else if ((Parent = Wnd->Parent))
{
if(Parent->LastChild == WndPrevSibling)
Parent->LastChild = Wnd;
}
Wnd->PrevSibling->NextSibling = Wnd;
}
else
{
/* link at top */
Parent = Wnd->Parent;
if ((Wnd->NextSibling = WndParent->FirstChild))
Wnd->NextSibling->PrevSibling = Wnd;
else if (Parent)
{
Parent->LastChild = Wnd;
Parent->FirstChild = Wnd;
return;
}
if(Parent)
{
Parent->FirstChild = Wnd;
}
}
}
HWND FASTCALL
IntSetOwner(HWND hWnd, HWND hWndNewOwner)
{
PWINDOW_OBJECT Wnd, WndOldOwner, WndNewOwner;
HWND ret;
Wnd = IntGetWindowObject(hWnd);
if(!Wnd)
return NULL;
WndOldOwner = IntGetWindowObject(Wnd->hOwner);
if (WndOldOwner)
{
ret = WndOldOwner->hSelf;
UserDerefObject(WndOldOwner);
}
else
{
ret = 0;
}
if((WndNewOwner = UserGetWindowObject(hWndNewOwner)))
{
Wnd->hOwner = hWndNewOwner;
}
else
Wnd->hOwner = NULL;
UserDerefObject(Wnd);
return ret;
}
PWINDOW_OBJECT FASTCALL
co_IntSetParent(PWINDOW_OBJECT Wnd, PWINDOW_OBJECT WndNewParent)
{
PWINDOW_OBJECT WndOldParent, Sibling, InsertAfter;
// HWND hWnd, hWndNewParent;
BOOL WasVisible;
ASSERT(Wnd);
ASSERT(WndNewParent);
ASSERT_REFS_CO(Wnd);
ASSERT_REFS_CO(WndNewParent);
// hWnd = Wnd->hSelf;
// hWndNewParent = WndNewParent->hSelf;
/*
* Windows hides the window first, then shows it again
* including the WM_SHOWWINDOW messages and all
*/
WasVisible = co_WinPosShowWindow(Wnd, SW_HIDE);
// /* Validate that window and parent still exist */
// if (!IntIsWindow(hWnd) || !IntIsWindow(hWndNewParent))
// return NULL;
/* Window must belong to current process */
if (Wnd->OwnerThread->ThreadsProcess != PsGetCurrentProcess())
return NULL;
WndOldParent = Wnd->Parent;
if (WndOldParent) UserRefObject(WndOldParent); /* caller must deref */
if (WndNewParent != WndOldParent)
{
IntUnlinkWindow(Wnd);
InsertAfter = NULL;
if (0 == (Wnd->ExStyle & WS_EX_TOPMOST))
{
/* Not a TOPMOST window, put after TOPMOSTs of new parent */
Sibling = WndNewParent->FirstChild;
while (NULL != Sibling && 0 != (Sibling->ExStyle & WS_EX_TOPMOST))
{
InsertAfter = Sibling;
Sibling = Sibling->NextSibling;
}
}
if (NULL == InsertAfter)
{
IntLinkWindow(Wnd, WndNewParent, InsertAfter /*prev sibling*/);
}
else
{
// UserRefObject(InsertAfter);
IntLinkWindow(Wnd, WndNewParent, InsertAfter /*prev sibling*/);
// UserDerefObject(InsertAfter);
}
}
/*
* SetParent additionally needs to make hwnd the top window
* in the z-order and send the expected WM_WINDOWPOSCHANGING and
* WM_WINDOWPOSCHANGED notification messages.
*/
co_WinPosSetWindowPos(Wnd, (0 == (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOP : HWND_TOPMOST),
0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE
| (WasVisible ? SWP_SHOWWINDOW : 0));
/*
* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
* for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE
*/
/*
* Validate that the old parent still exist, since it migth have been
* destroyed during the last callbacks to user-mode
*/
// if(WndOldParent)
// {
// if(!IntIsWindow(WndOldParent->hSelf))
// {
// UserDerefObject(WndOldParent);
// return NULL;
// }
/* don't dereference the window object here, it must be done by the caller
of IntSetParent() */
// return WndOldParent;
// }
return WndOldParent;//NULL;
}
BOOL FASTCALL
IntSetSystemMenu(PWINDOW_OBJECT Window, PMENU_OBJECT Menu)
{
PMENU_OBJECT OldMenu;
if(Window->SystemMenu)
{
OldMenu = IntGetMenuObject(Window->SystemMenu);
if(OldMenu)
{
OldMenu->MenuInfo.Flags &= ~ MF_SYSMENU;
IntReleaseMenuObject(OldMenu);
}
}
if(Menu)
{
/* FIXME check window style, propably return FALSE ? */
Window->SystemMenu = Menu->MenuInfo.Self;
Menu->MenuInfo.Flags |= MF_SYSMENU;
}
else
Window->SystemMenu = (HMENU)0;
return TRUE;
}
/* unlink the window from siblings and parent. children are kept in place. */
VOID FASTCALL
IntUnlinkWindow(PWINDOW_OBJECT Wnd)
{
PWINDOW_OBJECT WndParent = Wnd->Parent;
if (Wnd->NextSibling)
Wnd->NextSibling->PrevSibling = Wnd->PrevSibling;
else if (WndParent && WndParent->LastChild == Wnd)
WndParent->LastChild = Wnd->PrevSibling;
if (Wnd->PrevSibling)
Wnd->PrevSibling->NextSibling = Wnd->NextSibling;
else if (WndParent && WndParent->FirstChild == Wnd)
WndParent->FirstChild = Wnd->NextSibling;
Wnd->PrevSibling = Wnd->NextSibling = Wnd->Parent = NULL;
}
BOOL FASTCALL
IntAnyPopup(VOID)
{
PWINDOW_OBJECT Window, Child;
if(!(Window = UserGetWindowObject(IntGetDesktopWindow())))
{
return FALSE;
}
for(Child = Window->FirstChild; Child; Child = Child->NextSibling)
{
if(Child->hOwner && Child->Style & WS_VISIBLE)
{
/*
* The desktop has a popup window if one of them has
* an owner window and is visible
*/
return TRUE;
}
}
return FALSE;
}
BOOL FASTCALL
IntIsWindowInDestroy(PWINDOW_OBJECT Window)
{
return ((Window->Status & WINDOWSTATUS_DESTROYING) == WINDOWSTATUS_DESTROYING);
}
/* FUNCTIONS *****************************************************************/
/*
* @unimplemented
*/
DWORD STDCALL
NtUserAlterWindowStyle(DWORD Unknown0,
DWORD Unknown1,
DWORD Unknown2)
{
UNIMPLEMENTED
return(0);
}
/*
* As best as I can figure, this function is used by EnumWindows,
* EnumChildWindows, EnumDesktopWindows, & EnumThreadWindows.
*
* It's supposed to build a list of HWNDs to return to the caller.
* We can figure out what kind of list by what parameters are
* passed to us.
*/
/*
* @implemented
*/
ULONG
STDCALL
NtUserBuildHwndList(
HDESK hDesktop,
HWND hwndParent,
BOOLEAN bChildren,
ULONG dwThreadId,
ULONG lParam,
HWND* pWnd,
ULONG nBufSize)
{
NTSTATUS Status;
ULONG dwCount = 0;
if (hwndParent || !dwThreadId)
{
PDESKTOP_OBJECT Desktop;
PWINDOW_OBJECT Parent, Window;
if(!hwndParent)
{
if(hDesktop == NULL && !(Desktop = IntGetActiveDesktop()))
{
SetLastWin32Error(ERROR_INVALID_HANDLE);
return 0;
}
if(hDesktop)
{
Status = IntValidateDesktopHandle(hDesktop,
UserMode,
0,
&Desktop);
if(!NT_SUCCESS(Status))
{
SetLastWin32Error(ERROR_INVALID_HANDLE);
return 0;
}
}
hwndParent = Desktop->DesktopWindow;
}
else
{
hDesktop = 0;
}
if((Parent = UserGetWindowObject(hwndParent)) &&
(Window = Parent->FirstChild))
{
BOOL bGoDown = TRUE;
Status = STATUS_SUCCESS;
while(TRUE)
{
if (bGoDown)
{
if(dwCount++ < nBufSize && pWnd)
{
_SEH_TRY
{
ProbeForWrite(pWnd, sizeof(HWND), 1);
*pWnd = Window->hSelf;
pWnd++;
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END
if(!NT_SUCCESS(Status))
{
SetLastNtError(Status);
break;
}
}
if (Window->FirstChild && bChildren)
{
Window = Window->FirstChild;
continue;
}
bGoDown = FALSE;
}
if (Window->NextSibling)
{
Window = Window->NextSibling;
bGoDown = TRUE;
continue;
}
Window = Window->Parent;
if (Window == Parent)
{
break;
}
}
}
if(hDesktop)
{
ObDereferenceObject(Desktop);
}
}
else
{
PETHREAD Thread;
PW32THREAD W32Thread;
PLIST_ENTRY Current;
PWINDOW_OBJECT Window;
Status = PsLookupThreadByThreadId((HANDLE)dwThreadId, &Thread);
if(!NT_SUCCESS(Status))
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return 0;
}
if(!(W32Thread = (PW32THREAD)Thread->Tcb.Win32Thread))
{
ObDereferenceObject(Thread);
DPRINT("Thread is not a GUI Thread!\n");
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return 0;
}
Current = W32Thread->WindowListHead.Flink;
while(Current != &(W32Thread->WindowListHead))
{
Window = CONTAINING_RECORD(Current, WINDOW_OBJECT, ThreadListEntry);
ASSERT(Window);
if(dwCount < nBufSize && pWnd)
{
Status = MmCopyToCaller(pWnd++, &Window->hSelf, sizeof(HWND));
if(!NT_SUCCESS(Status))
{
SetLastNtError(Status);
break;
}
}
dwCount++;
Current = Current->Flink;
}
ObDereferenceObject(Thread);
}
return dwCount;
}
/*
* @implemented
*/
HWND STDCALL
NtUserChildWindowFromPointEx(HWND hwndParent,
LONG x,
LONG y,
UINT uiFlags)
{
PWINDOW_OBJECT Parent;
POINTL Pt;
HWND Ret;
HWND *List, *phWnd;
if(!(Parent = UserGetWindowObject(hwndParent)))
{
return NULL;
}
Pt.x = x;
Pt.y = y;
if(Parent->hSelf != IntGetDesktopWindow())
{
Pt.x += Parent->ClientRect.left;
Pt.y += Parent->ClientRect.top;
}
if(!IntPtInWindow(Parent, Pt.x, Pt.y))
{
return NULL;
}
Ret = Parent->hSelf;
if((List = IntWinListChildren(Parent)))
{
for(phWnd = List; *phWnd; phWnd++)
{
PWINDOW_OBJECT Child;
if((Child = UserGetWindowObject(*phWnd)))
{
if(!(Child->Style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE))
{
continue;
}
if((Child->Style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED))
{
continue;
}
if((Child->ExStyle & WS_EX_TRANSPARENT) && (uiFlags & CWP_SKIPTRANSPARENT))
{
continue;
}
if(IntPtInWindow(Child, Pt.x, Pt.y))
{
Ret = Child->hSelf;
break;
}
}
}
ExFreePool(List);
}
return Ret;
}
/*
* calculates the default position of a window
*/
BOOL FASTCALL
IntCalcDefPosSize(PWINDOW_OBJECT Parent, PWINDOW_OBJECT Window, RECT *rc, BOOL IncPos)
{
SIZE Sz;
POINT Pos = {0, 0};
if(Parent != NULL)
{
IntGdiIntersectRect(rc, rc, &Parent->ClientRect);
if(IncPos)
{
Pos.x = Parent->TiledCounter * (UserGetSystemMetrics(SM_CXSIZE) + UserGetSystemMetrics(SM_CXFRAME));
Pos.y = Parent->TiledCounter * (UserGetSystemMetrics(SM_CYSIZE) + UserGetSystemMetrics(SM_CYFRAME));
if(Pos.x > ((rc->right - rc->left) / 4) ||
Pos.y > ((rc->bottom - rc->top) / 4))
{
/* reset counter and position */
Pos.x = 0;
Pos.y = 0;
Parent->TiledCounter = 0;
}
Parent->TiledCounter++;
}
Pos.x += rc->left;
Pos.y += rc->top;
}
else
{
Pos.x = rc->left;
Pos.y = rc->top;
}
Sz.cx = EngMulDiv(rc->right - rc->left, 3, 4);
Sz.cy = EngMulDiv(rc->bottom - rc->top, 3, 4);
rc->left = Pos.x;
rc->top = Pos.y;
rc->right = rc->left + Sz.cx;
rc->bottom = rc->top + Sz.cy;
return TRUE;
}
/*
* @implemented
*/
HWND STDCALL
co_IntCreateWindowEx(DWORD dwExStyle,
PUNICODE_STRING ClassName,
PUNICODE_STRING WindowName,
DWORD dwStyle,
LONG x,
LONG y,
LONG nWidth,
LONG nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam,
DWORD dwShowMode,
BOOL bUnicodeWindow)
{
PWINSTATION_OBJECT WinSta;
PWINDOWCLASS *ClassLink, Class = NULL;
RTL_ATOM ClassAtom;
PWINDOW_OBJECT Window = NULL;
PWINDOW_OBJECT ParentWindow = NULL, OwnerWindow;
HWND ParentWindowHandle;
HWND OwnerWindowHandle;
PMENU_OBJECT SystemMenu;
HWND hWnd;
POINT Pos;
SIZE Size;
PW32THREADINFO ti = NULL;
#if 0
POINT MaxSize, MaxPos, MinTrack, MaxTrack;
#else
POINT MaxPos;
#endif
CREATESTRUCTW Cs;
CBT_CREATEWNDW CbtCreate;
LRESULT Result;
BOOL MenuChanged;
DECLARE_RETURN(HWND);
BOOL HasOwner;
USER_REFERENCE_ENTRY ParentRef, Ref;
ParentWindowHandle = PsGetCurrentThreadWin32Thread()->Desktop->DesktopWindow;
OwnerWindowHandle = NULL;
if (hWndParent == HWND_MESSAGE)
{
/*
* native ole32.OleInitialize uses HWND_MESSAGE to create the
* message window (style: WS_POPUP|WS_DISABLED)
*/
DPRINT1("FIXME - Parent is HWND_MESSAGE\n");
}
else if (hWndParent)
{
if ((dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
{ //temp hack
PWINDOW_OBJECT Par = UserGetWindowObject(hWndParent), Root;
if (Par && (Root = UserGetAncestor(Par, GA_ROOT)))
OwnerWindowHandle = Root->hSelf;
}
else
ParentWindowHandle = hWndParent;
}
else if ((dwStyle & (WS_CHILD | WS_POPUP)) == WS_CHILD)
{
SetLastWin32Error(ERROR_TLW_WITH_WSCHILD);
RETURN( (HWND)0); /* WS_CHILD needs a parent, but WS_POPUP doesn't */
}
// if (NULL != ParentWindowHandle)
// {
ParentWindow = UserGetWindowObject(ParentWindowHandle);
if (ParentWindow) UserRefObjectCo(ParentWindow, &ParentRef);
// }
// else
// {
// ParentWindow = NULL;
// }
/* FIXME: parent must belong to the current process */
/* Check the window station. */
ti = GetW32ThreadInfo();
if (ti == NULL || PsGetCurrentThreadWin32Thread()->Desktop == NULL)
{
DPRINT1("Thread is not attached to a desktop! Cannot create window!\n");
RETURN( (HWND)0);
}
/* Check the class. */
ClassAtom = IntGetClassAtom(ClassName,
hInstance,
ti->kpi,
&Class,
&ClassLink);
if (ClassAtom == (RTL_ATOM)0)
{
if (IS_ATOM(ClassName->Buffer))
{
DPRINT1("Class 0x%p not found\n", (DWORD_PTR) ClassName->Buffer);
}
else
{
DPRINT1("Class \"%wZ\" not found\n", ClassName);
}
SetLastWin32Error(ERROR_CANNOT_FIND_WND_CLASS);
RETURN((HWND)0);
}
Class = IntReferenceClass(Class,
ClassLink,
ti->Desktop);
if (Class == NULL)
{
DPRINT1("Failed to reference window class!\n");
RETURN(NULL);
}
WinSta = PsGetCurrentThreadWin32Thread()->Desktop->WindowStation;
//FIXME: Reference thread/desktop instead
ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0);
/* Create the window object. */
Window = (PWINDOW_OBJECT)
ObmCreateObject(gHandleTable, (PHANDLE)&hWnd,
otWindow, sizeof(WINDOW_OBJECT) + Class->WndExtra
);
DPRINT("Created object with handle %X\n", hWnd);
if (!Window)
{
ObDereferenceObject(WinSta);
SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
RETURN( (HWND)0);
}
UserRefObjectCo(Window, &Ref);
ObDereferenceObject(WinSta);
if (NULL == PsGetCurrentThreadWin32Thread()->Desktop->DesktopWindow)
{
/* If there is no desktop window yet, we must be creating it */
PsGetCurrentThreadWin32Thread()->Desktop->DesktopWindow = hWnd;
}
/*
* Fill out the structure describing it.
*/
Window->ti = ti;
Window->Class = Class;
Class = NULL;
Window->SystemMenu = (HMENU)0;
Window->ContextHelpId = 0;
Window->IDMenu = 0;
Window->Instance = hInstance;
Window->hSelf = hWnd;
if (!hMenu)
hMenu = Window->Class->hMenu;
if (0 != (dwStyle & WS_CHILD))
{
Window->IDMenu = (UINT) hMenu;
}
else
{
IntSetMenu(Window, hMenu, &MenuChanged);
}
Window->MessageQueue = PsGetCurrentThreadWin32Thread()->MessageQueue;
IntReferenceMessageQueue(Window->MessageQueue);
Window->Parent = ParentWindow;
if((OwnerWindow = UserGetWindowObject(OwnerWindowHandle)))
{
Window->hOwner = OwnerWindowHandle;
HasOwner = TRUE;
}
else
{
Window->hOwner = NULL;
HasOwner = FALSE;
}
Window->UserData = 0;
Window->IsSystem = Window->Class->System;
if (Window->Class->System)
{
/* NOTE: Always create a unicode window for system classes! */
Window->Unicode = TRUE;
Window->WndProc = Window->Class->WndProc;
Window->WndProcExtra = Window->Class->WndProcExtra;
}
else
{
Window->Unicode = Window->Class->Unicode;
Window->WndProc = Window->Class->WndProc;
Window->CallProc = NULL;
}
Window->OwnerThread = PsGetCurrentThread();
Window->FirstChild = NULL;
Window->LastChild = NULL;
Window->PrevSibling = NULL;
Window->NextSibling = NULL;
Window->ExtraDataSize = Window->Class->WndExtra;
/* extra window data */
if (Window->Class->WndExtra)
Window->ExtraData = (PCHAR)(Window + 1);
InitializeListHead(&Window->PropListHead);
InitializeListHead(&Window->WndObjListHead);
if (NULL != WindowName->Buffer)
{
Window->WindowName.MaximumLength = WindowName->MaximumLength;
Window->WindowName.Length = WindowName->Length;
Window->WindowName.Buffer = ExAllocatePoolWithTag(PagedPool, WindowName->MaximumLength,
TAG_STRING);
if (NULL == Window->WindowName.Buffer)
{
DPRINT1("Failed to allocate mem for window name\n");
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
RETURN( NULL);
}
RtlCopyMemory(Window->WindowName.Buffer, WindowName->Buffer, WindowName->MaximumLength);
}
else
{
RtlInitUnicodeString(&Window->WindowName, NULL);
}
/*
* This has been tested for WS_CHILD | WS_VISIBLE. It has not been
* tested for WS_POPUP
*/
if ((dwExStyle & WS_EX_DLGMODALFRAME) ||
((!(dwExStyle & WS_EX_STATICEDGE)) &&
(dwStyle & (WS_DLGFRAME | WS_THICKFRAME))))
dwExStyle |= WS_EX_WINDOWEDGE;
else
dwExStyle &= ~WS_EX_WINDOWEDGE;
/* Correct the window style. */
if (!(dwStyle & WS_CHILD))
{
dwStyle |= WS_CLIPSIBLINGS;
DPRINT("3: Style is now %lx\n", dwStyle);
if (!(dwStyle & WS_POPUP))
{
dwStyle |= WS_CAPTION;
Window->Flags |= WINDOWOBJECT_NEED_SIZE;
DPRINT("4: Style is now %lx\n", dwStyle);
}
}
/* create system menu */
if((dwStyle & WS_SYSMENU) &&
(dwStyle & WS_CAPTION) == WS_CAPTION)
{
SystemMenu = IntGetSystemMenu(Window, TRUE, TRUE);
if(SystemMenu)
{
Window->SystemMenu = SystemMenu->MenuInfo.Self;
IntReleaseMenuObject(SystemMenu);
}
}
/* Insert the window into the thread's window list. */
InsertTailList (&PsGetCurrentThreadWin32Thread()->WindowListHead, &Window->ThreadListEntry);
/* Allocate a DCE for this window. */
if (dwStyle & CS_OWNDC)
{
Window->Dce = DceAllocDCE(Window, DCE_WINDOW_DC);
}
/* FIXME: Handle "CS_CLASSDC" */
Pos.x = x;
Pos.y = y;
Size.cx = nWidth;
Size.cy = nHeight;
Window->ExStyle = dwExStyle;
Window->Style = dwStyle & ~WS_VISIBLE;
/* call hook */
Cs.lpCreateParams = lpParam;
Cs.hInstance = hInstance;
Cs.hMenu = hMenu;
Cs.hwndParent = hWndParent; //Pass the original Parent handle!
Cs.cx = Size.cx;
Cs.cy = Size.cy;
Cs.x = Pos.x;
Cs.y = Pos.y;
Cs.style = Window->Style;
Cs.lpszName = (LPCWSTR) WindowName;
Cs.lpszClass = (LPCWSTR) ClassName;
Cs.dwExStyle = dwExStyle;
CbtCreate.lpcs = &Cs;
CbtCreate.hwndInsertAfter = HWND_TOP;
if (co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) &CbtCreate))
{
/* FIXME - Delete window object and remove it from the thread windows list */
/* FIXME - delete allocated DCE */
DPRINT1("CBT-hook returned !0\n");
RETURN( (HWND) NULL);
}
x = Cs.x;
y = Cs.y;
nWidth = Cs.cx;
nHeight = Cs.cy;
/* default positioning for overlapped windows */
if(!(Window->Style & (WS_POPUP | WS_CHILD)))
{
RECT rc, WorkArea;
PRTL_USER_PROCESS_PARAMETERS ProcessParams;
BOOL CalculatedDefPosSize = FALSE;
IntGetDesktopWorkArea(((PW32THREAD)Window->OwnerThread->Tcb.Win32Thread)->Desktop, &WorkArea);
rc = WorkArea;
ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
if(x == CW_USEDEFAULT || x == CW_USEDEFAULT16)
{
CalculatedDefPosSize = IntCalcDefPosSize(ParentWindow, Window, &rc, TRUE);
if(ProcessParams->WindowFlags & STARTF_USEPOSITION)
{
ProcessParams->WindowFlags &= ~STARTF_USEPOSITION;
Pos.x = WorkArea.left + ProcessParams->StartingX;
Pos.y = WorkArea.top + ProcessParams->StartingY;
}
else
{
Pos.x = rc.left;
Pos.y = rc.top;
}
/*
According to wine, the ShowMode is set to y if x == CW_USEDEFAULT(16) and
y is something else. and Quote!
*/
/* Never believe Microsoft's documentation... CreateWindowEx doc says
* that if an overlapped window is created with WS_VISIBLE style bit
* set and the x parameter is set to CW_USEDEFAULT, the system ignores
* the y parameter. However, disassembling NT implementation (WIN32K.SYS)
* reveals that
*
* 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
* 2) it does not ignore the y parameter as the docs claim; instead, it
* uses it as second parameter to ShowWindow() unless y is either
* CW_USEDEFAULT or CW_USEDEFAULT16.
*
* The fact that we didn't do 2) caused bogus windows pop up when wine
* was running apps that were using this obscure feature. Example -
* calc.exe that comes with Win98 (only Win98, it's different from
* the one that comes with Win95 and NT)
*/
if(y != CW_USEDEFAULT && y != CW_USEDEFAULT16)
{
dwShowMode = y;
}
}
if(nWidth == CW_USEDEFAULT || nWidth == CW_USEDEFAULT16)
{
if(!CalculatedDefPosSize)
{
IntCalcDefPosSize(ParentWindow, Window, &rc, FALSE);
}
if(ProcessParams->WindowFlags & STARTF_USESIZE)
{
ProcessParams->WindowFlags &= ~STARTF_USESIZE;
Size.cx = ProcessParams->CountX;
Size.cy = ProcessParams->CountY;
}
else
{
Size.cx = rc.right - rc.left;
Size.cy = rc.bottom - rc.top;
}
/* move the window if necessary */
if(Pos.x > rc.left)
Pos.x = max(rc.left, 0);
if(Pos.y > rc.top)
Pos.y = max(rc.top, 0);
}
}
else
{
/* if CW_USEDEFAULT(16) is set for non-overlapped windows, both values are set to zero) */
if(x == CW_USEDEFAULT || x == CW_USEDEFAULT16)
{
Pos.x = 0;
Pos.y = 0;
}
if(nWidth == CW_USEDEFAULT || nWidth == CW_USEDEFAULT16)
{
Size.cx = 0;
Size.cy = 0;
}
}
/* Initialize the window dimensions. */
Window->WindowRect.left = Pos.x;
Window->WindowRect.top = Pos.y;
Window->WindowRect.right = Pos.x + Size.cx;
Window->WindowRect.bottom = Pos.y + Size.cy;
if (0 != (Window->Style & WS_CHILD) && ParentWindow)
{
IntGdiOffsetRect(&(Window->WindowRect), ParentWindow->ClientRect.left,
ParentWindow->ClientRect.top);
}
Window->ClientRect = Window->WindowRect;
/*
* Get the size and position of the window.
*/
if ((dwStyle & WS_THICKFRAME) || !(dwStyle & (WS_POPUP | WS_CHILD)))
{
POINT MaxSize, MaxPos, MinTrack, MaxTrack;
/* WinPosGetMinMaxInfo sends the WM_GETMINMAXINFO message */
co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack,
&MaxTrack);
if (MaxSize.x < Size.cx)
Size.cx = MaxSize.x;
if (MaxSize.y < Size.cy)
Size.cy = MaxSize.y;
if (Size.cx < MinTrack.x )
Size.cx = MinTrack.x;
if (Size.cy < MinTrack.y )
Size.cy = MinTrack.y;
if (Size.cx < 0)
Size.cx = 0;
if (Size.cy < 0)
Size.cy = 0;
}
Window->WindowRect.left = Pos.x;
Window->WindowRect.top = Pos.y;
Window->WindowRect.right = Pos.x + Size.cx;
Window->WindowRect.bottom = Pos.y + Size.cy;
if (0 != (Window->Style & WS_CHILD) && ParentWindow)
{
IntGdiOffsetRect(&(Window->WindowRect), ParentWindow->ClientRect.left,
ParentWindow->ClientRect.top);
}
Window->ClientRect = Window->WindowRect;
/* FIXME: Initialize the window menu. */
/* Send a NCCREATE message. */
Cs.cx = Size.cx;
Cs.cy = Size.cy;
Cs.x = Pos.x;
Cs.y = Pos.y;
DPRINT("[win32k.window] IntCreateWindowEx style %d, exstyle %d, parent %d\n", Cs.style, Cs.dwExStyle, Cs.hwndParent);
DPRINT("IntCreateWindowEx(): (%d,%d-%d,%d)\n", x, y, Size.cx, Size.cy);
DPRINT("IntCreateWindowEx(): About to send NCCREATE message.\n");
Result = co_IntSendMessage(Window->hSelf, WM_NCCREATE, 0, (LPARAM) &Cs);
if (!Result)
{
/* FIXME: Cleanup. */
DPRINT("IntCreateWindowEx(): NCCREATE message failed.\n");
RETURN((HWND)0);
}
/* Calculate the non-client size. */
MaxPos.x = Window->WindowRect.left;
MaxPos.y = Window->WindowRect.top;
DPRINT("IntCreateWindowEx(): About to get non-client size.\n");
/* WinPosGetNonClientSize SENDS THE WM_NCCALCSIZE message */
Result = co_WinPosGetNonClientSize(Window,
&Window->WindowRect,
&Window->ClientRect);
IntGdiOffsetRect(&Window->WindowRect,
MaxPos.x - Window->WindowRect.left,
MaxPos.y - Window->WindowRect.top);
if (NULL != ParentWindow)
{
/* link the window into the parent's child list */
if ((dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
{
PWINDOW_OBJECT PrevSibling;
PrevSibling = ParentWindow->LastChild;
/* link window as bottom sibling */
IntLinkWindow(Window, ParentWindow, PrevSibling /*prev sibling*/);
}
else
{
/* link window as top sibling (but after topmost siblings) */
PWINDOW_OBJECT InsertAfter, Sibling;
if (!(dwExStyle & WS_EX_TOPMOST))
{
InsertAfter = NULL;
Sibling = ParentWindow->FirstChild;
while (Sibling && (Sibling->ExStyle & WS_EX_TOPMOST))
{
InsertAfter = Sibling;
Sibling = Sibling->NextSibling;
}
}
else
{
InsertAfter = NULL;
}
IntLinkWindow(Window, ParentWindow, InsertAfter /* prev sibling */);
}
}
/* Send the WM_CREATE message. */
DPRINT("IntCreateWindowEx(): about to send CREATE message.\n");
Result = co_IntSendMessage(Window->hSelf, WM_CREATE, 0, (LPARAM) &Cs);
if (Result == (LRESULT)-1)
{
/* FIXME: Cleanup. */
DPRINT("IntCreateWindowEx(): send CREATE message failed.\n");
RETURN((HWND)0);
}
/* Send move and size messages. */
if (!(Window->Flags & WINDOWOBJECT_NEED_SIZE))
{
LONG lParam;
DPRINT("IntCreateWindow(): About to send WM_SIZE\n");
if ((Window->ClientRect.right - Window->ClientRect.left) < 0 ||
(Window->ClientRect.bottom - Window->ClientRect.top) < 0)
{
DPRINT("Sending bogus WM_SIZE\n");
}
lParam = MAKE_LONG(Window->ClientRect.right -
Window->ClientRect.left,
Window->ClientRect.bottom -
Window->ClientRect.top);
co_IntSendMessage(Window->hSelf, WM_SIZE, SIZE_RESTORED,
lParam);
DPRINT("IntCreateWindow(): About to send WM_MOVE\n");
if (0 != (Window->Style & WS_CHILD) && ParentWindow)
{
lParam = MAKE_LONG(Window->ClientRect.left - ParentWindow->ClientRect.left,
Window->ClientRect.top - ParentWindow->ClientRect.top);
}
else
{
lParam = MAKE_LONG(Window->ClientRect.left,
Window->ClientRect.top);
}
co_IntSendMessage(Window->hSelf, WM_MOVE, 0, lParam);
/* Call WNDOBJ change procs */
IntEngWindowChanged(Window, WOC_RGN_CLIENT);
}
/* Show or maybe minimize or maximize the window. */
if (Window->Style & (WS_MINIMIZE | WS_MAXIMIZE))
{
RECT NewPos;
UINT16 SwFlag;
SwFlag = (Window->Style & WS_MINIMIZE) ? SW_MINIMIZE :
SW_MAXIMIZE;
co_WinPosMinMaximize(Window, SwFlag, &NewPos);
SwFlag =
((Window->Style & WS_CHILD) || UserGetActiveWindow()) ?
SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED :
SWP_NOZORDER | SWP_FRAMECHANGED;
DPRINT("IntCreateWindow(): About to minimize/maximize\n");
DPRINT("%d,%d %dx%d\n", NewPos.left, NewPos.top, NewPos.right, NewPos.bottom);
co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
NewPos.right, NewPos.bottom, SwFlag);
}
/* Notify the parent window of a new child. */
if ((Window->Style & WS_CHILD) &&
(!(Window->ExStyle & WS_EX_NOPARENTNOTIFY)) && ParentWindow)
{
DPRINT("IntCreateWindow(): About to notify parent\n");
co_IntSendMessage(ParentWindow->hSelf,
WM_PARENTNOTIFY,
MAKEWPARAM(WM_CREATE, Window->IDMenu),
(LPARAM)Window->hSelf);
}
if ((!hWndParent) && (!HasOwner))
{
DPRINT("Sending CREATED notify\n");
co_IntShellHookNotify(HSHELL_WINDOWCREATED, (LPARAM)hWnd);
}
else
{
DPRINT("Not sending CREATED notify, %x %d\n", ParentWindow, HasOwner);
}
/* Initialize and show the window's scrollbars */
if (Window->Style & WS_VSCROLL)
{
co_UserShowScrollBar(Window, SB_VERT, TRUE);
}
if (Window->Style & WS_HSCROLL)
{
co_UserShowScrollBar(Window, SB_HORZ, TRUE);
}
if (dwStyle & WS_VISIBLE)
{
DPRINT("IntCreateWindow(): About to show window\n");
co_WinPosShowWindow(Window, dwShowMode);
}
DPRINT("IntCreateWindow(): = %X\n", hWnd);
DPRINT("WindowObject->SystemMenu = 0x%x\n", Window->SystemMenu);
RETURN(hWnd);
CLEANUP:
if (Window) UserDerefObjectCo(Window);
if (ParentWindow) UserDerefObjectCo(ParentWindow);
if (!_ret_ && ti != NULL)
{
if (Class != NULL)
{
IntDereferenceClass(Class,
ti->Desktop,
ti->kpi);
}
}
END_CLEANUP;
}
HWND STDCALL
NtUserCreateWindowEx(DWORD dwExStyle,
PUNICODE_STRING UnsafeClassName,
PUNICODE_STRING UnsafeWindowName,
DWORD dwStyle,
LONG x,
LONG y,
LONG nWidth,
LONG nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam,
DWORD dwShowMode,
BOOL bUnicodeWindow,
DWORD dwUnknown)
{
NTSTATUS Status;
UNICODE_STRING WindowName;
UNICODE_STRING ClassName;
HWND NewWindow;
DECLARE_RETURN(HWND);
DPRINT("Enter NtUserCreateWindowEx(): (%d,%d-%d,%d)\n", x, y, nWidth, nHeight);
UserEnterExclusive();
/* Get the class name (string or atom) */
Status = MmCopyFromCaller(&ClassName, UnsafeClassName, sizeof(UNICODE_STRING));
if (! NT_SUCCESS(Status))
{
SetLastNtError(Status);
RETURN( NULL);
}
if (ClassName.Length != 0)
{
Status = IntSafeCopyUnicodeStringTerminateNULL(&ClassName, UnsafeClassName);
if (! NT_SUCCESS(Status))
{
SetLastNtError(Status);
RETURN( NULL);
}
}
else if (! IS_ATOM(ClassName.Buffer))
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return NULL;
}
/* safely copy the window name */
if (NULL != UnsafeWindowName)
{
Status = IntSafeCopyUnicodeString(&WindowName, UnsafeWindowName);
if (! NT_SUCCESS(Status))
{
if (! IS_ATOM(ClassName.Buffer))
{
RtlFreeUnicodeString(&ClassName);
}
SetLastNtError(Status);
RETURN( NULL);
}
}
else
{
RtlInitUnicodeString(&WindowName, NULL);
}
NewWindow = co_IntCreateWindowEx(dwExStyle, &ClassName, &WindowName, dwStyle, x, y, nWidth, nHeight,
hWndParent, hMenu, hInstance, lpParam, dwShowMode, bUnicodeWindow);
RtlFreeUnicodeString(&WindowName);
if (! IS_ATOM(ClassName.Buffer))
{
RtlFreeUnicodeString(&ClassName);
}
RETURN( NewWindow);
CLEANUP:
DPRINT("Leave NtUserCreateWindowEx, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* @unimplemented
*/
HDWP STDCALL
NtUserDeferWindowPos(HDWP WinPosInfo,
HWND Wnd,
HWND WndInsertAfter,
int x,
int y,
int cx,
int cy,
UINT Flags)
{
UNIMPLEMENTED
return 0;
}
BOOLEAN FASTCALL co_UserDestroyWindow(PWINDOW_OBJECT Window)
{
BOOLEAN isChild;
ASSERT_REFS_CO(Window); //fixme: temp hack?
/* Check for owner thread */
if ((Window->OwnerThread != PsGetCurrentThread()))
{
SetLastWin32Error(ERROR_ACCESS_DENIED);
return FALSE;
}
/* Look whether the focus is within the tree of windows we will
* be destroying.
*/
if (!co_WinPosShowWindow(Window, SW_HIDE))
{
if (UserGetActiveWindow() == Window->hSelf)
{
co_WinPosActivateOtherWindow(Window);
}
}
if (Window->MessageQueue->ActiveWindow == Window->hSelf)
Window->MessageQueue->ActiveWindow = NULL;
if (Window->MessageQueue->FocusWindow == Window->hSelf)
Window->MessageQueue->FocusWindow = NULL;
if (Window->MessageQueue->CaptureWindow == Window->hSelf)
Window->MessageQueue->CaptureWindow = NULL;
IntDereferenceMessageQueue(Window->MessageQueue);
/* Call hooks */
#if 0 /* FIXME */
if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hwnd, 0, TRUE))
{
return FALSE;
}
#endif
IntEngWindowChanged(Window, WOC_DELETE);
isChild = (0 != (Window->Style & WS_CHILD));
#if 0 /* FIXME */
if (isChild)
{
if (! USER_IsExitingThread(GetCurrentThreadId()))
{
send_parent_notify(hwnd, WM_DESTROY);
}
}
else if (NULL != GetWindow(Wnd, GW_OWNER))
{
co_HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
/* FIXME: clean up palette - see "Internals" p.352 */
}
#endif
if (!IntIsWindow(Window->hSelf))
{
return TRUE;
}
/* Recursively destroy owned windows */
if (! isChild)
{
for (;;)
{
BOOL GotOne = FALSE;
HWND *Children;
HWND *ChildHandle;
PWINDOW_OBJECT Child, Desktop;
Desktop = IntIsDesktopWindow(Window) ? Window :
UserGetWindowObject(IntGetDesktopWindow());
Children = IntWinListChildren(Desktop);
if (Children)
{
for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
{
Child = UserGetWindowObject(*ChildHandle);
if (Child == NULL)
continue;
if (Child->hOwner != Window->hSelf)
{
continue;
}
if (IntWndBelongsToThread(Child, PsGetCurrentThreadWin32Thread()))
{
USER_REFERENCE_ENTRY ChildRef;
UserRefObjectCo(Child, &ChildRef);//temp hack?
co_UserDestroyWindow(Child);
UserDerefObjectCo(Child);//temp hack?
GotOne = TRUE;
continue;
}
if (Child->hOwner != NULL)
{
Child->hOwner = NULL;
}
}
ExFreePool(Children);
}
if (! GotOne)
{
break;
}
}
}
if (!IntIsWindow(Window->hSelf))
{
return TRUE;
}
/* Destroy the window storage */
co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
return TRUE;
}
/*
* @implemented
*/
BOOLEAN STDCALL
NtUserDestroyWindow(HWND Wnd)
{
PWINDOW_OBJECT Window;
DECLARE_RETURN(BOOLEAN);
BOOLEAN ret;
USER_REFERENCE_ENTRY Ref;
DPRINT("Enter NtUserDestroyWindow\n");
UserEnterExclusive();
if (!(Window = UserGetWindowObject(Wnd)))
{
RETURN(FALSE);
}
UserRefObjectCo(Window, &Ref);//faxme: dunno if win should be reffed during destroy..
ret = co_UserDestroyWindow(Window);
UserDerefObjectCo(Window);//faxme: dunno if win should be reffed during destroy..
RETURN(ret);
CLEANUP:
DPRINT("Leave NtUserDestroyWindow, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* @unimplemented
*/
DWORD
STDCALL
NtUserDrawMenuBarTemp(
HWND hWnd,
HDC hDC,
PRECT hRect,
HMENU hMenu,
HFONT hFont)
{
/* we'll use this function just for caching the menu bar */
UNIMPLEMENTED
return 0;
}
/*
* @unimplemented
*/
DWORD STDCALL
NtUserEndDeferWindowPosEx(DWORD Unknown0,
DWORD Unknown1)
{
UNIMPLEMENTED
return 0;
}
/*
* @unimplemented
*/
DWORD STDCALL
NtUserFillWindow(DWORD Unknown0,
DWORD Unknown1,
DWORD Unknown2,
DWORD Unknown3)
{
UNIMPLEMENTED
return 0;
}
static HWND FASTCALL
IntFindWindow(PWINDOW_OBJECT Parent,
PWINDOW_OBJECT ChildAfter,
RTL_ATOM ClassAtom,
PUNICODE_STRING WindowName)
{
BOOL CheckWindowName;
HWND *List, *phWnd;
HWND Ret = NULL;
ASSERT(Parent);
CheckWindowName = WindowName->Length != 0;
if((List = IntWinListChildren(Parent)))
{
phWnd = List;
if(ChildAfter)
{
/* skip handles before and including ChildAfter */
while(*phWnd && (*(phWnd++) != ChildAfter->hSelf))
;
}
/* search children */
while(*phWnd)
{
PWINDOW_OBJECT Child;
if(!(Child = UserGetWindowObject(*(phWnd++))))
{
continue;
}
/* Do not send WM_GETTEXT messages in the kernel mode version!
The user mode version however calls GetWindowText() which will
send WM_GETTEXT messages to windows belonging to its processes */
if((!CheckWindowName || !RtlCompareUnicodeString(WindowName, &(Child->WindowName), TRUE)) &&
(!ClassAtom || Child->Class->Atom == ClassAtom))
{
Ret = Child->hSelf;
break;
}
}
ExFreePool(List);
}
return Ret;
}
/*
* FUNCTION:
* Searches a window's children for a window with the specified
* class and name
* ARGUMENTS:
* hwndParent = The window whose childs are to be searched.
* NULL = desktop
* HWND_MESSAGE = message-only windows
*
* hwndChildAfter = Search starts after this child window.
* NULL = start from beginning
*
* ucClassName = Class name to search for
* Reguired parameter.
*
* ucWindowName = Window name
* ->Buffer == NULL = don't care
*
* RETURNS:
* The HWND of the window if it was found, otherwise NULL
*/
/*
* @implemented
*/
HWND STDCALL
NtUserFindWindowEx(HWND hwndParent,
HWND hwndChildAfter,
PUNICODE_STRING ucClassName,
PUNICODE_STRING ucWindowName,
DWORD dwUnknown)
{
PWINDOW_OBJECT Parent, ChildAfter;
UNICODE_STRING ClassName = {0}, WindowName = {0};
HWND Desktop, Ret = NULL;
RTL_ATOM ClassAtom = (RTL_ATOM)0;
DECLARE_RETURN(HWND);
DPRINT("Enter NtUserFindWindowEx\n");
UserEnterShared();
if (ucClassName != NULL || ucWindowName != NULL)
{
_SEH_TRY
{
if (ucClassName != NULL)
{
ClassName = ProbeForReadUnicodeString(ucClassName);
if (ClassName.Length != 0)
{
ProbeForRead(ClassName.Buffer,
ClassName.Length,
sizeof(WCHAR));
}
else if (!IS_ATOM(ClassName.Buffer))
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
_SEH_LEAVE;
}
if (!IntGetAtomFromStringOrAtom(&ClassName,
&ClassAtom))
{
_SEH_LEAVE;
}
}
if (ucWindowName != NULL)
{
WindowName = ProbeForReadUnicodeString(ucWindowName);
if (WindowName.Length != 0)
{
ProbeForRead(WindowName.Buffer,
WindowName.Length,
sizeof(WCHAR));
}
}
}
_SEH_HANDLE
{
SetLastNtError(_SEH_GetExceptionCode());
_SEH_YIELD(RETURN(NULL));
}
_SEH_END;
if (ucClassName != NULL)
{
if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
!IS_ATOM(ClassName.Buffer))
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
RETURN(NULL);
}
else if (ClassAtom == (RTL_ATOM)0)
{
/* LastError code was set by IntGetAtomFromStringOrAtom */
RETURN(NULL);
}
}
}
Desktop = IntGetCurrentThreadDesktopWindow();
if(hwndParent == NULL)
hwndParent = Desktop;
/* FIXME
else if(hwndParent == HWND_MESSAGE)
{
hwndParent = IntGetMessageWindow();
}
*/
if(!(Parent = UserGetWindowObject(hwndParent)))
{
RETURN( NULL);
}
ChildAfter = NULL;
if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
{
RETURN( NULL);
}
_SEH_TRY
{
if(Parent->hSelf == Desktop)
{
HWND *List, *phWnd;
PWINDOW_OBJECT TopLevelWindow;
BOOLEAN CheckWindowName;
BOOLEAN WindowMatches;
BOOLEAN ClassMatches;
/* windows searches through all top-level windows if the parent is the desktop
window */
if((List = IntWinListChildren(Parent)))
{
phWnd = List;
if(ChildAfter)
{
/* skip handles before and including ChildAfter */
while(*phWnd && (*(phWnd++) != ChildAfter->hSelf))
;
}
CheckWindowName = WindowName.Length != 0;
/* search children */
while(*phWnd)
{
if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
{
continue;
}
/* Do not send WM_GETTEXT messages in the kernel mode version!
The user mode version however calls GetWindowText() which will
send WM_GETTEXT messages to windows belonging to its processes */
WindowMatches = !CheckWindowName || !RtlCompareUnicodeString(
&WindowName, &TopLevelWindow->WindowName, TRUE);
ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
ClassAtom == TopLevelWindow->Class->Atom;
if (WindowMatches && ClassMatches)
{
Ret = TopLevelWindow->hSelf;
break;
}
if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
{
/* window returns the handle of the top-level window, in case it found
the child window */
Ret = TopLevelWindow->hSelf;
break;
}
}
ExFreePool(List);
}
}
else
Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
#if 0
if(Ret == NULL && hwndParent == NULL && hwndChildAfter == NULL)
{
/* FIXME - if both hwndParent and hwndChildAfter are NULL, we also should
search the message-only windows. Should this also be done if
Parent is the desktop window??? */
PWINDOW_OBJECT MsgWindows;
if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
{
Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
}
}
#endif
}
_SEH_HANDLE
{
SetLastNtError(_SEH_GetExceptionCode());
Ret = NULL;
}
_SEH_END;
RETURN( Ret);
CLEANUP:
DPRINT("Leave NtUserFindWindowEx, ret %i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* @unimplemented
*/
DWORD STDCALL
NtUserFlashWindowEx(DWORD Unknown0)
{
UNIMPLEMENTED
return 0;
}
/*
* @implemented
*/
PWINDOW_OBJECT FASTCALL UserGetAncestor(PWINDOW_OBJECT Wnd, UINT Type)
{
PWINDOW_OBJECT WndAncestor, Parent;
if (Wnd->hSelf == IntGetDesktopWindow())
{
return NULL;
}
switch (Type)
{
case GA_PARENT:
{
WndAncestor = Wnd->Parent;
break;
}
case GA_ROOT:
{
WndAncestor = Wnd;
Parent = NULL;
for(;;)
{
if(!(Parent = WndAncestor->Parent))
{
break;
}
if(IntIsDesktopWindow(Parent))
{
break;
}
WndAncestor = Parent;
}
break;
}
case GA_ROOTOWNER:
{
WndAncestor = Wnd;
for (;;)
{
PWINDOW_OBJECT Parent, Old;
Old = WndAncestor;
Parent = IntGetParent(WndAncestor);
if (!Parent)
{
break;
}
//temp hack
// UserDerefObject(Parent);
WndAncestor = Parent;
}
break;
}
default:
{
return NULL;
}
}
return WndAncestor;
}
/*
* @implemented
*/
HWND STDCALL
NtUserGetAncestor(HWND hWnd, UINT Type)
{
PWINDOW_OBJECT Window, Ancestor;
DECLARE_RETURN(HWND);
DPRINT("Enter NtUserGetAncestor\n");
UserEnterExclusive();
if (!(Window = UserGetWindowObject(hWnd)))
{
RETURN(NULL);
}
Ancestor = UserGetAncestor(Window, Type);
/* faxme: can UserGetAncestor ever return NULL for a valid window? */
RETURN(Ancestor ? Ancestor->hSelf : NULL);
CLEANUP:
DPRINT("Leave NtUserGetAncestor, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*!
* Returns client window rectangle relative to the upper-left corner of client area.
*
* \param hWnd window handle.
* \param Rect pointer to the buffer where the coordinates are returned.
*
*/
/*
* @implemented
*/
BOOL STDCALL
NtUserGetClientRect(HWND hWnd, LPRECT Rect)
{
PWINDOW_OBJECT Window;
RECT SafeRect;
DECLARE_RETURN(BOOL);
DPRINT("Enter NtUserGetClientRect\n");
UserEnterShared();
if(!(Window = UserGetWindowObject(hWnd)))
{
RETURN( FALSE);
}
IntGetClientRect(Window, &SafeRect);
if(!NT_SUCCESS(MmCopyToCaller(Rect, &SafeRect, sizeof(RECT))))
{
RETURN( FALSE);
}
RETURN( TRUE);
CLEANUP:
DPRINT("Leave NtUserGetClientRect, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
BOOL
STDCALL
NtUserGetComboBoxInfo(
HWND hWnd,
PCOMBOBOXINFO pcbi)
{
PWINDOW_OBJECT Wnd;
DECLARE_RETURN(BOOL);
DPRINT("Enter NtUserGetComboBoxInfo\n");
UserEnterShared();
if (!(Wnd = UserGetWindowObject(hWnd)))
{
RETURN( FALSE );
}
_SEH_TRY
{
if(pcbi)
{
ProbeForWrite(pcbi,
sizeof(COMBOBOXINFO),
1);
}
}
_SEH_HANDLE
{
SetLastNtError(_SEH_GetExceptionCode());
_SEH_YIELD(RETURN(FALSE));
}
_SEH_END;
// Pass the user pointer, it was already probed.
RETURN( (BOOL) co_IntSendMessage( Wnd->hSelf, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
CLEANUP:
DPRINT("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* @implemented
*/
HWND STDCALL
NtUserGetDesktopWindow()
{
DECLARE_RETURN(HWND);
DPRINT("Enter NtUserGetDesktopWindow\n");
UserEnterShared();
RETURN( IntGetDesktopWindow());
CLEANUP:
DPRINT("Leave NtUserGetDesktopWindow, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* @unimplemented
*/
DWORD STDCALL
NtUserGetInternalWindowPos(DWORD Unknown0,
DWORD Unknown1,
DWORD Unknown2)
{
UNIMPLEMENTED
return 0;
}
/*
* @unimplemented
*/
HWND STDCALL
NtUserGetLastActivePopup(HWND hWnd)
{
/*
* This code can't work, because hWndLastPopup member of WINDOW_OBJECT is
* not changed anywhere.
* -- Filip, 01/nov/2003
*/
#if 0
PWINDOW_OBJECT Wnd;
HWND hWndLastPopup;
if (!(Wnd = UserGetWindowObject(hWnd)))
{
return NULL;
}
hWndLastPopup = Wnd->hWndLastPopup;
return hWndLastPopup;
#else
return NULL;
#endif
}
DWORD
STDCALL
NtUserGetListBoxInfo(
HWND hWnd)
{
PWINDOW_OBJECT Wnd;
DECLARE_RETURN(DWORD);
DPRINT("Enter NtUserGetListBoxInfo\n");
UserEnterShared();
if (!(Wnd = UserGetWindowObject(hWnd)))
{
RETURN( 0 );
}
RETURN( (DWORD) co_IntSendMessage( Wnd->hSelf, LB_GETLISTBOXINFO, 0, 0 ));
CLEANUP:
DPRINT("Leave NtUserGetListBoxInfo, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* NtUserGetParent
*
* The NtUserGetParent function retrieves a handle to the specified window's
* parent or owner.
*
* Remarks
* Note that, despite its name, this function can return an owner window
* instead of a parent window.
*
* Status
* @implemented
*/
HWND STDCALL
NtUserGetParent(HWND hWnd)
{
PWINDOW_OBJECT Wnd, WndParent;
HWND hWndParent = NULL;
DECLARE_RETURN(HWND);
DPRINT("Enter NtUserGetParent\n");
UserEnterExclusive();
if (!(Wnd = UserGetWindowObject(hWnd)))
{
RETURN( NULL);
}
WndParent = IntGetParent(Wnd);
if (WndParent)
{
hWndParent = WndParent->hSelf;
}
RETURN( hWndParent);
CLEANUP:
DPRINT("Leave NtUserGetParent, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
HWND FASTCALL
co_UserSetParent(HWND hWndChild, HWND hWndNewParent)
{
PWINDOW_OBJECT Wnd = NULL, WndParent = NULL, WndOldParent;
HWND hWndOldParent = NULL;
USER_REFERENCE_ENTRY Ref, ParentRef;
if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return( NULL);
}
if (hWndChild == IntGetDesktopWindow())
{
SetLastWin32Error(ERROR_ACCESS_DENIED);
return( NULL);
}
if (hWndNewParent)
{
if (!(WndParent = UserGetWindowObject(hWndNewParent)))
{
return( NULL);
}
}
else
{
if (!(WndParent = UserGetWindowObject(IntGetDesktopWindow())))
{
return( NULL);
}
}
if (!(Wnd = UserGetWindowObject(hWndChild)))
{
return( NULL);
}
UserRefObjectCo(Wnd, &Ref);
UserRefObjectCo(WndParent, &ParentRef);
WndOldParent = co_IntSetParent(Wnd, WndParent);
UserDerefObjectCo(WndParent);
UserDerefObjectCo(Wnd);
if (WndOldParent)
{
hWndOldParent = WndOldParent->hSelf;
UserDerefObject(WndOldParent);
}
return( hWndOldParent);
}
/*
* NtUserSetParent
*
* The NtUserSetParent function changes the parent window of the specified
* child window.
*
* Remarks
* The new parent window and the child window must belong to the same
* application. If the window identified by the hWndChild parameter is
* visible, the system performs the appropriate redrawing and repainting.
* For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
* or WS_POPUP window styles of the window whose parent is being changed.
*
* Status
* @implemented
*/
HWND STDCALL
NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
{
DECLARE_RETURN(HWND);
DPRINT("Enter NtUserSetParent\n");
UserEnterExclusive();
RETURN( co_UserSetParent(hWndChild, hWndNewParent));
CLEANUP:
DPRINT("Leave NtUserSetParent, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
HWND FASTCALL UserGetShellWindow()
{
PWINSTATION_OBJECT WinStaObject;
HWND Ret;
NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
KernelMode,
0,
&WinStaObject);
if (!NT_SUCCESS(Status))
{
SetLastNtError(Status);
return( (HWND)0);
}
Ret = (HWND)WinStaObject->ShellWindow;
ObDereferenceObject(WinStaObject);
return( Ret);
}
/*
* NtUserGetShellWindow
*
* Returns a handle to shell window that was set by NtUserSetShellWindowEx.
*
* Status
* @implemented
*/
HWND STDCALL
NtUserGetShellWindow()
{
DECLARE_RETURN(HWND);
DPRINT("Enter NtUserGetShellWindow\n");
UserEnterShared();
RETURN( UserGetShellWindow() );
CLEANUP:
DPRINT("Leave NtUserGetShellWindow, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* NtUserSetShellWindowEx
*
* This is undocumented function to set global shell window. The global
* shell window has special handling of window position.
*
* Status
* @implemented
*/
BOOL STDCALL
NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
{
PWINSTATION_OBJECT WinStaObject;
PWINDOW_OBJECT WndShell;
DECLARE_RETURN(BOOL);
USER_REFERENCE_ENTRY Ref;
NTSTATUS Status;
DPRINT("Enter NtUserSetShellWindowEx\n");
UserEnterExclusive();
if (!(WndShell = UserGetWindowObject(hwndShell)))
{
RETURN(FALSE);
}
Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
KernelMode,
0,
&WinStaObject);
if (!NT_SUCCESS(Status))
{
SetLastNtError(Status);
RETURN( FALSE);
}
/*
* Test if we are permitted to change the shell window.
*/
if (WinStaObject->ShellWindow)
{
ObDereferenceObject(WinStaObject);
RETURN( FALSE);
}
/*
* Move shell window into background.
*/
if (hwndListView && hwndListView != hwndShell)
{
/*
* Disabled for now to get Explorer working.
* -- Filip, 01/nov/2003
*/
#if 0
co_WinPosSetWindowPos(hwndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
#endif
if (UserGetWindowLong(hwndListView, GWL_EXSTYLE, FALSE) & WS_EX_TOPMOST)
{
ObDereferenceObject(WinStaObject);
RETURN( FALSE);
}
}
if (UserGetWindowLong(hwndShell, GWL_EXSTYLE, FALSE) & WS_EX_TOPMOST)
{
ObDereferenceObject(WinStaObject);
RETURN( FALSE);
}
UserRefObjectCo(WndShell, &Ref);
co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
WinStaObject->ShellWindow = hwndShell;
WinStaObject->ShellListView = hwndListView;
UserDerefObjectCo(WndShell);
ObDereferenceObject(WinStaObject);
RETURN( TRUE);
CLEANUP:
DPRINT("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* NtUserGetSystemMenu
*
* The NtUserGetSystemMenu function allows the application to access the
* window menu (also known as the system menu or the control menu) for
* copying and modifying.
*
* Parameters
* hWnd
* Handle to the window that will own a copy of the window menu.
* bRevert
* Specifies the action to be taken. If this parameter is FALSE,
* NtUserGetSystemMenu returns a handle to the copy of the window menu
* currently in use. The copy is initially identical to the window menu
* but it can be modified.
* If this parameter is TRUE, GetSystemMenu resets the window menu back
* to the default state. The previous window menu, if any, is destroyed.
*
* Return Value
* If the bRevert parameter is FALSE, the return value is a handle to a
* copy of the window menu. If the bRevert parameter is TRUE, the return
* value is NULL.
*
* Status
* @implemented
*/
HMENU STDCALL
NtUserGetSystemMenu(HWND hWnd, BOOL bRevert)
{
PWINDOW_OBJECT Window;
PMENU_OBJECT Menu;
DECLARE_RETURN(HMENU);
DPRINT("Enter NtUserGetSystemMenu\n");
UserEnterShared();
if (!(Window = UserGetWindowObject(hWnd)))
{
RETURN(NULL);
}
if (!(Menu = IntGetSystemMenu(Window, bRevert, FALSE)))
{
RETURN(NULL);
}
RETURN(Menu->MenuInfo.Self);
CLEANUP:
DPRINT("Leave NtUserGetSystemMenu, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* NtUserSetSystemMenu
*
* Status
* @implemented
*/
BOOL STDCALL
NtUserSetSystemMenu(HWND hWnd, HMENU hMenu)
{
BOOL Result = FALSE;
PWINDOW_OBJECT Window;
PMENU_OBJECT Menu;
DECLARE_RETURN(BOOL);
DPRINT("Enter NtUserSetSystemMenu\n");
UserEnterExclusive();
if (!(Window = UserGetWindowObject(hWnd)))
{
RETURN( FALSE);
}
if (hMenu)
{
/*
* Assign new menu handle.
*/
if (!(Menu = UserGetMenuObject(hMenu)))
{
RETURN( FALSE);
}
Result = IntSetSystemMenu(Window, Menu);
}
RETURN( Result);
CLEANUP:
DPRINT("Leave NtUserSetSystemMenu, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
HWND FASTCALL
UserGetWindow(HWND hWnd, UINT Relationship)
{
PWINDOW_OBJECT Parent, Window;
HWND hWndResult = NULL;
if (!(Window = UserGetWindowObject(hWnd)))
return NULL;
switch (Relationship)
{
case GW_HWNDFIRST:
if((Parent = Window->Parent))
{
if (Parent->FirstChild)
hWndResult = Parent->FirstChild->hSelf;
}
break;
case GW_HWNDLAST:
if((Parent = Window->Parent))
{
if (Parent->LastChild)
hWndResult = Parent->LastChild->hSelf;
}
break;
case GW_HWNDNEXT:
if (Window->NextSibling)
hWndResult = Window->NextSibling->hSelf;
break;
case GW_HWNDPREV:
if (Window->PrevSibling)
hWndResult = Window->PrevSibling->hSelf;
break;
case GW_OWNER:
if((Parent = UserGetWindowObject(Window->hOwner)))
{
hWndResult = Parent->hSelf;
}
break;
case GW_CHILD:
if (Window->FirstChild)
hWndResult = Window->FirstChild->hSelf;
break;
}
return hWndResult;
}
/*
* NtUserGetWindow
*
* The NtUserGetWindow function retrieves a handle to a window that has the
* specified relationship (Z order or owner) to the specified window.
*
* Status
* @implemented
*/
HWND STDCALL
NtUserGetWindow(HWND hWnd, UINT Relationship)
{
DECLARE_RETURN(HWND);
DPRINT("Enter NtUserGetWindow\n");
UserEnterShared();
RETURN(UserGetWindow(hWnd, Relationship));
CLEANUP:
DPRINT("Leave NtUserGetWindow, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* NtUserGetWindowLong
*
* The NtUserGetWindowLong function retrieves information about the specified
* window. The function also retrieves the 32-bit (long) value at the
* specified offset into the extra window memory.
*
* Status
* @implemented
*/
LONG FASTCALL
UserGetWindowLong(HWND hWnd, DWORD Index, BOOL Ansi)
{
PWINDOW_OBJECT Window, Parent;
LONG Result = 0;
DPRINT("NtUserGetWindowLong(%x,%d,%d)\n", hWnd, (INT)Index, Ansi);
if (!(Window = UserGetWindowObject(hWnd)))
{
return 0;
}
/*
* WndProc is only available to the owner process
*/
if (GWL_WNDPROC == Index
&& Window->OwnerThread->ThreadsProcess != PsGetCurrentProcess())
{
SetLastWin32Error(ERROR_ACCESS_DENIED);
return 0;
}
if ((INT)Index >= 0)
{
if ((Index + sizeof(LONG)) > Window->ExtraDataSize)
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return 0;
}
Result = *((LONG *)(Window->ExtraData + Index));
}
else
{
switch (Index)
{
case GWL_EXSTYLE:
Result = Window->ExStyle;
break;
case GWL_STYLE:
Result = Window->Style;
break;
case GWL_WNDPROC:
Result = (LONG)IntGetWindowProc(Window,
Ansi);
break;
case GWL_HINSTANCE:
Result = (LONG) Window->Instance;
break;
case GWL_HWNDPARENT:
Parent = Window->Parent;
if(Parent)
{
if (Parent && Parent->hSelf == IntGetDesktopWindow())
Result = (LONG) UserGetWindow(Window->hSelf, GW_OWNER);
else
Result = (LONG) Parent->hSelf;
}
break;
case GWL_ID:
Result = (LONG) Window->IDMenu;
break;
case GWL_USERDATA:
Result = Window->UserData;
break;
default:
DPRINT1("NtUserGetWindowLong(): Unsupported index %d\n", Index);
SetLastWin32Error(ERROR_INVALID_PARAMETER);
Result = 0;
break;
}
}
return Result;
}
/*
* NtUserGetWindowLong
*
* The NtUserGetWindowLong function retrieves information about the specified
* window. The function also retrieves the 32-bit (long) value at the
* specified offset into the extra window memory.
*
* Status
* @implemented
*/
LONG STDCALL
NtUserGetWindowLong(HWND hWnd, DWORD Index, BOOL Ansi)
{
DECLARE_RETURN(LONG);
DPRINT("Enter NtUserGetWindowLong(%x,%d,%d)\n", hWnd, (INT)Index, Ansi);
UserEnterExclusive();
RETURN(UserGetWindowLong(hWnd, Index, Ansi));
CLEANUP:
DPRINT("Leave NtUserGetWindowLong, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
static WNDPROC
IntSetWindowProc(PWINDOW_OBJECT Window,
WNDPROC NewWndProc,
BOOL Ansi)
{
WNDPROC Ret;
PCALLPROC CallProc;
/* resolve any callproc handle if possible */
if (IsCallProcHandle(NewWndProc))
{
WNDPROC_INFO wpInfo;
if (UserGetCallProcInfo((HANDLE)NewWndProc,
&wpInfo))
{
NewWndProc = wpInfo.WindowProc;
/* FIXME - what if wpInfo.IsUnicode doesn't match Ansi? */
}
}
/* attempt to get the previous window proc */
if (Window->IsSystem)
{
Ret = (Ansi ? Window->WndProcExtra : Window->WndProc);
}
else
{
if (!Ansi == Window->Unicode)
{
Ret = Window->WndProc;
}
else
{
CallProc = UserFindCallProc(Window->Class,
Window->WndProc,
Window->Unicode);
if (CallProc == NULL)
{
CallProc = CreateCallProc(NULL,
Window->WndProc,
Window->Unicode,
Window->ti->kpi);
if (CallProc == NULL)
{
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
UserAddCallProcToClass(Window->Class,
CallProc);
}
Window->CallProc = CallProc;
Ret = GetCallProcHandle(Window->CallProc);
}
}
if (Window->Class->System)
{
/* check if the new procedure matches with the one in the
window class. If so, we need to restore both procedures! */
Window->IsSystem = (NewWndProc == Window->Class->WndProc ||
NewWndProc == Window->Class->WndProcExtra);
if (Window->IsSystem)
{
Window->WndProc = Window->Class->WndProc;
Window->WndProcExtra = Window->Class->WndProcExtra;
Window->Unicode = !Ansi;
return Ret;
}
}
ASSERT(!Window->IsSystem);
/* update the window procedure */
Window->WndProc = NewWndProc;
Window->Unicode = !Ansi;
return Ret;
}
LONG FASTCALL
co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
{
PWINDOW_OBJECT Window, Parent;
PWINSTATION_OBJECT WindowStation;
LONG OldValue;
STYLESTRUCT Style;
if (hWnd == IntGetDesktopWindow())
{
SetLastWin32Error(STATUS_ACCESS_DENIED);
return( 0);
}
if (!(Window = UserGetWindowObject(hWnd)))
{
return( 0);
}
if ((INT)Index >= 0)
{
if ((Index + sizeof(LONG)) > Window->ExtraDataSize)
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return( 0);
}
OldValue = *((LONG *)(Window->ExtraData + Index));
*((LONG *)(Window->ExtraData + Index)) = NewValue;
}
else
{
switch (Index)
{
case GWL_EXSTYLE:
OldValue = (LONG) Window->ExStyle;
Style.styleOld = OldValue;
Style.styleNew = NewValue;
/*
* Remove extended window style bit WS_EX_TOPMOST for shell windows.
*/
WindowStation = ((PW32THREAD)Window->OwnerThread->Tcb.Win32Thread)->Desktop->WindowStation;
if(WindowStation)
{
if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
Style.styleNew &= ~WS_EX_TOPMOST;
}
co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
Window->ExStyle = (DWORD)Style.styleNew;
co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
break;
case GWL_STYLE:
OldValue = (LONG) Window->Style;
Style.styleOld = OldValue;
Style.styleNew = NewValue;
co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
Window->Style = (DWORD)Style.styleNew;
co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
break;
case GWL_WNDPROC:
{
/* FIXME: should check if window belongs to current process */
OldValue = (LONG)IntSetWindowProc(Window,
(WNDPROC)NewValue,
Ansi);
break;
}
case GWL_HINSTANCE:
OldValue = (LONG) Window->Instance;
Window->Instance = (HINSTANCE) NewValue;
break;
case GWL_HWNDPARENT:
Parent = Window->Parent;
if (Parent && (Parent->hSelf == IntGetDesktopWindow()))
OldValue = (LONG) IntSetOwner(Window->hSelf, (HWND) NewValue);
else
OldValue = (LONG) co_UserSetParent(Window->hSelf, (HWND) NewValue);
break;
case GWL_ID:
OldValue = (LONG) Window->IDMenu;
Window->IDMenu = (UINT) NewValue;
break;
case GWL_USERDATA:
OldValue = Window->UserData;
Window->UserData = NewValue;
break;
default:
DPRINT1("NtUserSetWindowLong(): Unsupported index %d\n", Index);
SetLastWin32Error(ERROR_INVALID_PARAMETER);
OldValue = 0;
break;
}
}
return( OldValue);
}
/*
* NtUserSetWindowLong
*
* The NtUserSetWindowLong function changes an attribute of the specified
* window. The function also sets the 32-bit (long) value at the specified
* offset into the extra window memory.
*
* Status
* @implemented
*/
LONG STDCALL
NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
{
DECLARE_RETURN(LONG);
DPRINT("Enter NtUserSetWindowLong\n");
UserEnterExclusive();
RETURN( co_UserSetWindowLong(hWnd, Index, NewValue, Ansi));
CLEANUP:
DPRINT("Leave NtUserSetWindowLong, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* NtUserSetWindowWord
*
* Legacy function similar to NtUserSetWindowLong.
*
* Status
* @implemented
*/
WORD STDCALL
NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue)
{
PWINDOW_OBJECT Window;
WORD OldValue;
DECLARE_RETURN(WORD);
DPRINT("Enter NtUserSetWindowWord\n");
UserEnterExclusive();
if (!(Window = UserGetWindowObject(hWnd)))
{
RETURN( 0);
}
switch (Index)
{
case GWL_ID:
case GWL_HINSTANCE:
case GWL_HWNDPARENT:
RETURN( co_UserSetWindowLong(Window->hSelf, Index, (UINT)NewValue, TRUE));
default:
if (Index < 0)
{
SetLastWin32Error(ERROR_INVALID_INDEX);
RETURN( 0);
}
}
if (Index > Window->ExtraDataSize - sizeof(WORD))
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
RETURN( 0);
}
OldValue = *((WORD *)(Window->ExtraData + Index));
*((WORD *)(Window->ExtraData + Index)) = NewValue;
RETURN( OldValue);
CLEANUP:
DPRINT("Leave NtUserSetWindowWord, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* @implemented
*/
BOOL STDCALL
NtUserGetWindowPlacement(HWND hWnd,
WINDOWPLACEMENT *lpwndpl)
{
PWINDOW_OBJECT Window;
PINTERNALPOS InternalPos;
POINT Size;
WINDOWPLACEMENT Safepl;
NTSTATUS Status;
DECLARE_RETURN(BOOL);
DPRINT("Enter NtUserGetWindowPlacement\n");
UserEnterShared();
if (!(Window = UserGetWindowObject(hWnd)))
{
RETURN( FALSE);
}
Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
if(!NT_SUCCESS(Status))
{
SetLastNtError(Status);
RETURN( FALSE);
}
if(Safepl.length != sizeof(WINDOWPLACEMENT))
{
RETURN( FALSE);
}
Safepl.flags = 0;
if (0 == (Window->Style & WS_VISIBLE))
{
Safepl.showCmd = SW_HIDE;
}
else if (0 != (Window->Flags & WINDOWOBJECT_RESTOREMAX) ||
0 != (Window->Style & WS_MAXIMIZE))
{
Safepl.showCmd = SW_MAXIMIZE;
}
else if (0 != (Window->Style & WS_MINIMIZE))
{
Safepl.showCmd = SW_MINIMIZE;
}
else if (0 != (Window->Style & WS_VISIBLE))
{
Safepl.showCmd = SW_SHOWNORMAL;
}
Size.x = Window->WindowRect.left;
Size.y = Window->WindowRect.top;
InternalPos = WinPosInitInternalPos(Window, &Size,
&Window->WindowRect);
if (InternalPos)
{
Safepl.rcNormalPosition = InternalPos->NormalRect;
Safepl.ptMinPosition = InternalPos->IconPos;
Safepl.ptMaxPosition = InternalPos->MaxPos;
}
else
{
RETURN( FALSE);
}
Status = MmCopyToCaller(lpwndpl, &Safepl, sizeof(WINDOWPLACEMENT));
if(!NT_SUCCESS(Status))
{
SetLastNtError(Status);
RETURN( FALSE);
}
RETURN( TRUE);
CLEANUP:
DPRINT("Leave NtUserGetWindowPlacement, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*!
* Return the dimension of the window in the screen coordinates.
* \param hWnd window handle.
* \param Rect pointer to the buffer where the coordinates are returned.
*/
/*
* @implemented
*/
BOOL STDCALL
NtUserGetWindowRect(HWND hWnd, LPRECT Rect)
{
PWINDOW_OBJECT Wnd;
NTSTATUS Status;
DECLARE_RETURN(BOOL);
DPRINT("Enter NtUserGetWindowRect\n");
UserEnterShared();
if (!(Wnd = UserGetWindowObject(hWnd)))
{
RETURN(FALSE);
}
Status = MmCopyToCaller(Rect, &Wnd->WindowRect, sizeof(RECT));
if (!NT_SUCCESS(Status))
{
SetLastNtError(Status);
RETURN( FALSE);
}
RETURN( TRUE);
CLEANUP:
DPRINT("Leave NtUserGetWindowRect, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* @implemented
*/
DWORD STDCALL
NtUserGetWindowThreadProcessId(HWND hWnd, LPDWORD UnsafePid)
{
PWINDOW_OBJECT Wnd;
DWORD tid, pid;
DECLARE_RETURN(DWORD);
DPRINT("Enter NtUserGetWindowThreadProcessId\n");
UserEnterShared();
if (!(Wnd = UserGetWindowObject(hWnd)))
{
RETURN( 0);
}
tid = (DWORD)IntGetWndThreadId(Wnd);
pid = (DWORD)IntGetWndProcessId(Wnd);
if (UnsafePid)
MmCopyToCaller(UnsafePid, &pid, sizeof(DWORD));
RETURN( tid);
CLEANUP:
DPRINT("Leave NtUserGetWindowThreadProcessId, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* @unimplemented
*/
DWORD STDCALL
NtUserLockWindowUpdate(DWORD Unknown0)
{
UNIMPLEMENTED
return 0;
}
/*
* @implemented
*/
BOOL STDCALL
NtUserMoveWindow(
HWND hWnd,
int X,
int Y,
int nWidth,
int nHeight,
BOOL bRepaint)
{
return NtUserSetWindowPos(hWnd, 0, X, Y, nWidth, nHeight,
(bRepaint ? SWP_NOZORDER | SWP_NOACTIVATE :
SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW));
}
/*
QueryWindow based on KJK::Hyperion and James Tabor.
0 = QWUniqueProcessId
1 = QWUniqueThreadId
4 = QWIsHung Implements IsHungAppWindow found
by KJK::Hyperion.
9 = QWKillWindow When I called this with hWnd ==
DesktopWindow, it shutdown the system
and rebooted.
*/
/*
* @implemented
*/
DWORD STDCALL
NtUserQueryWindow(HWND hWnd, DWORD Index)
{
PWINDOW_OBJECT Window;
DWORD Result;
DECLARE_RETURN(UINT);
DPRINT("Enter NtUserQueryWindow\n");
UserEnterShared();
if (!(Window = UserGetWindowObject(hWnd)))
{
RETURN( 0);
}
switch(Index)
{
case QUERY_WINDOW_UNIQUE_PROCESS_ID:
Result = (DWORD)IntGetWndProcessId(Window);
break;
case QUERY_WINDOW_UNIQUE_THREAD_ID:
Result = (DWORD)IntGetWndThreadId(Window);
break;
case QUERY_WINDOW_ISHUNG:
Result = (DWORD)MsqIsHung(Window->MessageQueue);
break;
default:
Result = (DWORD)NULL;
break;
}
RETURN( Result);
CLEANUP:
DPRINT("Leave NtUserQueryWindow, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* @unimplemented
*/
DWORD STDCALL
NtUserRealChildWindowFromPoint(DWORD Unknown0,
DWORD Unknown1,
DWORD Unknown2)
{
UNIMPLEMENTED
return 0;
}
/*
* @implemented
*/
UINT STDCALL
NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe)
{
UNICODE_STRING SafeMessageName;
NTSTATUS Status;
UINT Ret;
DECLARE_RETURN(UINT);
DPRINT("Enter NtUserRegisterWindowMessage\n");
UserEnterExclusive();
if(MessageNameUnsafe == NULL)
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
RETURN( 0);
}
Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe);
if(!NT_SUCCESS(Status))
{
SetLastNtError(Status);
RETURN( 0);
}
Ret = (UINT)IntAddAtom(SafeMessageName.Buffer);
RtlFreeUnicodeString(&SafeMessageName);
RETURN( Ret);
CLEANUP:
DPRINT("Leave NtUserRegisterWindowMessage, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* @unimplemented
*/
DWORD STDCALL
NtUserSetImeOwnerWindow(DWORD Unknown0,
DWORD Unknown1)
{
UNIMPLEMENTED
return 0;
}
/*
* @unimplemented
*/
DWORD STDCALL
NtUserSetInternalWindowPos(DWORD Unknown0,
DWORD Unknown1,
DWORD Unknown2,
DWORD Unknown3)
{
UNIMPLEMENTED
return 0;
}
/*
* @unimplemented
*/
DWORD STDCALL
NtUserSetLayeredWindowAttributes(DWORD Unknown0,
DWORD Unknown1,
DWORD Unknown2,
DWORD Unknown3)
{
UNIMPLEMENTED
return 0;
}
/*
* @unimplemented
*/
DWORD STDCALL
NtUserSetLogonNotifyWindow(DWORD Unknown0)
{
UNIMPLEMENTED
return 0;
}
/*
* @implemented
*/
BOOL STDCALL
NtUserSetMenu(
HWND hWnd,
HMENU Menu,
BOOL Repaint)
{
PWINDOW_OBJECT Window;
BOOL Changed;
DECLARE_RETURN(BOOL);
DPRINT("Enter NtUserSetMenu\n");
UserEnterExclusive();
if (!(Window = UserGetWindowObject(hWnd)))
{
RETURN( FALSE);
}
if (! IntSetMenu(Window, Menu, &Changed))
{
RETURN( FALSE);
}
if (Changed && Repaint)
{
USER_REFERENCE_ENTRY Ref;
UserRefObjectCo(Window, &Ref);
co_WinPosSetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
UserDerefObjectCo(Window);
}
RETURN( TRUE);
CLEANUP:
DPRINT("Leave NtUserSetMenu, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* @unimplemented
*/
DWORD STDCALL
NtUserSetWindowFNID(DWORD Unknown0,
DWORD Unknown1)
{
UNIMPLEMENTED
return 0;
}
/*
* @implemented
*/
BOOL STDCALL
NtUserSetWindowPlacement(HWND hWnd,
WINDOWPLACEMENT *lpwndpl)
{
PWINDOW_OBJECT Window;
WINDOWPLACEMENT Safepl;
NTSTATUS Status;
DECLARE_RETURN(BOOL);
USER_REFERENCE_ENTRY Ref;
DPRINT("Enter NtUserSetWindowPlacement\n");
UserEnterExclusive();
if (!(Window = UserGetWindowObject(hWnd)))
{
RETURN( FALSE);
}
Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
if(!NT_SUCCESS(Status))
{
SetLastNtError(Status);
RETURN( FALSE);
}
if(Safepl.length != sizeof(WINDOWPLACEMENT))
{
RETURN( FALSE);
}
UserRefObjectCo(Window, &Ref);
if ((Window->Style & (WS_MAXIMIZE | WS_MINIMIZE)) == 0)
{
co_WinPosSetWindowPos(Window, NULL,
Safepl.rcNormalPosition.left, Safepl.rcNormalPosition.top,
Safepl.rcNormalPosition.right - Safepl.rcNormalPosition.left,
Safepl.rcNormalPosition.bottom - Safepl.rcNormalPosition.top,
SWP_NOZORDER | SWP_NOACTIVATE);
}
/* FIXME - change window status */
co_WinPosShowWindow(Window, Safepl.showCmd);
if (Window->InternalPos == NULL)
Window->InternalPos = ExAllocatePoolWithTag(PagedPool, sizeof(INTERNALPOS), TAG_WININTLIST);
Window->InternalPos->NormalRect = Safepl.rcNormalPosition;
Window->InternalPos->IconPos = Safepl.ptMinPosition;
Window->InternalPos->MaxPos = Safepl.ptMaxPosition;
UserDerefObjectCo(Window);
RETURN(TRUE);
CLEANUP:
DPRINT("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* @implemented
*/
BOOL STDCALL
NtUserSetWindowPos(
HWND hWnd,
HWND hWndInsertAfter,
int X,
int Y,
int cx,
int cy,
UINT uFlags)
{
DECLARE_RETURN(BOOL);
PWINDOW_OBJECT Window;
BOOL ret;
USER_REFERENCE_ENTRY Ref;
DPRINT("Enter NtUserSetWindowPos\n");
UserEnterExclusive();
if (!(Window = UserGetWindowObject(hWnd)))
{
RETURN(FALSE);
}
UserRefObjectCo(Window, &Ref);
ret = co_WinPosSetWindowPos(Window, hWndInsertAfter, X, Y, cx, cy, uFlags);
UserDerefObjectCo(Window);
RETURN(ret);
CLEANUP:
DPRINT("Leave NtUserSetWindowPos, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
INT FASTCALL
IntGetWindowRgn(PWINDOW_OBJECT Window, HRGN hRgn)
{
INT Ret;
HRGN VisRgn;
ROSRGNDATA *pRgn;
if(!Window)
{
return ERROR;
}
if(!hRgn)
{
return ERROR;
}
/* Create a new window region using the window rectangle */
VisRgn = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
NtGdiOffsetRgn(VisRgn, -Window->WindowRect.left, -Window->WindowRect.top);
/* if there's a region assigned to the window, combine them both */
if(Window->WindowRegion && !(Window->Style & WS_MINIMIZE))
NtGdiCombineRgn(VisRgn, VisRgn, Window->WindowRegion, RGN_AND);
/* Copy the region into hRgn */
NtGdiCombineRgn(hRgn, VisRgn, NULL, RGN_COPY);
if((pRgn = RGNDATA_LockRgn(hRgn)))
{
Ret = pRgn->rdh.iType;
RGNDATA_UnlockRgn(pRgn);
}
else
Ret = ERROR;
NtGdiDeleteObject(VisRgn);
return Ret;
}
INT FASTCALL
IntGetWindowRgnBox(PWINDOW_OBJECT Window, RECT *Rect)
{
INT Ret;
HRGN VisRgn;
ROSRGNDATA *pRgn;
if(!Window)
{
return ERROR;
}
if(!Rect)
{
return ERROR;
}
/* Create a new window region using the window rectangle */
VisRgn = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
NtGdiOffsetRgn(VisRgn, -Window->WindowRect.left, -Window->WindowRect.top);
/* if there's a region assigned to the window, combine them both */
if(Window->WindowRegion && !(Window->Style & WS_MINIMIZE))
NtGdiCombineRgn(VisRgn, VisRgn, Window->WindowRegion, RGN_AND);
if((pRgn = RGNDATA_LockRgn(VisRgn)))
{
Ret = pRgn->rdh.iType;
*Rect = pRgn->rdh.rcBound;
RGNDATA_UnlockRgn(pRgn);
}
else
Ret = ERROR;
NtGdiDeleteObject(VisRgn);
return Ret;
}
/*
* @implemented
*/
INT STDCALL
NtUserSetWindowRgn(
HWND hWnd,
HRGN hRgn,
BOOL bRedraw)
{
PWINDOW_OBJECT Window;
DECLARE_RETURN(INT);
DPRINT("Enter NtUserSetWindowRgn\n");
UserEnterExclusive();
if (!(Window = UserGetWindowObject(hWnd)))
{
RETURN( 0);
}
/* FIXME - Verify if hRgn is a valid handle!!!!
Propably make this operation thread-safe, but maybe it's not necessary */
if(Window->WindowRegion)
{
/* Delete no longer needed region handle */
NtGdiDeleteObject(Window->WindowRegion);
}
Window->WindowRegion = hRgn;
/* FIXME - send WM_WINDOWPOSCHANGING and WM_WINDOWPOSCHANGED messages to the window */
if(bRedraw)
{
USER_REFERENCE_ENTRY Ref;
UserRefObjectCo(Window, &Ref);
co_UserRedrawWindow(Window, NULL, NULL, RDW_INVALIDATE);
UserDerefObjectCo(Window);
}
RETURN( (INT)hRgn);
CLEANUP:
DPRINT("Leave NtUserSetWindowRgn, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* @implemented
*/
BOOL STDCALL
NtUserShowWindow(HWND hWnd, LONG nCmdShow)
{
PWINDOW_OBJECT Window;
BOOL ret;
DECLARE_RETURN(BOOL);
USER_REFERENCE_ENTRY Ref;
DPRINT("Enter NtUserShowWindow\n");
UserEnterExclusive();
if (!(Window = UserGetWindowObject(hWnd)))
{
RETURN(FALSE);
}
UserRefObjectCo(Window, &Ref);
ret = co_WinPosShowWindow(Window, nCmdShow);
UserDerefObjectCo(Window);
RETURN(ret);
CLEANUP:
DPRINT("Leave NtUserShowWindow, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* @unimplemented
*/
BOOL STDCALL
NtUserShowWindowAsync(HWND hWnd, LONG nCmdShow)
{
#if 0
UNIMPLEMENTED
return 0;
#else
return NtUserShowWindow(hWnd, nCmdShow);
#endif
}
/*
* @unimplemented
*/
DWORD STDCALL
NtUserUpdateLayeredWindow(DWORD Unknown0,
DWORD Unknown1,
DWORD Unknown2,
DWORD Unknown3,
DWORD Unknown4,
DWORD Unknown5,
DWORD Unknown6,
DWORD Unknown7,
DWORD Unknown8)
{
UNIMPLEMENTED
return 0;
}
/*
* @implemented
*/
HWND STDCALL
NtUserWindowFromPoint(LONG X, LONG Y)
{
POINT pt;
HWND Ret;
PWINDOW_OBJECT DesktopWindow = NULL, Window = NULL;
DECLARE_RETURN(HWND);
USER_REFERENCE_ENTRY Ref;
DPRINT("Enter NtUserWindowFromPoint\n");
UserEnterExclusive();
if ((DesktopWindow = UserGetWindowObject(IntGetDesktopWindow())))
{
USHORT Hit;
pt.x = X;
pt.y = Y;
//hmm... threads live on desktops thus we have a reference on the desktop and indirectly the desktop window
//its possible this referencing is useless, thou it shouldnt hurt...
UserRefObjectCo(DesktopWindow, &Ref);
Hit = co_WinPosWindowFromPoint(DesktopWindow, PsGetCurrentThreadWin32Thread()->MessageQueue, &pt, &Window);
if(Window)
{
Ret = Window->hSelf;
RETURN( Ret);
}
}
RETURN( NULL);
CLEANUP:
if (Window) UserDerefObject(Window);
if (DesktopWindow) UserDerefObjectCo(DesktopWindow);
DPRINT("Leave NtUserWindowFromPoint, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* NtUserDefSetText
*
* Undocumented function that is called from DefWindowProc to set
* window text.
*
* Status
* @implemented
*/
BOOL STDCALL
NtUserDefSetText(HWND hWnd, PUNICODE_STRING WindowText)
{
PWINDOW_OBJECT Window;
UNICODE_STRING SafeText;
NTSTATUS Status;
DECLARE_RETURN(INT);
DPRINT("Enter NtUserDefSetText\n");
UserEnterExclusive();
if(!(Window = UserGetWindowObject(hWnd)))
{
RETURN( FALSE);
}
if(WindowText)
{
Status = IntSafeCopyUnicodeString(&SafeText, WindowText);
if(!NT_SUCCESS(Status))
{
SetLastNtError(Status);
RETURN( FALSE);
}
}
else
{
RtlInitUnicodeString(&SafeText, NULL);
}
/* FIXME - do this thread-safe! otherwise one could crash here! */
RtlFreeUnicodeString(&Window->WindowName);
Window->WindowName = SafeText;
/* Send shell notifications */
if (!IntGetOwner(Window) && !IntGetParent(Window))
{
co_IntShellHookNotify(HSHELL_REDRAW, (LPARAM) hWnd);
}
RETURN( TRUE);
CLEANUP:
DPRINT("Leave NtUserDefSetText, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* NtUserInternalGetWindowText
*
* Status
* @implemented
*/
INT STDCALL
NtUserInternalGetWindowText(HWND hWnd, LPWSTR lpString, INT nMaxCount)
{
PWINDOW_OBJECT Window;
NTSTATUS Status;
INT Result;
DECLARE_RETURN(INT);
DPRINT("Enter NtUserInternalGetWindowText\n");
UserEnterShared();
if(lpString && (nMaxCount <= 1))
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
RETURN( 0);
}
if(!(Window = UserGetWindowObject(hWnd)))
{
RETURN( 0);
}
/* FIXME - do this thread-safe! otherwise one could crash here! */
Result = Window->WindowName.Length / sizeof(WCHAR);
if(lpString)
{
const WCHAR Terminator = L'\0';
INT Copy;
WCHAR *Buffer = (WCHAR*)lpString;
Copy = min(nMaxCount - 1, Result);
if(Copy > 0)
{
Status = MmCopyToCaller(Buffer, Window->WindowName.Buffer, Copy * sizeof(WCHAR));
if(!NT_SUCCESS(Status))
{
SetLastNtError(Status);
RETURN( 0);
}
Buffer += Copy;
}
Status = MmCopyToCaller(Buffer, &Terminator, sizeof(WCHAR));
if(!NT_SUCCESS(Status))
{
SetLastNtError(Status);
RETURN( 0);
}
Result = Copy;
}
RETURN( Result);
CLEANUP:
DPRINT("Leave NtUserInternalGetWindowText, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
#define WIN_NEEDS_SHOW_OWNEDPOPUP (0x00000040)
BOOL
FASTCALL
IntShowOwnedPopups(PWINDOW_OBJECT OwnerWnd, BOOL fShow )
{
int count = 0;
PWINDOW_OBJECT pWnd;
HWND *win_array;
ASSERT(OwnerWnd);
win_array = IntWinListChildren(OwnerWnd);//faxme: use desktop?
if (!win_array)
return TRUE;
while (win_array[count])
count++;
while (--count >= 0)
{
if (UserGetWindow( win_array[count], GW_OWNER ) != OwnerWnd->hSelf)
continue;
if (!(pWnd = UserGetWindowObject( win_array[count] )))
continue;
// if (pWnd == WND_OTHER_PROCESS) continue;
if (fShow)
{
if (pWnd->Flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
{
/* In Windows, ShowOwnedPopups(TRUE) generates
* WM_SHOWWINDOW messages with SW_PARENTOPENING,
* regardless of the state of the owner
*/
co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
continue;
}
}
else
{
if (pWnd->Style & WS_VISIBLE)
{
/* In Windows, ShowOwnedPopups(FALSE) generates
* WM_SHOWWINDOW messages with SW_PARENTCLOSING,
* regardless of the state of the owner
*/
co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
continue;
}
}
}
ExFreePool( win_array );
return TRUE;
}
/*
* NtUserValidateHandleSecure
*
* Status
* @implemented
*/
BOOL
STDCALL
NtUserValidateHandleSecure(
HANDLE handle,
BOOL Restricted)
{
if(!Restricted)
{
UINT uType;
{
PUSER_HANDLE_ENTRY entry;
if (!(entry = handle_to_entry(gHandleTable, handle )))
{
SetLastWin32Error(ERROR_INVALID_HANDLE);
return FALSE;
}
uType = entry->type;
}
switch (uType)
{
case otWindow:
{
PWINDOW_OBJECT Window;
if ((Window = UserGetWindowObject((HWND) handle))) return TRUE;
return FALSE;
}
case otMenu:
{
PMENU_OBJECT Menu;
if ((Menu = UserGetMenuObject((HMENU) handle))) return TRUE;
return FALSE;
}
case otAccel:
{
PACCELERATOR_TABLE Accel;
if ((Accel = UserGetAccelObject((HACCEL) handle))) return TRUE;
return FALSE;
}
case otCursorIcon:
{
PCURICON_OBJECT Cursor;
if ((Cursor = UserGetCurIconObject((HCURSOR) handle))) return TRUE;
return FALSE;
}
case otHook:
{
PHOOK Hook;
if ((Hook = IntGetHookObject((HHOOK) handle))) return TRUE;
return FALSE;
}
case otMonitor:
{
PMONITOR_OBJECT Monitor;
if ((Monitor = UserGetMonitorObject((HMONITOR) handle))) return TRUE;
return FALSE;
}
case otCallProc:
{
WNDPROC_INFO Proc;
return UserGetCallProcInfo( handle, &Proc );
}
default:
SetLastWin32Error(ERROR_INVALID_HANDLE);
}
}
else
{ /* Is handle entry restricted? */
UNIMPLEMENTED
}
return FALSE;
}
/* EOF */