mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 15:13:05 +00:00
4688 lines
108 KiB
C
4688 lines
108 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>
|
|
|
|
static WndProcHandle *WndProcHandlesArray = 0;
|
|
static WORD WndProcHandlesArraySize = 0;
|
|
#define WPH_SIZE 0x40 /* the size to add to the WndProcHandle array each time */
|
|
|
|
/* 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)
|
|
{
|
|
WndProcHandlesArray = ExAllocatePoolWithTag(PagedPool,WPH_SIZE * sizeof(WndProcHandle), TAG_WINPROCLST);
|
|
WndProcHandlesArraySize = WPH_SIZE;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* CleanupWindowImpl
|
|
*
|
|
* Cleanup windowing implementation.
|
|
*/
|
|
|
|
NTSTATUS FASTCALL
|
|
CleanupWindowImpl(VOID)
|
|
{
|
|
ExFreePool(WndProcHandlesArray);
|
|
WndProcHandlesArray = 0;
|
|
WndProcHandlesArraySize = 0;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* HELPER FUNCTIONS ***********************************************************/
|
|
|
|
|
|
|
|
/* temp hack */
|
|
PWINDOW_OBJECT FASTCALL UserGetWindowObjectNoRef(HWND hWnd)
|
|
{
|
|
|
|
PWINDOW_OBJECT w = IntGetWindowObject(hWnd);
|
|
if (w) IntReleaseWindowObject(w);
|
|
return w;
|
|
}
|
|
|
|
|
|
/*
|
|
* 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 = IntGetWindowObject(hWnd)))
|
|
return FALSE;
|
|
|
|
IntReleaseWindowObject(Window);
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* IntGetProcessWindowObject
|
|
*
|
|
* Get window object from handle of specified process.
|
|
*/
|
|
|
|
PWINDOW_OBJECT FASTCALL
|
|
IntGetProcessWindowObject(PW32THREAD Thread, HWND hWnd)
|
|
{
|
|
PWINDOW_OBJECT WindowObject;
|
|
NTSTATUS Status;
|
|
|
|
if(Thread->Desktop != NULL)
|
|
{
|
|
Status = ObmReferenceObjectByHandle(Thread->Desktop->WindowStation->HandleTable,
|
|
hWnd, otWindow, (PVOID*)&WindowObject);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
return WindowObject;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PWINDOW_OBJECT FASTCALL
|
|
IntGetParent(PWINDOW_OBJECT Wnd)
|
|
{
|
|
HWND hWnd;
|
|
|
|
if (Wnd->Style & WS_POPUP)
|
|
{
|
|
hWnd = Wnd->Owner;
|
|
return IntGetWindowObject(hWnd);
|
|
}
|
|
else if (Wnd->Style & WS_CHILD)
|
|
{
|
|
hWnd = Wnd->Parent;
|
|
return IntGetWindowObject(hWnd);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
PWINDOW_OBJECT FASTCALL
|
|
IntGetOwner(PWINDOW_OBJECT Wnd)
|
|
{
|
|
HWND hWnd;
|
|
|
|
hWnd = Wnd->Owner;
|
|
|
|
return IntGetWindowObject(hWnd);
|
|
}
|
|
|
|
PWINDOW_OBJECT FASTCALL
|
|
IntGetParentObject(PWINDOW_OBJECT Wnd)
|
|
{
|
|
HWND hParent;
|
|
|
|
hParent = Wnd->Parent;
|
|
return IntGetWindowObject(hParent);
|
|
}
|
|
|
|
/*
|
|
* 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->Self;
|
|
List[Index] = NULL;
|
|
|
|
return List;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* IntSendDestroyMsg
|
|
*/
|
|
static void IntSendDestroyMsg(HWND Wnd)
|
|
{
|
|
|
|
PWINDOW_OBJECT Window, Owner, Parent;
|
|
#if 0 /* FIXME */
|
|
GUITHREADINFO info;
|
|
|
|
if (GetGUIThreadInfo(GetCurrentThreadId(), &info))
|
|
{
|
|
if (Wnd == info.hwndCaret)
|
|
{
|
|
DestroyCaret();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
Window = IntGetWindowObject(Wnd);
|
|
if (Window) {
|
|
Owner = IntGetOwner(Window);
|
|
if (!Owner) {
|
|
Parent = IntGetParent(Window);
|
|
if (!Parent)
|
|
co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (LPARAM) Wnd);
|
|
else
|
|
IntReleaseWindowObject(Parent);
|
|
} else {
|
|
IntReleaseWindowObject(Owner);
|
|
}
|
|
|
|
IntReleaseWindowObject(Window);
|
|
}
|
|
|
|
/* The window could already be destroyed here */
|
|
|
|
/*
|
|
* Send the WM_DESTROY to the window.
|
|
*/
|
|
|
|
co_IntSendMessage(Wnd, 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
|
|
*/
|
|
static LRESULT co_IntDestroyWindow(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->Flags &= ~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->Self);
|
|
|
|
if(SendMessages)
|
|
{
|
|
/* Send destroy messages */
|
|
IntSendDestroyMsg(Window->Self);
|
|
}
|
|
|
|
/* 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->Self);
|
|
}
|
|
else
|
|
co_IntDestroyWindow(Child, ProcessData, ThreadData, SendMessages);
|
|
IntReleaseWindowObject(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->Self, WM_NCDESTROY, 0, 0);
|
|
}
|
|
MsqRemoveTimersWindow(ThreadData->MessageQueue, Window->Self);
|
|
|
|
/* 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->Self == ThreadData->Desktop->WindowStation->ShellWindow)
|
|
ThreadData->Desktop->WindowStation->ShellWindow = NULL;
|
|
|
|
if (Window->Self == 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->Self);
|
|
if (Window->Self == GetCapture())
|
|
{
|
|
ReleaseCapture();
|
|
}
|
|
|
|
/* free resources associated with the window */
|
|
TIMER_RemoveWindowTimers(Window->Self);
|
|
#endif
|
|
|
|
if (!(Window->Style & WS_CHILD) && Window->IDMenu
|
|
&& (Menu = IntGetMenuObject((HMENU)Window->IDMenu)))
|
|
{
|
|
IntDestroyMenuObject(Menu, TRUE, TRUE);
|
|
Window->IDMenu = 0;
|
|
IntReleaseMenuObject(Menu);
|
|
}
|
|
|
|
if(Window->SystemMenu
|
|
&& (Menu = IntGetMenuObject(Window->SystemMenu)))
|
|
{
|
|
IntDestroyMenuObject(Menu, TRUE, TRUE);
|
|
Window->SystemMenu = (HMENU)0;
|
|
IntReleaseMenuObject(Menu);
|
|
}
|
|
|
|
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);
|
|
|
|
IntReferenceWindowObject(Window);
|
|
ObmCloseHandle(ThreadData->Desktop->WindowStation->HandleTable, Window->Self);
|
|
|
|
IntDestroyScrollBars(Window);
|
|
|
|
/* remove the window from the class object */
|
|
RemoveEntryList(&Window->ClassListEntry);
|
|
|
|
/* dereference the class */
|
|
ClassDereferenceObject(Window->Class);
|
|
Window->Class = NULL;
|
|
|
|
if(Window->WindowRegion)
|
|
{
|
|
NtGdiDeleteObject(Window->WindowRegion);
|
|
}
|
|
|
|
RtlFreeUnicodeString(&Window->WindowName);
|
|
|
|
IntReleaseWindowObject(Window);
|
|
|
|
return 0;
|
|
}
|
|
|
|
VOID FASTCALL
|
|
IntGetWindowBorderMeasures(PWINDOW_OBJECT WindowObject, UINT *cx, UINT *cy)
|
|
{
|
|
if(HAS_DLGFRAME(WindowObject->Style, WindowObject->ExStyle) && !(WindowObject->Style & WS_MINIMIZE))
|
|
{
|
|
*cx = UserGetSystemMetrics(SM_CXDLGFRAME);
|
|
*cy = UserGetSystemMetrics(SM_CYDLGFRAME);
|
|
}
|
|
else
|
|
{
|
|
if(HAS_THICKFRAME(WindowObject->Style, WindowObject->ExStyle)&& !(WindowObject->Style & WS_MINIMIZE))
|
|
{
|
|
*cx = UserGetSystemMetrics(SM_CXFRAME);
|
|
*cy = UserGetSystemMetrics(SM_CYFRAME);
|
|
}
|
|
else if(HAS_THINFRAME(WindowObject->Style, WindowObject->ExStyle))
|
|
{
|
|
*cx = UserGetSystemMetrics(SM_CXBORDER);
|
|
*cy = UserGetSystemMetrics(SM_CYBORDER);
|
|
}
|
|
else
|
|
{
|
|
*cx = *cy = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL FASTCALL
|
|
IntGetWindowInfo(PWINDOW_OBJECT WindowObject, PWINDOWINFO pwi)
|
|
{
|
|
pwi->cbSize = sizeof(WINDOWINFO);
|
|
pwi->rcWindow = WindowObject->WindowRect;
|
|
pwi->rcClient = WindowObject->ClientRect;
|
|
pwi->dwStyle = WindowObject->Style;
|
|
pwi->dwExStyle = WindowObject->ExStyle;
|
|
pwi->dwWindowStatus = (UserGetForegroundWindow() == WindowObject->Self); /* WS_ACTIVECAPTION */
|
|
IntGetWindowBorderMeasures(WindowObject, &pwi->cxWindowBorders, &pwi->cyWindowBorders);
|
|
pwi->atomWindowType = (WindowObject->Class ? WindowObject->Class->Atom : 0);
|
|
pwi->wCreatorVersion = 0x400; /* FIXME - return a real version number */
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL FASTCALL
|
|
IntSetMenu(
|
|
PWINDOW_OBJECT WindowObject,
|
|
HMENU Menu,
|
|
BOOL *Changed)
|
|
{
|
|
PMENU_OBJECT OldMenuObject, NewMenuObject = NULL;
|
|
|
|
if ((WindowObject->Style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
*Changed = (WindowObject->IDMenu != (UINT) Menu);
|
|
if (! *Changed)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
if (WindowObject->IDMenu)
|
|
{
|
|
OldMenuObject = IntGetMenuObject((HMENU) WindowObject->IDMenu);
|
|
ASSERT(NULL == OldMenuObject || OldMenuObject->MenuInfo.Wnd == WindowObject->Self);
|
|
}
|
|
else
|
|
{
|
|
OldMenuObject = NULL;
|
|
}
|
|
|
|
if (NULL != Menu)
|
|
{
|
|
NewMenuObject = IntGetMenuObject(Menu);
|
|
if (NULL == NewMenuObject)
|
|
{
|
|
if (NULL != OldMenuObject)
|
|
{
|
|
IntReleaseMenuObject(OldMenuObject);
|
|
}
|
|
SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
|
|
return FALSE;
|
|
}
|
|
if (NULL != NewMenuObject->MenuInfo.Wnd)
|
|
{
|
|
/* Can't use the same menu for two windows */
|
|
if (NULL != OldMenuObject)
|
|
{
|
|
IntReleaseMenuObject(OldMenuObject);
|
|
}
|
|
SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
WindowObject->IDMenu = (UINT) Menu;
|
|
if (NULL != NewMenuObject)
|
|
{
|
|
NewMenuObject->MenuInfo.Wnd = WindowObject->Self;
|
|
IntReleaseMenuObject(NewMenuObject);
|
|
}
|
|
if (NULL != OldMenuObject)
|
|
{
|
|
OldMenuObject->MenuInfo.Wnd = NULL;
|
|
IntReleaseMenuObject(OldMenuObject);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* INTERNAL ******************************************************************/
|
|
|
|
|
|
VOID FASTCALL
|
|
co_DestroyThreadWindows(struct _ETHREAD *Thread)
|
|
{
|
|
PLIST_ENTRY Current;
|
|
PW32PROCESS Win32Process;
|
|
PW32THREAD Win32Thread;
|
|
PWINDOW_OBJECT *List, *pWnd;
|
|
ULONG Cnt = 0;
|
|
|
|
Win32Thread = Thread->Tcb.Win32Thread;
|
|
Win32Process = (PW32PROCESS)Thread->ThreadsProcess->Win32Process;
|
|
|
|
Current = Win32Thread->WindowListHead.Flink;
|
|
while (Current != &(Win32Thread->WindowListHead))
|
|
{
|
|
Cnt++;
|
|
Current = Current->Flink;
|
|
}
|
|
|
|
if(Cnt > 0)
|
|
{
|
|
List = ExAllocatePool(PagedPool, (Cnt + 1) * sizeof(PWINDOW_OBJECT));
|
|
if(!List)
|
|
{
|
|
DPRINT("Not enough memory to allocate window handle list\n");
|
|
return;
|
|
}
|
|
pWnd = List;
|
|
Current = Win32Thread->WindowListHead.Flink;
|
|
while (Current != &(Win32Thread->WindowListHead))
|
|
{
|
|
*pWnd = CONTAINING_RECORD(Current, WINDOW_OBJECT, ThreadListEntry);
|
|
IntReferenceWindowObject(*pWnd);
|
|
pWnd++;
|
|
Current = Current->Flink;
|
|
}
|
|
*pWnd = NULL;
|
|
|
|
for(pWnd = List; *pWnd; pWnd++)
|
|
{
|
|
co_UserDestroyWindow(*pWnd);
|
|
IntReleaseWindowObject(*pWnd);
|
|
}
|
|
ExFreePool(List);
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*!
|
|
* 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 WindowObject, PRECT Rect)
|
|
{
|
|
ASSERT( WindowObject );
|
|
ASSERT( Rect );
|
|
|
|
Rect->left = Rect->top = 0;
|
|
Rect->right = WindowObject->ClientRect.right - WindowObject->ClientRect.left;
|
|
Rect->bottom = WindowObject->ClientRect.bottom - WindowObject->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 WindowObject, BOOL bRevert, BOOL RetMenu)
|
|
{
|
|
PMENU_OBJECT MenuObject, NewMenuObject, SysMenuObject, ret = NULL;
|
|
PW32THREAD W32Thread;
|
|
HMENU NewMenu, SysMenu;
|
|
ROSMENUITEMINFO ItemInfo;
|
|
|
|
if(bRevert)
|
|
{
|
|
W32Thread = PsGetWin32Thread();
|
|
|
|
if(!W32Thread->Desktop)
|
|
return NULL;
|
|
|
|
if(WindowObject->SystemMenu)
|
|
{
|
|
MenuObject = IntGetMenuObject(WindowObject->SystemMenu);
|
|
if(MenuObject)
|
|
{
|
|
IntDestroyMenuObject(MenuObject, FALSE, TRUE);
|
|
WindowObject->SystemMenu = (HMENU)0;
|
|
IntReleaseMenuObject(MenuObject);
|
|
}
|
|
}
|
|
|
|
if(W32Thread->Desktop->WindowStation->SystemMenuTemplate)
|
|
{
|
|
/* clone system menu */
|
|
MenuObject = IntGetMenuObject(W32Thread->Desktop->WindowStation->SystemMenuTemplate);
|
|
if(!MenuObject)
|
|
return NULL;
|
|
|
|
NewMenuObject = IntCloneMenu(MenuObject);
|
|
if(NewMenuObject)
|
|
{
|
|
WindowObject->SystemMenu = NewMenuObject->MenuInfo.Self;
|
|
NewMenuObject->MenuInfo.Flags |= MF_SYSMENU;
|
|
NewMenuObject->MenuInfo.Wnd = WindowObject->Self;
|
|
ret = NewMenuObject;
|
|
//IntReleaseMenuObject(NewMenuObject);
|
|
}
|
|
IntReleaseMenuObject(MenuObject);
|
|
}
|
|
else
|
|
{
|
|
SysMenu = UserCreateMenu(FALSE);
|
|
if (NULL == SysMenu)
|
|
{
|
|
return NULL;
|
|
}
|
|
SysMenuObject = IntGetMenuObject(SysMenu);
|
|
if (NULL == SysMenuObject)
|
|
{
|
|
UserDestroyMenu(SysMenu);
|
|
return NULL;
|
|
}
|
|
SysMenuObject->MenuInfo.Flags |= MF_SYSMENU;
|
|
SysMenuObject->MenuInfo.Wnd = WindowObject->Self;
|
|
NewMenu = co_IntLoadSysMenuTemplate();
|
|
if(!NewMenu)
|
|
{
|
|
IntReleaseMenuObject(SysMenuObject);
|
|
UserDestroyMenu(SysMenu);
|
|
return NULL;
|
|
}
|
|
MenuObject = IntGetMenuObject(NewMenu);
|
|
if(!MenuObject)
|
|
{
|
|
IntReleaseMenuObject(SysMenuObject);
|
|
UserDestroyMenu(SysMenu);
|
|
return NULL;
|
|
}
|
|
|
|
NewMenuObject = IntCloneMenu(MenuObject);
|
|
if(NewMenuObject)
|
|
{
|
|
NewMenuObject->MenuInfo.Flags |= MF_SYSMENU | MF_POPUP;
|
|
IntReleaseMenuObject(NewMenuObject);
|
|
UserSetMenuDefaultItem(NewMenuObject->MenuInfo.Self, 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 = NewMenuObject->MenuInfo.Self;
|
|
IntInsertMenuItem(SysMenuObject, (UINT) -1, TRUE, &ItemInfo);
|
|
|
|
WindowObject->SystemMenu = SysMenuObject->MenuInfo.Self;
|
|
|
|
ret = SysMenuObject;
|
|
}
|
|
IntDestroyMenuObject(MenuObject, FALSE, TRUE);
|
|
IntReleaseMenuObject(MenuObject);
|
|
}
|
|
if(RetMenu)
|
|
return ret;
|
|
else
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
if(WindowObject->SystemMenu)
|
|
return IntGetMenuObject((HMENU)WindowObject->SystemMenu);
|
|
else
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL FASTCALL
|
|
IntIsChildWindow(HWND Parent, HWND Child)
|
|
{
|
|
PWINDOW_OBJECT BaseWindow, Window, Old;
|
|
|
|
if(!(BaseWindow = IntGetWindowObject(Child)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
Window = BaseWindow;
|
|
while (Window)
|
|
{
|
|
if (Window->Self == Parent)
|
|
{
|
|
if(Window != BaseWindow)
|
|
IntReleaseWindowObject(Window);
|
|
IntReleaseWindowObject(BaseWindow);
|
|
return(TRUE);
|
|
}
|
|
if(!(Window->Style & WS_CHILD))
|
|
{
|
|
if(Window != BaseWindow)
|
|
IntReleaseWindowObject(Window);
|
|
break;
|
|
}
|
|
Old = Window;
|
|
Window = IntGetParentObject(Window);
|
|
if(Old != BaseWindow)
|
|
IntReleaseWindowObject(Old);
|
|
}
|
|
|
|
IntReleaseWindowObject(BaseWindow);
|
|
return(FALSE);
|
|
}
|
|
|
|
BOOL FASTCALL
|
|
IntIsWindowVisible(HWND hWnd)
|
|
{
|
|
PWINDOW_OBJECT BaseWindow, Window, Old;
|
|
|
|
if(!(BaseWindow = IntGetWindowObject(hWnd)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
Window = BaseWindow;
|
|
while(Window)
|
|
{
|
|
if(!(Window->Style & WS_CHILD))
|
|
{
|
|
break;
|
|
}
|
|
if(!(Window->Style & WS_VISIBLE))
|
|
{
|
|
if(Window != BaseWindow)
|
|
IntReleaseWindowObject(Window);
|
|
IntReleaseWindowObject(BaseWindow);
|
|
return FALSE;
|
|
}
|
|
Old = Window;
|
|
Window = IntGetParentObject(Window);
|
|
if(Old != BaseWindow)
|
|
IntReleaseWindowObject(Old);
|
|
}
|
|
|
|
if(Window)
|
|
{
|
|
if(Window->Style & WS_VISIBLE)
|
|
{
|
|
if(Window != BaseWindow)
|
|
IntReleaseWindowObject(Window);
|
|
IntReleaseWindowObject(BaseWindow);
|
|
return TRUE;
|
|
}
|
|
if(Window != BaseWindow)
|
|
IntReleaseWindowObject(Window);
|
|
}
|
|
IntReleaseWindowObject(BaseWindow);
|
|
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->Self;
|
|
if ((Wnd->PrevSibling = WndPrevSibling))
|
|
{
|
|
/* link after WndPrevSibling */
|
|
if ((Wnd->NextSibling = WndPrevSibling->NextSibling))
|
|
Wnd->NextSibling->PrevSibling = Wnd;
|
|
else if ((Parent = IntGetWindowObject(Wnd->Parent)))
|
|
{
|
|
if(Parent->LastChild == WndPrevSibling)
|
|
Parent->LastChild = Wnd;
|
|
IntReleaseWindowObject(Parent);
|
|
}
|
|
Wnd->PrevSibling->NextSibling = Wnd;
|
|
}
|
|
else
|
|
{
|
|
/* link at top */
|
|
Parent = IntGetWindowObject(Wnd->Parent);
|
|
if ((Wnd->NextSibling = WndParent->FirstChild))
|
|
Wnd->NextSibling->PrevSibling = Wnd;
|
|
else if (Parent)
|
|
{
|
|
Parent->LastChild = Wnd;
|
|
Parent->FirstChild = Wnd;
|
|
IntReleaseWindowObject(Parent);
|
|
return;
|
|
}
|
|
if(Parent)
|
|
{
|
|
Parent->FirstChild = Wnd;
|
|
IntReleaseWindowObject(Parent);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
HWND FASTCALL
|
|
IntSetOwner(HWND hWnd, HWND hWndNewOwner)
|
|
{
|
|
PWINDOW_OBJECT Wnd, WndOldOwner, WndNewOwner;
|
|
HWND ret;
|
|
|
|
Wnd = IntGetWindowObject(hWnd);
|
|
if(!Wnd)
|
|
return NULL;
|
|
|
|
WndOldOwner = IntGetWindowObject(Wnd->Owner);
|
|
if (WndOldOwner)
|
|
{
|
|
ret = WndOldOwner->Self;
|
|
IntReleaseWindowObject(WndOldOwner);
|
|
}
|
|
else
|
|
{
|
|
ret = 0;
|
|
}
|
|
|
|
if((WndNewOwner = IntGetWindowObject(hWndNewOwner)))
|
|
{
|
|
Wnd->Owner = hWndNewOwner;
|
|
IntReleaseWindowObject(WndNewOwner);
|
|
}
|
|
else
|
|
Wnd->Owner = NULL;
|
|
|
|
IntReleaseWindowObject(Wnd);
|
|
return ret;
|
|
}
|
|
|
|
PWINDOW_OBJECT FASTCALL
|
|
IntSetParent(PWINDOW_OBJECT Wnd, PWINDOW_OBJECT WndNewParent)
|
|
{
|
|
PWINDOW_OBJECT WndOldParent, Sibling, InsertAfter;
|
|
HWND hWnd, hWndNewParent, hWndOldParent;
|
|
BOOL WasVisible;
|
|
BOOL MenuChanged;
|
|
|
|
ASSERT(Wnd);
|
|
ASSERT(WndNewParent);
|
|
|
|
hWnd = Wnd->Self;
|
|
hWndNewParent = WndNewParent->Self;
|
|
|
|
/*
|
|
* Windows hides the window first, then shows it again
|
|
* including the WM_SHOWWINDOW messages and all
|
|
*/
|
|
WasVisible = co_WinPosShowWindow(hWnd, 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 = IntGetParentObject(Wnd);
|
|
hWndOldParent = (WndOldParent ? WndOldParent->Self : NULL);
|
|
|
|
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
|
|
{
|
|
IntReferenceWindowObject(InsertAfter);
|
|
IntLinkWindow(Wnd, WndNewParent, InsertAfter /*prev sibling*/);
|
|
IntReleaseWindowObject(InsertAfter);
|
|
}
|
|
|
|
if (WndNewParent->Self != IntGetDesktopWindow()) /* a child window */
|
|
{
|
|
if (!(Wnd->Style & WS_CHILD))
|
|
{
|
|
//if ( Wnd->Menu ) DestroyMenu ( Wnd->menu );
|
|
IntSetMenu(Wnd, NULL, &MenuChanged);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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(hWnd, (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->Self))
|
|
{
|
|
IntReleaseWindowObject(WndOldParent);
|
|
return NULL;
|
|
}
|
|
|
|
/* don't dereference the window object here, it must be done by the caller
|
|
of IntSetParent() */
|
|
return WndOldParent;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
BOOL FASTCALL
|
|
IntSetSystemMenu(PWINDOW_OBJECT WindowObject, PMENU_OBJECT MenuObject)
|
|
{
|
|
PMENU_OBJECT OldMenuObject;
|
|
if(WindowObject->SystemMenu)
|
|
{
|
|
OldMenuObject = IntGetMenuObject(WindowObject->SystemMenu);
|
|
if(OldMenuObject)
|
|
{
|
|
OldMenuObject->MenuInfo.Flags &= ~ MF_SYSMENU;
|
|
IntReleaseMenuObject(OldMenuObject);
|
|
}
|
|
}
|
|
|
|
if(MenuObject)
|
|
{
|
|
/* FIXME check window style, propably return FALSE ? */
|
|
WindowObject->SystemMenu = MenuObject->MenuInfo.Self;
|
|
MenuObject->MenuInfo.Flags |= MF_SYSMENU;
|
|
}
|
|
else
|
|
WindowObject->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;
|
|
|
|
if((WndParent = IntGetWindowObject(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;
|
|
|
|
if(WndParent)
|
|
{
|
|
IntReleaseWindowObject(WndParent);
|
|
}
|
|
Wnd->PrevSibling = Wnd->NextSibling = Wnd->Parent = NULL;
|
|
}
|
|
|
|
BOOL FASTCALL
|
|
IntAnyPopup(VOID)
|
|
{
|
|
PWINDOW_OBJECT Window, Child;
|
|
|
|
if(!(Window = IntGetWindowObject(IntGetDesktopWindow())))
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
for(Child = Window->FirstChild; Child; Child = Child->NextSibling)
|
|
{
|
|
if(Child->Owner && Child->Style & WS_VISIBLE)
|
|
{
|
|
/*
|
|
* The desktop has a popup window if one of them has
|
|
* an owner window and is visible
|
|
*/
|
|
IntReleaseWindowObject(Window);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
IntReleaseWindowObject(Window);
|
|
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;
|
|
|
|
/* FIXME handle bChildren */
|
|
|
|
if(hwndParent)
|
|
{
|
|
PWINDOW_OBJECT Window, Child;
|
|
if(!(Window = IntGetWindowObject(hwndParent)))
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_HANDLE);
|
|
return 0;
|
|
}
|
|
|
|
for(Child = Window->FirstChild; Child != NULL; Child = Child->NextSibling)
|
|
{
|
|
if(dwCount++ < nBufSize && pWnd)
|
|
{
|
|
Status = MmCopyToCaller(pWnd++, &Child->Self, sizeof(HWND));
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
SetLastNtError(Status);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
IntReleaseWindowObject(Window);
|
|
}
|
|
else if(dwThreadId)
|
|
{
|
|
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 = 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->Self, sizeof(HWND));
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
SetLastNtError(Status);
|
|
break;
|
|
}
|
|
}
|
|
dwCount++;
|
|
Current = Current->Flink;
|
|
}
|
|
|
|
ObDereferenceObject(Thread);
|
|
}
|
|
else
|
|
{
|
|
PDESKTOP_OBJECT Desktop;
|
|
PWINDOW_OBJECT Window, Child;
|
|
|
|
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;
|
|
}
|
|
}
|
|
if(!(Window = IntGetWindowObject(Desktop->DesktopWindow)))
|
|
{
|
|
if(hDesktop)
|
|
ObDereferenceObject(Desktop);
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
return 0;
|
|
}
|
|
|
|
for(Child = Window->FirstChild; Child != NULL; Child = Child->NextSibling)
|
|
{
|
|
if(dwCount++ < nBufSize && pWnd)
|
|
{
|
|
Status = MmCopyToCaller(pWnd++, &Child->Self, sizeof(HWND));
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
SetLastNtError(Status);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
IntReleaseWindowObject(Window);
|
|
if(hDesktop)
|
|
ObDereferenceObject(Desktop);
|
|
}
|
|
|
|
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 = IntGetWindowObject(hwndParent)))
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
return NULL;
|
|
}
|
|
|
|
Pt.x = x;
|
|
Pt.y = y;
|
|
|
|
if(Parent->Self != IntGetDesktopWindow())
|
|
{
|
|
Pt.x += Parent->ClientRect.left;
|
|
Pt.y += Parent->ClientRect.top;
|
|
}
|
|
|
|
if(!IntPtInWindow(Parent, Pt.x, Pt.y))
|
|
{
|
|
IntReleaseWindowObject(Parent);
|
|
return NULL;
|
|
}
|
|
|
|
Ret = Parent->Self;
|
|
if((List = IntWinListChildren(Parent)))
|
|
{
|
|
for(phWnd = List; *phWnd; phWnd++)
|
|
{
|
|
PWINDOW_OBJECT Child;
|
|
if((Child = IntGetWindowObject(*phWnd)))
|
|
{
|
|
if(!(Child->Style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE))
|
|
{
|
|
IntReleaseWindowObject(Child);
|
|
continue;
|
|
}
|
|
if((Child->Style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED))
|
|
{
|
|
IntReleaseWindowObject(Child);
|
|
continue;
|
|
}
|
|
if((Child->ExStyle & WS_EX_TRANSPARENT) && (uiFlags & CWP_SKIPTRANSPARENT))
|
|
{
|
|
IntReleaseWindowObject(Child);
|
|
continue;
|
|
}
|
|
if(IntPtInWindow(Child, Pt.x, Pt.y))
|
|
{
|
|
Ret = Child->Self;
|
|
IntReleaseWindowObject(Child);
|
|
break;
|
|
}
|
|
IntReleaseWindowObject(Child);
|
|
}
|
|
}
|
|
ExFreePool(List);
|
|
}
|
|
|
|
IntReleaseWindowObject(Parent);
|
|
return Ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* calculates the default position of a window
|
|
*/
|
|
BOOL FASTCALL
|
|
IntCalcDefPosSize(PWINDOW_OBJECT Parent, PWINDOW_OBJECT WindowObject, 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 WinStaObject;
|
|
PWNDCLASS_OBJECT ClassObject;
|
|
PWINDOW_OBJECT WindowObject;
|
|
PWINDOW_OBJECT ParentWindow, OwnerWindow;
|
|
HWND ParentWindowHandle;
|
|
HWND OwnerWindowHandle;
|
|
PMENU_OBJECT SystemMenu;
|
|
HANDLE Handle;
|
|
POINT Pos;
|
|
SIZE Size;
|
|
#if 0
|
|
POINT MaxSize, MaxPos, MinTrack, MaxTrack;
|
|
#else
|
|
POINT MaxPos;
|
|
#endif
|
|
CREATESTRUCTW Cs;
|
|
CBT_CREATEWNDW CbtCreate;
|
|
LRESULT Result;
|
|
BOOL MenuChanged;
|
|
BOOL ClassFound;
|
|
|
|
BOOL HasOwner;
|
|
|
|
ParentWindowHandle = PsGetWin32Thread()->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)
|
|
ParentWindowHandle = hWndParent;
|
|
else
|
|
OwnerWindowHandle = UserGetAncestor(hWndParent, GA_ROOT);
|
|
}
|
|
else if ((dwStyle & (WS_CHILD | WS_POPUP)) == WS_CHILD)
|
|
{
|
|
return (HWND)0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
|
|
}
|
|
|
|
if (NULL != ParentWindowHandle)
|
|
{
|
|
ParentWindow = IntGetWindowObject(ParentWindowHandle);
|
|
}
|
|
else
|
|
{
|
|
ParentWindow = NULL;
|
|
}
|
|
|
|
/* FIXME: parent must belong to the current process */
|
|
|
|
/* Check the class. */
|
|
ClassFound = ClassReferenceClassByNameOrAtom(&ClassObject, ClassName->Buffer, hInstance);
|
|
if (!ClassFound)
|
|
{
|
|
if (IS_ATOM(ClassName->Buffer))
|
|
{
|
|
DPRINT1("Class 0x%x not found\n", (DWORD_PTR) ClassName->Buffer);
|
|
}
|
|
else
|
|
{
|
|
DPRINT1("Class %wZ not found\n", ClassName);
|
|
}
|
|
if (NULL != ParentWindow)
|
|
{
|
|
IntReleaseWindowObject(ParentWindow);
|
|
}
|
|
SetLastWin32Error(ERROR_CANNOT_FIND_WND_CLASS);
|
|
return((HWND)0);
|
|
}
|
|
|
|
/* Check the window station. */
|
|
if (PsGetWin32Thread()->Desktop == NULL)
|
|
{
|
|
ClassDereferenceObject(ClassObject);
|
|
if (NULL != ParentWindow)
|
|
{
|
|
IntReleaseWindowObject(ParentWindow);
|
|
}
|
|
DPRINT("Thread is not attached to a desktop! Cannot create window!\n");
|
|
return (HWND)0;
|
|
}
|
|
WinStaObject = PsGetWin32Thread()->Desktop->WindowStation;
|
|
ObReferenceObjectByPointer(WinStaObject, KernelMode, ExWindowStationObjectType, 0);
|
|
|
|
/* Create the window object. */
|
|
WindowObject = (PWINDOW_OBJECT)
|
|
ObmCreateObject(PsGetWin32Thread()->Desktop->WindowStation->HandleTable, &Handle,
|
|
otWindow, sizeof(WINDOW_OBJECT) + ClassObject->cbWndExtra
|
|
);
|
|
|
|
DPRINT("Created object with handle %X\n", Handle);
|
|
if (!WindowObject)
|
|
{
|
|
ObDereferenceObject(WinStaObject);
|
|
ClassDereferenceObject(ClassObject);
|
|
if (NULL != ParentWindow)
|
|
{
|
|
IntReleaseWindowObject(ParentWindow);
|
|
}
|
|
SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
|
|
return (HWND)0;
|
|
}
|
|
ObDereferenceObject(WinStaObject);
|
|
|
|
if (NULL == PsGetWin32Thread()->Desktop->DesktopWindow)
|
|
{
|
|
/* If there is no desktop window yet, we must be creating it */
|
|
PsGetWin32Thread()->Desktop->DesktopWindow = Handle;
|
|
}
|
|
|
|
/*
|
|
* Fill out the structure describing it.
|
|
*/
|
|
WindowObject->Class = ClassObject;
|
|
|
|
InsertTailList(&ClassObject->ClassWindowsListHead, &WindowObject->ClassListEntry);
|
|
|
|
WindowObject->ExStyle = dwExStyle;
|
|
WindowObject->Style = dwStyle & ~WS_VISIBLE;
|
|
DPRINT("1: Style is now %lx\n", WindowObject->Style);
|
|
|
|
WindowObject->SystemMenu = (HMENU)0;
|
|
WindowObject->ContextHelpId = 0;
|
|
WindowObject->IDMenu = 0;
|
|
WindowObject->Instance = hInstance;
|
|
WindowObject->Self = Handle;
|
|
if (0 != (dwStyle & WS_CHILD))
|
|
{
|
|
WindowObject->IDMenu = (UINT) hMenu;
|
|
}
|
|
else
|
|
{
|
|
IntSetMenu(WindowObject, hMenu, &MenuChanged);
|
|
}
|
|
WindowObject->MessageQueue = PsGetWin32Thread()->MessageQueue;
|
|
IntReferenceMessageQueue(WindowObject->MessageQueue);
|
|
WindowObject->Parent = (ParentWindow ? ParentWindow->Self : NULL);
|
|
if((OwnerWindow = IntGetWindowObject(OwnerWindowHandle)))
|
|
{
|
|
WindowObject->Owner = OwnerWindowHandle;
|
|
IntReleaseWindowObject(OwnerWindow);
|
|
HasOwner = TRUE;
|
|
} else {
|
|
WindowObject->Owner = NULL;
|
|
HasOwner = FALSE;
|
|
}
|
|
WindowObject->UserData = 0;
|
|
if ((((DWORD)ClassObject->lpfnWndProcA & 0xFFFF0000) != 0xFFFF0000)
|
|
&& (((DWORD)ClassObject->lpfnWndProcW & 0xFFFF0000) != 0xFFFF0000))
|
|
{
|
|
WindowObject->Unicode = bUnicodeWindow;
|
|
}
|
|
else
|
|
{
|
|
WindowObject->Unicode = ClassObject->Unicode;
|
|
}
|
|
WindowObject->WndProcA = ClassObject->lpfnWndProcA;
|
|
WindowObject->WndProcW = ClassObject->lpfnWndProcW;
|
|
WindowObject->OwnerThread = PsGetCurrentThread();
|
|
WindowObject->FirstChild = NULL;
|
|
WindowObject->LastChild = NULL;
|
|
WindowObject->PrevSibling = NULL;
|
|
WindowObject->NextSibling = NULL;
|
|
|
|
/* extra window data */
|
|
if (ClassObject->cbWndExtra != 0)
|
|
{
|
|
WindowObject->ExtraData = (PCHAR)(WindowObject + 1);
|
|
WindowObject->ExtraDataSize = ClassObject->cbWndExtra;
|
|
RtlZeroMemory(WindowObject->ExtraData, WindowObject->ExtraDataSize);
|
|
}
|
|
else
|
|
{
|
|
WindowObject->ExtraData = NULL;
|
|
WindowObject->ExtraDataSize = 0;
|
|
}
|
|
|
|
InitializeListHead(&WindowObject->PropListHead);
|
|
InitializeListHead(&WindowObject->WndObjListHead);
|
|
ExInitializeFastMutex(&WindowObject->WndObjListLock);
|
|
|
|
if (NULL != WindowName->Buffer)
|
|
{
|
|
WindowObject->WindowName.MaximumLength = WindowName->MaximumLength;
|
|
WindowObject->WindowName.Length = WindowName->Length;
|
|
WindowObject->WindowName.Buffer = ExAllocatePoolWithTag(PagedPool, WindowName->MaximumLength,
|
|
TAG_STRING);
|
|
if (NULL == WindowObject->WindowName.Buffer)
|
|
{
|
|
ClassDereferenceObject(ClassObject);
|
|
DPRINT1("Failed to allocate mem for window name\n");
|
|
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
|
|
return NULL;
|
|
}
|
|
RtlCopyMemory(WindowObject->WindowName.Buffer, WindowName->Buffer, WindowName->MaximumLength);
|
|
}
|
|
else
|
|
{
|
|
RtlInitUnicodeString(&WindowObject->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))
|
|
{
|
|
WindowObject->Style |= WS_CLIPSIBLINGS;
|
|
DPRINT("3: Style is now %lx\n", WindowObject->Style);
|
|
if (!(dwStyle & WS_POPUP))
|
|
{
|
|
WindowObject->Style |= WS_CAPTION;
|
|
WindowObject->Flags |= WINDOWOBJECT_NEED_SIZE;
|
|
DPRINT("4: Style is now %lx\n", WindowObject->Style);
|
|
}
|
|
}
|
|
|
|
/* create system menu */
|
|
if((WindowObject->Style & WS_SYSMENU) &&
|
|
(WindowObject->Style & WS_CAPTION) == WS_CAPTION)
|
|
{
|
|
SystemMenu = IntGetSystemMenu(WindowObject, TRUE, TRUE);
|
|
if(SystemMenu)
|
|
{
|
|
WindowObject->SystemMenu = SystemMenu->MenuInfo.Self;
|
|
IntReleaseMenuObject(SystemMenu);
|
|
}
|
|
}
|
|
|
|
/* Insert the window into the thread's window list. */
|
|
InsertTailList (&PsGetWin32Thread()->WindowListHead,
|
|
&WindowObject->ThreadListEntry);
|
|
|
|
/* Allocate a DCE for this window. */
|
|
if (dwStyle & CS_OWNDC)
|
|
{
|
|
WindowObject->Dce = DceAllocDCE(WindowObject->Self, DCE_WINDOW_DC);
|
|
}
|
|
/* FIXME: Handle "CS_CLASSDC" */
|
|
|
|
Pos.x = x;
|
|
Pos.y = y;
|
|
Size.cx = nWidth;
|
|
Size.cy = nHeight;
|
|
|
|
/* call hook */
|
|
Cs.lpCreateParams = lpParam;
|
|
Cs.hInstance = hInstance;
|
|
Cs.hMenu = hMenu;
|
|
Cs.hwndParent = ParentWindowHandle;
|
|
Cs.cx = Size.cx;
|
|
Cs.cy = Size.cy;
|
|
Cs.x = Pos.x;
|
|
Cs.y = Pos.y;
|
|
Cs.style = dwStyle;
|
|
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) Handle, (LPARAM) &CbtCreate))
|
|
{
|
|
if (NULL != ParentWindow)
|
|
{
|
|
IntReleaseWindowObject(ParentWindow);
|
|
}
|
|
|
|
/* FIXME - Delete window object and remove it from the thread windows list */
|
|
/* FIXME - delete allocated DCE */
|
|
|
|
ClassDereferenceObject(ClassObject);
|
|
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(!(WindowObject->Style & (WS_POPUP | WS_CHILD)))
|
|
{
|
|
RECT rc, WorkArea;
|
|
PRTL_USER_PROCESS_PARAMETERS ProcessParams;
|
|
BOOL CalculatedDefPosSize = FALSE;
|
|
|
|
IntGetDesktopWorkArea(WindowObject->OwnerThread->Tcb.Win32Thread->Desktop, &WorkArea);
|
|
|
|
rc = WorkArea;
|
|
ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
|
|
|
|
if(x == CW_USEDEFAULT || x == CW_USEDEFAULT16)
|
|
{
|
|
CalculatedDefPosSize = IntCalcDefPosSize(ParentWindow, WindowObject, &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 */
|
|
if(y != CW_USEDEFAULT && y != CW_USEDEFAULT16)
|
|
{
|
|
dwShowMode = y;
|
|
}
|
|
}
|
|
if(nWidth == CW_USEDEFAULT || nWidth == CW_USEDEFAULT16)
|
|
{
|
|
if(!CalculatedDefPosSize)
|
|
{
|
|
IntCalcDefPosSize(ParentWindow, WindowObject, &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. */
|
|
WindowObject->WindowRect.left = Pos.x;
|
|
WindowObject->WindowRect.top = Pos.y;
|
|
WindowObject->WindowRect.right = Pos.x + Size.cx;
|
|
WindowObject->WindowRect.bottom = Pos.y + Size.cy;
|
|
if (0 != (WindowObject->Style & WS_CHILD) && ParentWindow)
|
|
{
|
|
IntGdiOffsetRect(&(WindowObject->WindowRect), ParentWindow->ClientRect.left,
|
|
ParentWindow->ClientRect.top);
|
|
}
|
|
WindowObject->ClientRect = WindowObject->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(WindowObject, &MaxSize, &MaxPos, &MinTrack,
|
|
&MaxTrack);
|
|
if (MaxSize.x < nWidth) nWidth = MaxSize.x;
|
|
if (MaxSize.y < nHeight) nHeight = MaxSize.y;
|
|
if (nWidth < MinTrack.x ) nWidth = MinTrack.x;
|
|
if (nHeight < MinTrack.y ) nHeight = MinTrack.y;
|
|
if (nWidth < 0) nWidth = 0;
|
|
if (nHeight < 0) nHeight = 0;
|
|
}
|
|
|
|
WindowObject->WindowRect.left = Pos.x;
|
|
WindowObject->WindowRect.top = Pos.y;
|
|
WindowObject->WindowRect.right = Pos.x + Size.cx;
|
|
WindowObject->WindowRect.bottom = Pos.y + Size.cy;
|
|
if (0 != (WindowObject->Style & WS_CHILD) && ParentWindow)
|
|
{
|
|
IntGdiOffsetRect(&(WindowObject->WindowRect), ParentWindow->ClientRect.left,
|
|
ParentWindow->ClientRect.top);
|
|
}
|
|
WindowObject->ClientRect = WindowObject->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, nWidth, nHeight);
|
|
DPRINT("IntCreateWindowEx(): About to send NCCREATE message.\n");
|
|
Result = co_IntSendMessage(WindowObject->Self, WM_NCCREATE, 0, (LPARAM) &Cs);
|
|
if (!Result)
|
|
{
|
|
/* FIXME: Cleanup. */
|
|
if (NULL != ParentWindow)
|
|
{
|
|
IntReleaseWindowObject(ParentWindow);
|
|
}
|
|
DPRINT("IntCreateWindowEx(): NCCREATE message failed.\n");
|
|
return((HWND)0);
|
|
}
|
|
|
|
/* Calculate the non-client size. */
|
|
MaxPos.x = WindowObject->WindowRect.left;
|
|
MaxPos.y = WindowObject->WindowRect.top;
|
|
DPRINT("IntCreateWindowEx(): About to get non-client size.\n");
|
|
/* WinPosGetNonClientSize SENDS THE WM_NCCALCSIZE message */
|
|
Result = co_WinPosGetNonClientSize(WindowObject->Self,
|
|
&WindowObject->WindowRect,
|
|
&WindowObject->ClientRect);
|
|
IntGdiOffsetRect(&WindowObject->WindowRect,
|
|
MaxPos.x - WindowObject->WindowRect.left,
|
|
MaxPos.y - WindowObject->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;
|
|
if((PrevSibling = ParentWindow->LastChild))
|
|
IntReferenceWindowObject(PrevSibling);
|
|
/* link window as bottom sibling */
|
|
IntLinkWindow(WindowObject, ParentWindow, PrevSibling /*prev sibling*/);
|
|
if(PrevSibling)
|
|
IntReleaseWindowObject(PrevSibling);
|
|
}
|
|
else
|
|
{
|
|
/* link window as top sibling (but after topmost siblings) */
|
|
PWINDOW_OBJECT InsertAfter, Sibling;
|
|
if (0 == (dwExStyle & WS_EX_TOPMOST))
|
|
{
|
|
InsertAfter = NULL;
|
|
Sibling = ParentWindow->FirstChild;
|
|
while (NULL != Sibling && 0 != (Sibling->ExStyle & WS_EX_TOPMOST))
|
|
{
|
|
InsertAfter = Sibling;
|
|
Sibling = Sibling->NextSibling;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
InsertAfter = NULL;
|
|
}
|
|
if (NULL != InsertAfter)
|
|
{
|
|
IntReferenceWindowObject(InsertAfter);
|
|
}
|
|
IntLinkWindow(WindowObject, ParentWindow, InsertAfter /* prev sibling */);
|
|
if (NULL != InsertAfter)
|
|
{
|
|
IntReleaseWindowObject(InsertAfter);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Send the WM_CREATE message. */
|
|
DPRINT("IntCreateWindowEx(): about to send CREATE message.\n");
|
|
Result = co_IntSendMessage(WindowObject->Self, WM_CREATE, 0, (LPARAM) &Cs);
|
|
if (Result == (LRESULT)-1)
|
|
{
|
|
/* FIXME: Cleanup. */
|
|
if (NULL != ParentWindow)
|
|
{
|
|
IntReleaseWindowObject(ParentWindow);
|
|
}
|
|
ClassDereferenceObject(ClassObject);
|
|
DPRINT("IntCreateWindowEx(): send CREATE message failed.\n");
|
|
return((HWND)0);
|
|
}
|
|
|
|
/* Send move and size messages. */
|
|
if (!(WindowObject->Flags & WINDOWOBJECT_NEED_SIZE))
|
|
{
|
|
LONG lParam;
|
|
|
|
DPRINT("IntCreateWindow(): About to send WM_SIZE\n");
|
|
|
|
if ((WindowObject->ClientRect.right - WindowObject->ClientRect.left) < 0 ||
|
|
(WindowObject->ClientRect.bottom - WindowObject->ClientRect.top) < 0)
|
|
{
|
|
DPRINT("Sending bogus WM_SIZE\n");
|
|
}
|
|
|
|
lParam = MAKE_LONG(WindowObject->ClientRect.right -
|
|
WindowObject->ClientRect.left,
|
|
WindowObject->ClientRect.bottom -
|
|
WindowObject->ClientRect.top);
|
|
co_IntSendMessage(WindowObject->Self, WM_SIZE, SIZE_RESTORED,
|
|
lParam);
|
|
|
|
DPRINT("IntCreateWindow(): About to send WM_MOVE\n");
|
|
|
|
if (0 != (WindowObject->Style & WS_CHILD) && ParentWindow)
|
|
{
|
|
lParam = MAKE_LONG(WindowObject->ClientRect.left - ParentWindow->ClientRect.left,
|
|
WindowObject->ClientRect.top - ParentWindow->ClientRect.top);
|
|
}
|
|
else
|
|
{
|
|
lParam = MAKE_LONG(WindowObject->ClientRect.left,
|
|
WindowObject->ClientRect.top);
|
|
}
|
|
co_IntSendMessage(WindowObject->Self, WM_MOVE, 0, lParam);
|
|
|
|
/* Call WNDOBJ change procs */
|
|
IntEngWindowChanged(WindowObject, WOC_RGN_CLIENT);
|
|
}
|
|
|
|
/* Show or maybe minimize or maximize the window. */
|
|
if (WindowObject->Style & (WS_MINIMIZE | WS_MAXIMIZE))
|
|
{
|
|
RECT NewPos;
|
|
UINT16 SwFlag;
|
|
|
|
SwFlag = (WindowObject->Style & WS_MINIMIZE) ? SW_MINIMIZE :
|
|
SW_MAXIMIZE;
|
|
co_WinPosMinMaximize(WindowObject, SwFlag, &NewPos);
|
|
SwFlag =
|
|
((WindowObject->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(WindowObject->Self, 0, NewPos.left, NewPos.top,
|
|
NewPos.right, NewPos.bottom, SwFlag);
|
|
}
|
|
|
|
/* Notify the parent window of a new child. */
|
|
if ((WindowObject->Style & WS_CHILD) &&
|
|
(!(WindowObject->ExStyle & WS_EX_NOPARENTNOTIFY)) && ParentWindow)
|
|
{
|
|
DPRINT("IntCreateWindow(): About to notify parent\n");
|
|
co_IntSendMessage(ParentWindow->Self,
|
|
WM_PARENTNOTIFY,
|
|
MAKEWPARAM(WM_CREATE, WindowObject->IDMenu),
|
|
(LPARAM)WindowObject->Self);
|
|
}
|
|
|
|
if ((!hWndParent) && (!HasOwner)) {
|
|
DPRINT("Sending CREATED notify\n");
|
|
co_IntShellHookNotify(HSHELL_WINDOWCREATED, (LPARAM)Handle);
|
|
} else {
|
|
DPRINT("Not sending CREATED notify, %x %d\n", ParentWindow, HasOwner);
|
|
}
|
|
|
|
if (NULL != ParentWindow)
|
|
{
|
|
IntReleaseWindowObject(ParentWindow);
|
|
}
|
|
|
|
/* Initialize and show the window's scrollbars */
|
|
if (WindowObject->Style & WS_VSCROLL)
|
|
{
|
|
co_UserShowScrollBar(WindowObject->Self, SB_VERT, TRUE);
|
|
}
|
|
if (WindowObject->Style & WS_HSCROLL)
|
|
{
|
|
co_UserShowScrollBar(WindowObject->Self, SB_HORZ, TRUE);
|
|
}
|
|
|
|
if (dwStyle & WS_VISIBLE)
|
|
{
|
|
DPRINT("IntCreateWindow(): About to show window\n");
|
|
co_WinPosShowWindow(WindowObject->Self, dwShowMode);
|
|
}
|
|
|
|
DPRINT("IntCreateWindow(): = %X\n", Handle);
|
|
DPRINT("WindowObject->SystemMenu = 0x%x\n", WindowObject->SystemMenu);
|
|
return((HWND)Handle);
|
|
}
|
|
|
|
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)
|
|
{
|
|
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 (! IS_ATOM(ClassName.Buffer))
|
|
{
|
|
Status = IntSafeCopyUnicodeStringTerminateNULL(&ClassName, UnsafeClassName);
|
|
if (! NT_SUCCESS(Status))
|
|
{
|
|
SetLastNtError(Status);
|
|
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;
|
|
|
|
if (Window == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
/* Check for owner thread and desktop window */
|
|
if ((Window->OwnerThread != PsGetCurrentThread()) || IntIsDesktopWindow(Window))
|
|
{
|
|
SetLastWin32Error(ERROR_ACCESS_DENIED);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Look whether the focus is within the tree of windows we will
|
|
* be destroying.
|
|
*/
|
|
if (!co_WinPosShowWindow(Window->Self, SW_HIDE))
|
|
{
|
|
if (UserGetActiveWindow() == Window->Self)
|
|
{
|
|
co_WinPosActivateOtherWindow(Window);
|
|
}
|
|
}
|
|
|
|
if (Window->MessageQueue->ActiveWindow == Window->Self)
|
|
Window->MessageQueue->ActiveWindow = NULL;
|
|
if (Window->MessageQueue->FocusWindow == Window->Self)
|
|
Window->MessageQueue->FocusWindow = NULL;
|
|
if (Window->MessageQueue->CaptureWindow == Window->Self)
|
|
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->Self))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
/* Recursively destroy owned windows */
|
|
if (! isChild)
|
|
{
|
|
for (;;)
|
|
{
|
|
BOOL GotOne = FALSE;
|
|
HWND *Children;
|
|
HWND *ChildHandle;
|
|
PWINDOW_OBJECT Child, Desktop;
|
|
|
|
Desktop = IntGetWindowObject(IntGetDesktopWindow());
|
|
Children = IntWinListChildren(Desktop);
|
|
IntReleaseWindowObject(Desktop);
|
|
if (Children)
|
|
{
|
|
for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
|
|
{
|
|
Child = IntGetWindowObject(*ChildHandle);
|
|
if (Child == NULL)
|
|
continue;
|
|
if (Child->Owner != Window->Self)
|
|
{
|
|
IntReleaseWindowObject(Child);
|
|
continue;
|
|
}
|
|
|
|
if (IntWndBelongsToThread(Child, PsGetWin32Thread()))
|
|
{
|
|
co_UserDestroyWindow(Child);
|
|
IntReleaseWindowObject(Child);
|
|
GotOne = TRUE;
|
|
continue;
|
|
}
|
|
|
|
if (Child->Owner != NULL)
|
|
{
|
|
Child->Owner = NULL;
|
|
}
|
|
|
|
IntReleaseWindowObject(Child);
|
|
}
|
|
ExFreePool(Children);
|
|
}
|
|
if (! GotOne)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!IntIsWindow(Window->Self))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
/* Destroy the window storage */
|
|
co_IntDestroyWindow(Window, PsGetWin32Process(), PsGetWin32Thread(), TRUE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOLEAN STDCALL
|
|
NtUserDestroyWindow(HWND Wnd)
|
|
{
|
|
PWINDOW_OBJECT Window;
|
|
DECLARE_RETURN(BOOLEAN);
|
|
|
|
DPRINT("Enter NtUserDestroyWindow\n");
|
|
UserEnterExclusive();
|
|
|
|
Window = IntGetWindowObject(Wnd);
|
|
if (Window == NULL)
|
|
{
|
|
RETURN(FALSE);
|
|
}
|
|
|
|
RETURN(co_UserDestroyWindow(Window));
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
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 && (WindowName->Length > 0));
|
|
|
|
if((List = IntWinListChildren(Parent)))
|
|
{
|
|
phWnd = List;
|
|
if(ChildAfter)
|
|
{
|
|
/* skip handles before and including ChildAfter */
|
|
while(*phWnd && (*(phWnd++) != ChildAfter->Self));
|
|
}
|
|
|
|
/* search children */
|
|
while(*phWnd)
|
|
{
|
|
PWINDOW_OBJECT Child;
|
|
if(!(Child = IntGetWindowObject(*(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), FALSE)) &&
|
|
(!ClassAtom || Child->Class->Atom == ClassAtom))
|
|
{
|
|
Ret = Child->Self;
|
|
IntReleaseWindowObject(Child);
|
|
break;
|
|
}
|
|
|
|
IntReleaseWindowObject(Child);
|
|
}
|
|
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)
|
|
{
|
|
PWINDOW_OBJECT Parent, ChildAfter;
|
|
UNICODE_STRING ClassName, WindowName;
|
|
NTSTATUS Status;
|
|
HWND Desktop, Ret = NULL;
|
|
RTL_ATOM ClassAtom;
|
|
DECLARE_RETURN(HWND);
|
|
|
|
DPRINT("Enter NtUserFindWindowEx\n");
|
|
UserEnterShared();
|
|
|
|
Desktop = IntGetCurrentThreadDesktopWindow();
|
|
|
|
if(hwndParent == NULL)
|
|
hwndParent = Desktop;
|
|
/* FIXME
|
|
else if(hwndParent == HWND_MESSAGE)
|
|
{
|
|
hwndParent = IntGetMessageWindow();
|
|
}
|
|
*/
|
|
|
|
if(!(Parent = IntGetWindowObject(hwndParent)))
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
RETURN( NULL);
|
|
}
|
|
|
|
ChildAfter = NULL;
|
|
if(hwndChildAfter && !(ChildAfter = IntGetWindowObject(hwndChildAfter)))
|
|
{
|
|
IntReleaseWindowObject(Parent);
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
RETURN( NULL);
|
|
}
|
|
|
|
/* copy the window name */
|
|
Status = IntSafeCopyUnicodeString(&WindowName, ucWindowName);
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
SetLastNtError(Status);
|
|
goto Cleanup3;
|
|
}
|
|
|
|
/* safely copy the class name */
|
|
Status = MmCopyFromCaller(&ClassName, ucClassName, sizeof(UNICODE_STRING));
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
SetLastNtError(Status);
|
|
goto Cleanup2;
|
|
}
|
|
if(ClassName.Length > 0 && ClassName.Buffer)
|
|
{
|
|
WCHAR *buf;
|
|
/* safely copy the class name string (NULL terminated because class-lookup
|
|
depends on it... */
|
|
buf = ExAllocatePoolWithTag(PagedPool, ClassName.Length + sizeof(WCHAR), TAG_STRING);
|
|
if(!buf)
|
|
{
|
|
SetLastWin32Error(STATUS_INSUFFICIENT_RESOURCES);
|
|
goto Cleanup2;
|
|
}
|
|
Status = MmCopyFromCaller(buf, ClassName.Buffer, ClassName.Length);
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
ExFreePool(buf);
|
|
SetLastNtError(Status);
|
|
goto Cleanup2;
|
|
}
|
|
ClassName.Buffer = buf;
|
|
/* make sure the string is null-terminated */
|
|
buf += ClassName.Length / sizeof(WCHAR);
|
|
*buf = L'\0';
|
|
}
|
|
|
|
/* find the class object */
|
|
if(ClassName.Buffer)
|
|
{
|
|
PWINSTATION_OBJECT WinStaObject;
|
|
|
|
if (PsGetWin32Thread()->Desktop == NULL)
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_HANDLE);
|
|
goto Cleanup;
|
|
}
|
|
|
|
WinStaObject = PsGetWin32Thread()->Desktop->WindowStation;
|
|
|
|
Status = RtlLookupAtomInAtomTable(
|
|
WinStaObject->AtomTable,
|
|
ClassName.Buffer,
|
|
&ClassAtom);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failed to lookup class atom!\n");
|
|
SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
if(Parent->Self == Desktop)
|
|
{
|
|
HWND *List, *phWnd;
|
|
PWINDOW_OBJECT TopLevelWindow;
|
|
BOOLEAN CheckWindowName;
|
|
BOOLEAN CheckClassName;
|
|
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->Self));
|
|
}
|
|
|
|
CheckWindowName = WindowName.Length > 0;
|
|
CheckClassName = ClassName.Buffer != NULL;
|
|
|
|
/* search children */
|
|
while(*phWnd)
|
|
{
|
|
if(!(TopLevelWindow = IntGetWindowObject(*(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, FALSE);
|
|
ClassMatches = !CheckClassName ||
|
|
ClassAtom == TopLevelWindow->Class->Atom;
|
|
|
|
if (WindowMatches && ClassMatches)
|
|
{
|
|
Ret = TopLevelWindow->Self;
|
|
IntReleaseWindowObject(TopLevelWindow);
|
|
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->Self;
|
|
IntReleaseWindowObject(TopLevelWindow);
|
|
break;
|
|
}
|
|
|
|
IntReleaseWindowObject(TopLevelWindow);
|
|
}
|
|
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 = IntGetWindowObject(IntGetMessageWindow())))
|
|
{
|
|
Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
|
|
IntReleaseWindowObject(MsgWindows);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
Cleanup:
|
|
if(ClassName.Length > 0 && ClassName.Buffer)
|
|
ExFreePool(ClassName.Buffer);
|
|
|
|
Cleanup2:
|
|
RtlFreeUnicodeString(&WindowName);
|
|
|
|
Cleanup3:
|
|
if(ChildAfter)
|
|
IntReleaseWindowObject(ChildAfter);
|
|
IntReleaseWindowObject(Parent);
|
|
|
|
RETURN( Ret);
|
|
|
|
CLEANUP:
|
|
DPRINT("Leave NtUserFindWindowEx, ret %i\n",_ret_);
|
|
UserLeave();
|
|
END_CLEANUP;
|
|
}
|
|
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
DWORD STDCALL
|
|
NtUserFlashWindowEx(DWORD Unknown0)
|
|
{
|
|
UNIMPLEMENTED
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
HWND FASTCALL UserGetAncestor(HWND hWnd, UINT Type)
|
|
{
|
|
PWINDOW_OBJECT Wnd, WndAncestor, Parent;
|
|
HWND hWndAncestor;
|
|
|
|
if (hWnd == IntGetDesktopWindow())
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (!(Wnd = IntGetWindowObject(hWnd)))
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
return NULL;
|
|
}
|
|
|
|
switch (Type)
|
|
{
|
|
case GA_PARENT:
|
|
{
|
|
WndAncestor = IntGetParentObject(Wnd);
|
|
break;
|
|
}
|
|
|
|
case GA_ROOT:
|
|
{
|
|
PWINDOW_OBJECT tmp;
|
|
WndAncestor = Wnd;
|
|
Parent = NULL;
|
|
|
|
for(;;)
|
|
{
|
|
tmp = Parent;
|
|
if(!(Parent = IntGetParentObject(WndAncestor)))
|
|
{
|
|
break;
|
|
}
|
|
if(IntIsDesktopWindow(Parent))
|
|
{
|
|
IntReleaseWindowObject(Parent);
|
|
break;
|
|
}
|
|
if(tmp)
|
|
IntReleaseWindowObject(tmp);
|
|
WndAncestor = Parent;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case GA_ROOTOWNER:
|
|
{
|
|
WndAncestor = Wnd;
|
|
IntReferenceWindowObject(WndAncestor);
|
|
for (;;)
|
|
{
|
|
PWINDOW_OBJECT Old;
|
|
Old = WndAncestor;
|
|
Parent = IntGetParent(WndAncestor);
|
|
IntReleaseWindowObject(Old);
|
|
if (!Parent)
|
|
{
|
|
break;
|
|
}
|
|
WndAncestor = Parent;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
IntReleaseWindowObject(Wnd);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
hWndAncestor = (WndAncestor ? WndAncestor->Self : NULL);
|
|
IntReleaseWindowObject(Wnd);
|
|
|
|
if(WndAncestor && (WndAncestor != Wnd))
|
|
IntReleaseWindowObject(WndAncestor);
|
|
|
|
return hWndAncestor;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
HWND STDCALL
|
|
NtUserGetAncestor(HWND hWnd, UINT Type)
|
|
{
|
|
DECLARE_RETURN(HWND);
|
|
|
|
DPRINT("Enter NtUserGetAncestor\n");
|
|
UserEnterExclusive();
|
|
|
|
RETURN(UserGetAncestor(hWnd, Type));
|
|
|
|
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 WindowObject;
|
|
RECT SafeRect;
|
|
DECLARE_RETURN(BOOL);
|
|
|
|
DPRINT("Enter NtUserGetClientRect\n");
|
|
UserEnterShared();
|
|
|
|
if(!(WindowObject = IntGetWindowObject(hWnd)))
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
RETURN( FALSE);
|
|
}
|
|
|
|
IntGetClientRect(WindowObject, &SafeRect);
|
|
IntReleaseWindowObject(WindowObject);
|
|
|
|
if(!NT_SUCCESS(MmCopyToCaller(Rect, &SafeRect, sizeof(RECT))))
|
|
{
|
|
RETURN( FALSE);
|
|
}
|
|
RETURN( TRUE);
|
|
|
|
CLEANUP:
|
|
DPRINT("Leave NtUserGetClientRect, 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;
|
|
|
|
IntAcquireWinLockShared();
|
|
|
|
if (!(Wnd = IntGetWindowObject(hWnd)))
|
|
{
|
|
IntReleaseWinLock();
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
return NULL;
|
|
}
|
|
|
|
hWndLastPopup = Wnd->hWndLastPopup;
|
|
|
|
IntReleaseWinLock();
|
|
|
|
return hWndLastPopup;
|
|
#else
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* 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 = IntGetWindowObject(hWnd)))
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
RETURN( NULL);
|
|
}
|
|
|
|
WndParent = IntGetParent(Wnd);
|
|
if (WndParent)
|
|
{
|
|
hWndParent = WndParent->Self;
|
|
IntReleaseWindowObject(WndParent);
|
|
}
|
|
|
|
IntReleaseWindowObject(Wnd);
|
|
|
|
RETURN( hWndParent);
|
|
|
|
CLEANUP:
|
|
DPRINT("Leave NtUserGetParent, ret=%i\n",_ret_);
|
|
UserLeave();
|
|
END_CLEANUP;
|
|
}
|
|
|
|
|
|
|
|
|
|
HWND FASTCALL
|
|
UserSetParent(HWND hWndChild, HWND hWndNewParent)
|
|
{
|
|
PWINDOW_OBJECT Wnd = NULL, WndParent = NULL, WndOldParent;
|
|
HWND hWndOldParent = NULL;
|
|
|
|
if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
|
return( NULL);
|
|
}
|
|
|
|
if (hWndChild == IntGetDesktopWindow())
|
|
{
|
|
SetLastWin32Error(ERROR_ACCESS_DENIED);
|
|
return( NULL);
|
|
}
|
|
|
|
if (hWndNewParent)
|
|
{
|
|
if (!(WndParent = IntGetWindowObject(hWndNewParent)))
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
return( NULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!(WndParent = IntGetWindowObject(IntGetDesktopWindow())))
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
return( NULL);
|
|
}
|
|
}
|
|
|
|
if (!(Wnd = IntGetWindowObject(hWndChild)))
|
|
{
|
|
IntReleaseWindowObject(WndParent);
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
return( NULL);
|
|
}
|
|
|
|
WndOldParent = IntSetParent(Wnd, WndParent);
|
|
|
|
if (WndOldParent)
|
|
{
|
|
hWndOldParent = WndOldParent->Self;
|
|
IntReleaseWindowObject(WndOldParent);
|
|
}
|
|
|
|
IntReleaseWindowObject(Wnd);
|
|
IntReleaseWindowObject(WndParent);
|
|
|
|
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( 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;
|
|
DECLARE_RETURN(BOOL);
|
|
|
|
DPRINT("Enter NtUserSetShellWindowEx\n");
|
|
UserEnterExclusive();
|
|
|
|
NTSTATUS 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);
|
|
}
|
|
|
|
co_WinPosSetWindowPos(hwndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
|
|
|
|
WinStaObject->ShellWindow = hwndShell;
|
|
WinStaObject->ShellListView = hwndListView;
|
|
|
|
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)
|
|
{
|
|
HMENU Result = 0;
|
|
PWINDOW_OBJECT WindowObject;
|
|
PMENU_OBJECT MenuObject;
|
|
DECLARE_RETURN(HMENU);
|
|
|
|
DPRINT("Enter NtUserGetSystemMenu\n");
|
|
UserEnterShared();
|
|
|
|
WindowObject = IntGetWindowObject((HWND)hWnd);
|
|
if (WindowObject == NULL)
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
RETURN( 0);
|
|
}
|
|
|
|
MenuObject = IntGetSystemMenu(WindowObject, bRevert, FALSE);
|
|
if (MenuObject)
|
|
{
|
|
Result = MenuObject->MenuInfo.Self;
|
|
IntReleaseMenuObject(MenuObject);
|
|
}
|
|
|
|
IntReleaseWindowObject(WindowObject);
|
|
RETURN( Result);
|
|
|
|
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 WindowObject;
|
|
PMENU_OBJECT MenuObject;
|
|
DECLARE_RETURN(BOOL);
|
|
|
|
DPRINT("Enter NtUserSetSystemMenu\n");
|
|
UserEnterExclusive();
|
|
|
|
WindowObject = IntGetWindowObject(hWnd);
|
|
if (!WindowObject)
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
RETURN( FALSE);
|
|
}
|
|
|
|
if (hMenu)
|
|
{
|
|
/*
|
|
* Assign new menu handle.
|
|
*/
|
|
MenuObject = IntGetMenuObject(hMenu);
|
|
if (!MenuObject)
|
|
{
|
|
IntReleaseWindowObject(WindowObject);
|
|
SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
|
|
RETURN( FALSE);
|
|
}
|
|
|
|
Result = IntSetSystemMenu(WindowObject, MenuObject);
|
|
|
|
IntReleaseMenuObject(MenuObject);
|
|
}
|
|
|
|
IntReleaseWindowObject(WindowObject);
|
|
|
|
RETURN( Result);
|
|
|
|
CLEANUP:
|
|
DPRINT("Leave NtUserSetSystemMenu, ret=%i\n",_ret_);
|
|
UserLeave();
|
|
END_CLEANUP;
|
|
}
|
|
|
|
|
|
|
|
|
|
HWND FASTCALL
|
|
UserGetWindow(HWND hWnd, UINT Relationship)
|
|
{
|
|
PWINDOW_OBJECT Parent, WindowObject;
|
|
HWND hWndResult = NULL;
|
|
|
|
if (!(WindowObject = IntGetWindowObject(hWnd))) return NULL;
|
|
|
|
switch (Relationship)
|
|
{
|
|
case GW_HWNDFIRST:
|
|
if((Parent = IntGetParentObject(WindowObject)))
|
|
{
|
|
if (Parent->FirstChild)
|
|
hWndResult = Parent->FirstChild->Self;
|
|
|
|
IntReleaseWindowObject(Parent);
|
|
}
|
|
break;
|
|
|
|
case GW_HWNDLAST:
|
|
if((Parent = IntGetParentObject(WindowObject)))
|
|
{
|
|
if (Parent->LastChild)
|
|
hWndResult = Parent->LastChild->Self;
|
|
|
|
IntReleaseWindowObject(Parent);
|
|
}
|
|
break;
|
|
|
|
case GW_HWNDNEXT:
|
|
if (WindowObject->NextSibling)
|
|
hWndResult = WindowObject->NextSibling->Self;
|
|
break;
|
|
|
|
case GW_HWNDPREV:
|
|
if (WindowObject->PrevSibling)
|
|
hWndResult = WindowObject->PrevSibling->Self;
|
|
break;
|
|
|
|
case GW_OWNER:
|
|
if((Parent = IntGetWindowObject(WindowObject->Owner)))
|
|
{
|
|
hWndResult = Parent->Self;
|
|
IntReleaseWindowObject(Parent);
|
|
}
|
|
break;
|
|
case GW_CHILD:
|
|
if (WindowObject->FirstChild)
|
|
hWndResult = WindowObject->FirstChild->Self;
|
|
break;
|
|
}
|
|
|
|
IntReleaseWindowObject(WindowObject);
|
|
|
|
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 WindowObject, Parent;
|
|
LONG Result = 0;
|
|
|
|
DPRINT("NtUserGetWindowLong(%x,%d,%d)\n", hWnd, (INT)Index, Ansi);
|
|
|
|
WindowObject = IntGetWindowObject(hWnd);
|
|
if (WindowObject == NULL)
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* WndProc is only available to the owner process
|
|
*/
|
|
if (GWL_WNDPROC == Index
|
|
&& WindowObject->OwnerThread->ThreadsProcess != PsGetCurrentProcess())
|
|
{
|
|
SetLastWin32Error(ERROR_ACCESS_DENIED);
|
|
return 0;
|
|
}
|
|
|
|
if ((INT)Index >= 0)
|
|
{
|
|
if ((Index + sizeof(LONG)) > WindowObject->ExtraDataSize)
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
Result = *((LONG *)(WindowObject->ExtraData + Index));
|
|
}
|
|
else
|
|
{
|
|
switch (Index)
|
|
{
|
|
case GWL_EXSTYLE:
|
|
Result = WindowObject->ExStyle;
|
|
break;
|
|
|
|
case GWL_STYLE:
|
|
Result = WindowObject->Style;
|
|
break;
|
|
|
|
case GWL_WNDPROC:
|
|
if (Ansi)
|
|
Result = (LONG) WindowObject->WndProcA;
|
|
else
|
|
Result = (LONG) WindowObject->WndProcW;
|
|
break;
|
|
|
|
case GWL_HINSTANCE:
|
|
Result = (LONG) WindowObject->Instance;
|
|
break;
|
|
|
|
case GWL_HWNDPARENT:
|
|
Parent = IntGetWindowObject(WindowObject->Parent);
|
|
if(Parent)
|
|
{
|
|
if (Parent && Parent->Self == IntGetDesktopWindow())
|
|
Result = (LONG) UserGetWindow(WindowObject->Self, GW_OWNER);
|
|
else
|
|
Result = (LONG) Parent->Self;
|
|
IntReleaseWindowObject(Parent);
|
|
}
|
|
break;
|
|
|
|
case GWL_ID:
|
|
Result = (LONG) WindowObject->IDMenu;
|
|
break;
|
|
|
|
case GWL_USERDATA:
|
|
Result = WindowObject->UserData;
|
|
break;
|
|
|
|
default:
|
|
DPRINT1("NtUserGetWindowLong(): Unsupported index %d\n", Index);
|
|
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
|
Result = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
IntReleaseWindowObject(WindowObject);
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
|
|
LONG FASTCALL
|
|
UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
|
|
{
|
|
PWINDOW_OBJECT WindowObject, Parent;
|
|
PWINSTATION_OBJECT WindowStation;
|
|
LONG OldValue;
|
|
STYLESTRUCT Style;
|
|
|
|
if (hWnd == IntGetDesktopWindow())
|
|
{
|
|
SetLastWin32Error(STATUS_ACCESS_DENIED);
|
|
return( 0);
|
|
}
|
|
|
|
WindowObject = IntGetWindowObject(hWnd);
|
|
if (WindowObject == NULL)
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
return( 0);
|
|
}
|
|
|
|
if ((INT)Index >= 0)
|
|
{
|
|
if ((Index + sizeof(LONG)) > WindowObject->ExtraDataSize)
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
|
IntReleaseWindowObject(WindowObject);
|
|
return( 0);
|
|
}
|
|
OldValue = *((LONG *)(WindowObject->ExtraData + Index));
|
|
*((LONG *)(WindowObject->ExtraData + Index)) = NewValue;
|
|
}
|
|
else
|
|
{
|
|
switch (Index)
|
|
{
|
|
case GWL_EXSTYLE:
|
|
OldValue = (LONG) WindowObject->ExStyle;
|
|
Style.styleOld = OldValue;
|
|
Style.styleNew = NewValue;
|
|
|
|
/*
|
|
* Remove extended window style bit WS_EX_TOPMOST for shell windows.
|
|
*/
|
|
WindowStation = WindowObject->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);
|
|
WindowObject->ExStyle = (DWORD)Style.styleNew;
|
|
co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
|
|
break;
|
|
|
|
case GWL_STYLE:
|
|
OldValue = (LONG) WindowObject->Style;
|
|
Style.styleOld = OldValue;
|
|
Style.styleNew = NewValue;
|
|
co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
|
|
WindowObject->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 */
|
|
if (Ansi)
|
|
{
|
|
OldValue = (LONG) WindowObject->WndProcA;
|
|
WindowObject->WndProcA = (WNDPROC) NewValue;
|
|
WindowObject->WndProcW = (WNDPROC) IntAddWndProcHandle((WNDPROC)NewValue,FALSE);
|
|
WindowObject->Unicode = FALSE;
|
|
}
|
|
else
|
|
{
|
|
OldValue = (LONG) WindowObject->WndProcW;
|
|
WindowObject->WndProcW = (WNDPROC) NewValue;
|
|
WindowObject->WndProcA = (WNDPROC) IntAddWndProcHandle((WNDPROC)NewValue,TRUE);
|
|
WindowObject->Unicode = TRUE;
|
|
}
|
|
break;
|
|
|
|
case GWL_HINSTANCE:
|
|
OldValue = (LONG) WindowObject->Instance;
|
|
WindowObject->Instance = (HINSTANCE) NewValue;
|
|
break;
|
|
|
|
case GWL_HWNDPARENT:
|
|
Parent = IntGetParentObject(WindowObject);
|
|
if (Parent && (Parent->Self == IntGetDesktopWindow()))
|
|
OldValue = (LONG) IntSetOwner(WindowObject->Self, (HWND) NewValue);
|
|
else
|
|
OldValue = (LONG) UserSetParent(WindowObject->Self, (HWND) NewValue);
|
|
if(Parent)
|
|
IntReleaseWindowObject(Parent);
|
|
break;
|
|
|
|
case GWL_ID:
|
|
OldValue = (LONG) WindowObject->IDMenu;
|
|
WindowObject->IDMenu = (UINT) NewValue;
|
|
break;
|
|
|
|
case GWL_USERDATA:
|
|
OldValue = WindowObject->UserData;
|
|
WindowObject->UserData = NewValue;
|
|
break;
|
|
|
|
default:
|
|
DPRINT1("NtUserSetWindowLong(): Unsupported index %d\n", Index);
|
|
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
|
OldValue = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
IntReleaseWindowObject(WindowObject);
|
|
|
|
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( 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 WindowObject;
|
|
WORD OldValue;
|
|
DECLARE_RETURN(WORD);
|
|
|
|
DPRINT("Enter NtUserSetWindowWord\n");
|
|
UserEnterExclusive();
|
|
|
|
switch (Index)
|
|
{
|
|
case GWL_ID:
|
|
case GWL_HINSTANCE:
|
|
case GWL_HWNDPARENT:
|
|
RETURN( UserSetWindowLong(hWnd, Index, (UINT)NewValue, TRUE));
|
|
default:
|
|
if (Index < 0)
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_INDEX);
|
|
RETURN( 0);
|
|
}
|
|
}
|
|
|
|
WindowObject = IntGetWindowObject(hWnd);
|
|
if (WindowObject == NULL)
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
RETURN( 0);
|
|
}
|
|
|
|
if (Index > WindowObject->ExtraDataSize - sizeof(WORD))
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
|
IntReleaseWindowObject(WindowObject);
|
|
RETURN( 0);
|
|
}
|
|
|
|
OldValue = *((WORD *)(WindowObject->ExtraData + Index));
|
|
*((WORD *)(WindowObject->ExtraData + Index)) = NewValue;
|
|
|
|
IntReleaseWindowObject(WindowObject);
|
|
|
|
RETURN( OldValue);
|
|
|
|
CLEANUP:
|
|
DPRINT("Leave NtUserSetWindowWord, ret=%i\n",_ret_);
|
|
UserLeave();
|
|
END_CLEANUP;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL STDCALL
|
|
NtUserGetWindowPlacement(HWND hWnd,
|
|
WINDOWPLACEMENT *lpwndpl)
|
|
{
|
|
PWINDOW_OBJECT WindowObject;
|
|
PINTERNALPOS InternalPos;
|
|
POINT Size;
|
|
WINDOWPLACEMENT Safepl;
|
|
NTSTATUS Status;
|
|
DECLARE_RETURN(BOOL);
|
|
|
|
DPRINT("Enter NtUserGetWindowPlacement\n");
|
|
UserEnterShared();
|
|
|
|
WindowObject = IntGetWindowObject(hWnd);
|
|
if (WindowObject == NULL)
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
RETURN( FALSE);
|
|
}
|
|
|
|
Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
SetLastNtError(Status);
|
|
IntReleaseWindowObject(WindowObject);
|
|
RETURN( FALSE);
|
|
}
|
|
if(Safepl.length != sizeof(WINDOWPLACEMENT))
|
|
{
|
|
IntReleaseWindowObject(WindowObject);
|
|
RETURN( FALSE);
|
|
}
|
|
|
|
Safepl.flags = 0;
|
|
Safepl.showCmd = ((WindowObject->Flags & WINDOWOBJECT_RESTOREMAX) ? SW_MAXIMIZE : SW_SHOWNORMAL);
|
|
|
|
Size.x = WindowObject->WindowRect.left;
|
|
Size.y = WindowObject->WindowRect.top;
|
|
InternalPos = WinPosInitInternalPos(WindowObject, &Size,
|
|
&WindowObject->WindowRect);
|
|
if (InternalPos)
|
|
{
|
|
Safepl.rcNormalPosition = InternalPos->NormalRect;
|
|
Safepl.ptMinPosition = InternalPos->IconPos;
|
|
Safepl.ptMaxPosition = InternalPos->MaxPos;
|
|
}
|
|
else
|
|
{
|
|
IntReleaseWindowObject(WindowObject);
|
|
RETURN( FALSE);
|
|
}
|
|
|
|
Status = MmCopyToCaller(lpwndpl, &Safepl, sizeof(WINDOWPLACEMENT));
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
SetLastNtError(Status);
|
|
IntReleaseWindowObject(WindowObject);
|
|
RETURN( FALSE);
|
|
}
|
|
|
|
IntReleaseWindowObject(WindowObject);
|
|
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 = IntGetWindowObject(hWnd)))
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
RETURN(FALSE);
|
|
}
|
|
Status = MmCopyToCaller(Rect, &Wnd->WindowRect, sizeof(RECT));
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
IntReleaseWindowObject(Wnd);
|
|
SetLastNtError(Status);
|
|
RETURN( FALSE);
|
|
}
|
|
|
|
IntReleaseWindowObject(Wnd);
|
|
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 = IntGetWindowObject(hWnd)))
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
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 = IntGetWindowObject(hWnd);
|
|
DWORD Result;
|
|
DECLARE_RETURN(UINT);
|
|
|
|
DPRINT("Enter NtUserQueryWindow\n");
|
|
UserEnterShared();
|
|
|
|
if (Window == NULL)
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
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;
|
|
}
|
|
|
|
IntReleaseWindowObject(Window);
|
|
|
|
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 Wnd,
|
|
HMENU Menu,
|
|
BOOL Repaint)
|
|
{
|
|
PWINDOW_OBJECT WindowObject;
|
|
BOOL Changed;
|
|
DECLARE_RETURN(BOOL);
|
|
|
|
DPRINT("Enter NtUserSetMenu\n");
|
|
UserEnterExclusive();
|
|
|
|
WindowObject = IntGetWindowObject((HWND) Wnd);
|
|
if (NULL == WindowObject)
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
RETURN( FALSE);
|
|
}
|
|
|
|
if (! IntSetMenu(WindowObject, Menu, &Changed))
|
|
{
|
|
IntReleaseWindowObject(WindowObject);
|
|
RETURN( FALSE);
|
|
}
|
|
|
|
IntReleaseWindowObject(WindowObject);
|
|
|
|
if (Changed && Repaint)
|
|
{
|
|
co_WinPosSetWindowPos(Wnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
|
|
SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
|
|
}
|
|
|
|
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 WindowObject;
|
|
WINDOWPLACEMENT Safepl;
|
|
NTSTATUS Status;
|
|
DECLARE_RETURN(BOOL);
|
|
|
|
DPRINT("Enter NtUserSetWindowPlacement\n");
|
|
UserEnterExclusive();
|
|
|
|
WindowObject = IntGetWindowObject(hWnd);
|
|
if (WindowObject == NULL)
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
RETURN( FALSE);
|
|
}
|
|
Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
SetLastNtError(Status);
|
|
IntReleaseWindowObject(WindowObject);
|
|
RETURN( FALSE);
|
|
}
|
|
if(Safepl.length != sizeof(WINDOWPLACEMENT))
|
|
{
|
|
IntReleaseWindowObject(WindowObject);
|
|
RETURN( FALSE);
|
|
}
|
|
|
|
if ((WindowObject->Style & (WS_MAXIMIZE | WS_MINIMIZE)) == 0)
|
|
{
|
|
co_WinPosSetWindowPos(WindowObject->Self, 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(WindowObject->Self, Safepl.showCmd);
|
|
|
|
if (WindowObject->InternalPos == NULL)
|
|
WindowObject->InternalPos = ExAllocatePoolWithTag(PagedPool, sizeof(INTERNALPOS), TAG_WININTLIST);
|
|
WindowObject->InternalPos->NormalRect = Safepl.rcNormalPosition;
|
|
WindowObject->InternalPos->IconPos = Safepl.ptMinPosition;
|
|
WindowObject->InternalPos->MaxPos = Safepl.ptMaxPosition;
|
|
|
|
IntReleaseWindowObject(WindowObject);
|
|
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);
|
|
|
|
DPRINT("Enter NtUserSetWindowPos\n");
|
|
UserEnterExclusive();
|
|
|
|
RETURN( co_WinPosSetWindowPos(hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags));
|
|
|
|
CLEANUP:
|
|
DPRINT("Leave NtUserSetWindowPos, ret=%i\n",_ret_);
|
|
UserLeave();
|
|
END_CLEANUP;
|
|
}
|
|
|
|
|
|
INT FASTCALL
|
|
IntGetWindowRgn(HWND hWnd, HRGN hRgn)
|
|
{
|
|
INT Ret;
|
|
PWINDOW_OBJECT WindowObject;
|
|
HRGN VisRgn;
|
|
ROSRGNDATA *pRgn;
|
|
|
|
if(!(WindowObject = IntGetWindowObject(hWnd)))
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
return ERROR;
|
|
}
|
|
if(!hRgn)
|
|
{
|
|
IntReleaseWindowObject(WindowObject);
|
|
return ERROR;
|
|
}
|
|
|
|
/* Create a new window region using the window rectangle */
|
|
VisRgn = UnsafeIntCreateRectRgnIndirect(&WindowObject->WindowRect);
|
|
NtGdiOffsetRgn(VisRgn, -WindowObject->WindowRect.left, -WindowObject->WindowRect.top);
|
|
/* if there's a region assigned to the window, combine them both */
|
|
if(WindowObject->WindowRegion && !(WindowObject->Style & WS_MINIMIZE))
|
|
NtGdiCombineRgn(VisRgn, VisRgn, WindowObject->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);
|
|
|
|
IntReleaseWindowObject(WindowObject);
|
|
return Ret;
|
|
}
|
|
|
|
INT FASTCALL
|
|
IntGetWindowRgnBox(HWND hWnd, RECT *Rect)
|
|
{
|
|
INT Ret;
|
|
PWINDOW_OBJECT WindowObject;
|
|
HRGN VisRgn;
|
|
ROSRGNDATA *pRgn;
|
|
|
|
if(!(WindowObject = IntGetWindowObject(hWnd)))
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
return ERROR;
|
|
}
|
|
if(!Rect)
|
|
{
|
|
IntReleaseWindowObject(WindowObject);
|
|
return ERROR;
|
|
}
|
|
|
|
/* Create a new window region using the window rectangle */
|
|
VisRgn = UnsafeIntCreateRectRgnIndirect(&WindowObject->WindowRect);
|
|
NtGdiOffsetRgn(VisRgn, -WindowObject->WindowRect.left, -WindowObject->WindowRect.top);
|
|
/* if there's a region assigned to the window, combine them both */
|
|
if(WindowObject->WindowRegion && !(WindowObject->Style & WS_MINIMIZE))
|
|
NtGdiCombineRgn(VisRgn, VisRgn, WindowObject->WindowRegion, RGN_AND);
|
|
|
|
if((pRgn = RGNDATA_LockRgn(VisRgn)))
|
|
{
|
|
Ret = pRgn->rdh.iType;
|
|
*Rect = pRgn->rdh.rcBound;
|
|
RGNDATA_UnlockRgn(pRgn);
|
|
}
|
|
else
|
|
Ret = ERROR;
|
|
|
|
NtGdiDeleteObject(VisRgn);
|
|
|
|
IntReleaseWindowObject(WindowObject);
|
|
return Ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
INT STDCALL
|
|
NtUserSetWindowRgn(
|
|
HWND hWnd,
|
|
HRGN hRgn,
|
|
BOOL bRedraw)
|
|
{
|
|
PWINDOW_OBJECT WindowObject;
|
|
DECLARE_RETURN(INT);
|
|
|
|
DPRINT("Enter NtUserSetWindowRgn\n");
|
|
UserEnterExclusive();
|
|
|
|
WindowObject = IntGetWindowObject(hWnd);
|
|
if (WindowObject == NULL)
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
RETURN( 0);
|
|
}
|
|
|
|
/* FIXME - Verify if hRgn is a valid handle!!!!
|
|
Propably make this operation thread-safe, but maybe it's not necessary */
|
|
|
|
if(WindowObject->WindowRegion)
|
|
{
|
|
/* Delete no longer needed region handle */
|
|
NtGdiDeleteObject(WindowObject->WindowRegion);
|
|
}
|
|
WindowObject->WindowRegion = hRgn;
|
|
|
|
/* FIXME - send WM_WINDOWPOSCHANGING and WM_WINDOWPOSCHANGED messages to the window */
|
|
|
|
if(bRedraw)
|
|
{
|
|
co_UserRedrawWindow(WindowObject, NULL, NULL, RDW_INVALIDATE);
|
|
}
|
|
|
|
IntReleaseWindowObject(WindowObject);
|
|
RETURN( (INT)hRgn);
|
|
|
|
CLEANUP:
|
|
DPRINT("Leave NtUserSystemParametersInfo, ret=%i\n",_ret_);
|
|
UserLeave();
|
|
END_CLEANUP;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL STDCALL
|
|
NtUserShowWindow(HWND hWnd,
|
|
LONG nCmdShow)
|
|
{
|
|
DECLARE_RETURN(BOOL);
|
|
|
|
DPRINT("Enter NtUserShowWindow\n");
|
|
UserEnterExclusive();
|
|
|
|
RETURN( co_WinPosShowWindow(hWnd, nCmdShow));
|
|
|
|
CLEANUP:
|
|
DPRINT("Leave NtUserShowWindow, ret=%i\n",_ret_);
|
|
UserLeave();
|
|
END_CLEANUP;
|
|
}
|
|
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
DWORD STDCALL
|
|
NtUserShowWindowAsync(DWORD Unknown0,
|
|
DWORD Unknown1)
|
|
{
|
|
UNIMPLEMENTED
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* @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
|
|
*/
|
|
VOID STDCALL
|
|
NtUserValidateRect(HWND hWnd, const RECT* Rect)
|
|
{
|
|
return (VOID)NtUserRedrawWindow(hWnd, Rect, 0, RDW_VALIDATE | RDW_NOCHILDREN);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
HWND STDCALL
|
|
NtUserWindowFromPoint(LONG X, LONG Y)
|
|
{
|
|
POINT pt;
|
|
HWND Ret;
|
|
PWINDOW_OBJECT DesktopWindow, Window = NULL;
|
|
DECLARE_RETURN(HWND);
|
|
|
|
DPRINT("Enter NtUserWindowFromPoint\n");
|
|
UserEnterExclusive();
|
|
|
|
if ((DesktopWindow = IntGetWindowObject(IntGetDesktopWindow())))
|
|
{
|
|
USHORT Hit;
|
|
|
|
pt.x = X;
|
|
pt.y = Y;
|
|
|
|
Hit = co_WinPosWindowFromPoint(DesktopWindow, PsGetWin32Thread()->MessageQueue, &pt, &Window);
|
|
|
|
if(Window)
|
|
{
|
|
Ret = Window->Self;
|
|
IntReleaseWindowObject(Window);
|
|
IntReleaseWindowObject(DesktopWindow);
|
|
RETURN( Ret);
|
|
}
|
|
|
|
IntReleaseWindowObject(DesktopWindow);
|
|
}
|
|
|
|
RETURN( NULL);
|
|
|
|
CLEANUP:
|
|
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 WindowHandle, PUNICODE_STRING WindowText)
|
|
{
|
|
PWINDOW_OBJECT WindowObject, Parent, Owner;
|
|
UNICODE_STRING SafeText;
|
|
NTSTATUS Status;
|
|
DECLARE_RETURN(INT);
|
|
|
|
DPRINT("Enter NtUserDefSetText\n");
|
|
UserEnterExclusive();
|
|
|
|
WindowObject = IntGetWindowObject(WindowHandle);
|
|
if(!WindowObject)
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
RETURN( FALSE);
|
|
}
|
|
|
|
if(WindowText)
|
|
{
|
|
Status = IntSafeCopyUnicodeString(&SafeText, WindowText);
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
SetLastNtError(Status);
|
|
IntReleaseWindowObject(WindowObject);
|
|
RETURN( FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RtlInitUnicodeString(&SafeText, NULL);
|
|
}
|
|
|
|
/* FIXME - do this thread-safe! otherwise one could crash here! */
|
|
RtlFreeUnicodeString(&WindowObject->WindowName);
|
|
|
|
WindowObject->WindowName = SafeText;
|
|
|
|
/* Send shell notifications */
|
|
|
|
Owner = IntGetOwner(WindowObject);
|
|
Parent = IntGetParent(WindowObject);
|
|
|
|
if ((!Owner) && (!Parent))
|
|
{
|
|
co_IntShellHookNotify(HSHELL_REDRAW, (LPARAM) WindowHandle);
|
|
}
|
|
|
|
if (Owner)
|
|
{
|
|
IntReleaseWindowObject(Owner);
|
|
}
|
|
|
|
if (Parent)
|
|
{
|
|
IntReleaseWindowObject(Parent);
|
|
}
|
|
|
|
IntReleaseWindowObject(WindowObject);
|
|
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 WindowObject;
|
|
NTSTATUS Status;
|
|
INT Result;
|
|
DECLARE_RETURN(INT);
|
|
|
|
DPRINT("Enter NtUserInternalGetWindowText\n");
|
|
UserEnterShared();
|
|
|
|
if(lpString && (nMaxCount <= 1))
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
|
RETURN( 0);
|
|
}
|
|
|
|
WindowObject = IntGetWindowObject(hWnd);
|
|
if(!WindowObject)
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
RETURN( 0);
|
|
}
|
|
|
|
/* FIXME - do this thread-safe! otherwise one could crash here! */
|
|
Result = WindowObject->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, WindowObject->WindowName.Buffer, Copy * sizeof(WCHAR));
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
SetLastNtError(Status);
|
|
IntReleaseWindowObject(WindowObject);
|
|
RETURN( 0);
|
|
}
|
|
Buffer += Copy;
|
|
}
|
|
|
|
Status = MmCopyToCaller(Buffer, &Terminator, sizeof(WCHAR));
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
SetLastNtError(Status);
|
|
IntReleaseWindowObject(WindowObject);
|
|
RETURN( 0);
|
|
}
|
|
|
|
Result = Copy;
|
|
}
|
|
|
|
IntReleaseWindowObject(WindowObject);
|
|
RETURN( Result);
|
|
|
|
CLEANUP:
|
|
DPRINT("Leave NtUserInternalGetWindowText, ret=%i\n",_ret_);
|
|
UserLeave();
|
|
END_CLEANUP;
|
|
}
|
|
|
|
DWORD STDCALL
|
|
NtUserDereferenceWndProcHandle(WNDPROC wpHandle, WndProcHandle *Data)
|
|
{
|
|
DECLARE_RETURN(DWORD);
|
|
|
|
DPRINT("Enter NtUserDereferenceWndProcHandle\n");
|
|
UserEnterShared();
|
|
|
|
WndProcHandle Entry;
|
|
if (((DWORD)wpHandle & 0xFFFF0000) == 0xFFFF0000)
|
|
{
|
|
Entry = WndProcHandlesArray[(DWORD)wpHandle & 0x0000FFFF];
|
|
Data->WindowProc = Entry.WindowProc;
|
|
Data->IsUnicode = Entry.IsUnicode;
|
|
Data->ProcessID = Entry.ProcessID;
|
|
RETURN( TRUE);
|
|
} else {
|
|
RETURN( FALSE);
|
|
}
|
|
RETURN( FALSE);
|
|
|
|
CLEANUP:
|
|
DPRINT("Leave NtUserDereferenceWndProcHandle, ret=%i\n",_ret_);
|
|
UserLeave();
|
|
END_CLEANUP;
|
|
}
|
|
|
|
DWORD
|
|
IntAddWndProcHandle(WNDPROC WindowProc, BOOL IsUnicode)
|
|
{
|
|
WORD i;
|
|
WORD FreeSpot = 0;
|
|
BOOL found;
|
|
WndProcHandle *OldArray;
|
|
WORD OldArraySize;
|
|
found = FALSE;
|
|
for (i = 0;i < WndProcHandlesArraySize;i++)
|
|
{
|
|
if (WndProcHandlesArray[i].WindowProc == NULL)
|
|
{
|
|
FreeSpot = i;
|
|
found = TRUE;
|
|
}
|
|
}
|
|
if (!found)
|
|
{
|
|
OldArray = WndProcHandlesArray;
|
|
OldArraySize = WndProcHandlesArraySize;
|
|
WndProcHandlesArray = ExAllocatePoolWithTag(PagedPool,(OldArraySize + WPH_SIZE) * sizeof(WndProcHandle), TAG_WINPROCLST);
|
|
WndProcHandlesArraySize = OldArraySize + WPH_SIZE;
|
|
RtlCopyMemory(WndProcHandlesArray,OldArray,OldArraySize * sizeof(WndProcHandle));
|
|
ExFreePool(OldArray);
|
|
FreeSpot = OldArraySize + 1;
|
|
}
|
|
WndProcHandlesArray[FreeSpot].WindowProc = WindowProc;
|
|
WndProcHandlesArray[FreeSpot].IsUnicode = IsUnicode;
|
|
WndProcHandlesArray[FreeSpot].ProcessID = PsGetCurrentProcessId();
|
|
return FreeSpot + 0xFFFF0000;
|
|
}
|
|
|
|
DWORD
|
|
IntRemoveWndProcHandle(WNDPROC Handle)
|
|
{
|
|
WORD position;
|
|
position = (DWORD)Handle & 0x0000FFFF;
|
|
if (position > WndProcHandlesArraySize)
|
|
{
|
|
return FALSE;
|
|
}
|
|
WndProcHandlesArray[position].WindowProc = NULL;
|
|
WndProcHandlesArray[position].IsUnicode = FALSE;
|
|
WndProcHandlesArray[position].ProcessID = NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD
|
|
IntRemoveProcessWndProcHandles(HANDLE ProcessID)
|
|
{
|
|
WORD i;
|
|
for (i = 0;i < WndProcHandlesArraySize;i++)
|
|
{
|
|
if (WndProcHandlesArray[i].ProcessID == ProcessID)
|
|
{
|
|
WndProcHandlesArray[i].WindowProc = NULL;
|
|
WndProcHandlesArray[i].IsUnicode = FALSE;
|
|
WndProcHandlesArray[i].ProcessID = NULL;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
#define WIN_NEEDS_SHOW_OWNEDPOPUP (0x00000040)
|
|
|
|
BOOL
|
|
FASTCALL
|
|
IntShowOwnedPopups( HWND owner, BOOL fShow )
|
|
{
|
|
int count = 0;
|
|
PWINDOW_OBJECT Window, pWnd;
|
|
HWND *win_array;
|
|
|
|
if(!(Window = IntGetWindowObject(owner)))
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
win_array = IntWinListChildren( Window);
|
|
IntReleaseWindowObject(Window);
|
|
|
|
if (!win_array) return TRUE;
|
|
|
|
while (win_array[count]) count++;
|
|
while (--count >= 0)
|
|
{
|
|
if (UserGetWindow( win_array[count], GW_OWNER ) != owner) continue;
|
|
if (!(pWnd = IntGetWindowObject( win_array[count] ))) continue;
|
|
// if (pWnd == WND_OTHER_PROCESS) continue;
|
|
|
|
if (fShow)
|
|
{
|
|
if (pWnd->Flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
|
|
{
|
|
IntReleaseWindowObject( pWnd );
|
|
/* 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)
|
|
{
|
|
IntReleaseWindowObject( pWnd );
|
|
/* 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;
|
|
}
|
|
}
|
|
IntReleaseWindowObject( pWnd );
|
|
}
|
|
ExFreePool( win_array );
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* EOF */
|