reactos/win32ss/user/user32/windows/window.c
jimtabor b784074c2f [0.4.13][WIN32SS][RTL] Fix regression CORE-16769 + BSOD CORE-13907 & CORE-14857
Thanks to Jim Tabor, Mark Jansen & Thomas Faber
By squashed backmerge of the following commits:
--------------
[NTUSER] Fix Strings and Format to Hooks

Allocate heap instead of data segment to be used for callbacks on user side.
Move and correct initial hook call out setup. Use it in more than one hook call.

This fixes issues with strings out of alignment and use of kernel pointers.

See CORE-13907 and CORE-16769. KsStudio still needs retested.

Small wow update.

cherry picked from commit 0.4.14-dev-1287-g
568b6d0558
--------------
[RTL] Introduce RtlpImageNtHeader,
which implements the required functionality.
ntdll and ntoskrnl now have a wrapper for this, with SEH.
This protects the function against malformed / bad images,
whilst still being able to use the code in freeldr et al.
Idea from Thomas.
CORE-14857

cherry picked from commit 0.4.14-dev-1255-g
177ae91bf6
--------------
[WIN32SS] Form Sanity to Hook Callbacks

Fix WH_CALLWNDPROC/RET data to user hook calls. See CORE-13019 and CORE-13907.

cherry picked from commit 0.4.14-dev-1241-g
915a5764a9
--------------
[USER32] Fix null return.

See CORE-16769.

cherry picked from commit 0.4.14-dev-1240-g
d8add40e89
2020-04-03 14:51:10 +02:00

2048 lines
46 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS user32.dll
* FILE: win32ss/user/user32/windows/window.c
* PURPOSE: Window management
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
* Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
* UPDATE HISTORY:
* 06-06-2001 CSH Created
*/
#define DEBUG
#include <user32.h>
WINE_DEFAULT_DEBUG_CHANNEL(user32);
void MDI_CalcDefaultChildPos( HWND hwndClient, INT total, LPPOINT lpPos, INT delta, UINT *id );
extern LPCWSTR FASTCALL ClassNameToVersion(const void *lpszClass, LPCWSTR lpszMenuName, LPCWSTR *plpLibFileName, HANDLE *pContext, BOOL bAnsi);
/* FUNCTIONS *****************************************************************/
NTSTATUS WINAPI
User32CallSendAsyncProcForKernel(PVOID Arguments, ULONG ArgumentLength)
{
PSENDASYNCPROC_CALLBACK_ARGUMENTS CallbackArgs;
TRACE("User32CallSendAsyncProcKernel()\n");
CallbackArgs = (PSENDASYNCPROC_CALLBACK_ARGUMENTS)Arguments;
if (ArgumentLength != sizeof(SENDASYNCPROC_CALLBACK_ARGUMENTS))
{
return(STATUS_INFO_LENGTH_MISMATCH);
}
CallbackArgs->Callback(CallbackArgs->Wnd,
CallbackArgs->Msg,
CallbackArgs->Context,
CallbackArgs->Result);
return(STATUS_SUCCESS);
}
/*
* @implemented
*/
BOOL WINAPI
AllowSetForegroundWindow(DWORD dwProcessId)
{
return NtUserxAllowSetForegroundWindow(dwProcessId);
}
/*
* @unimplemented
*/
HDWP WINAPI
BeginDeferWindowPos(int nNumWindows)
{
return NtUserxBeginDeferWindowPos(nNumWindows);
}
/*
* @implemented
*/
BOOL WINAPI
BringWindowToTop(HWND hWnd)
{
return NtUserSetWindowPos(hWnd,
HWND_TOP,
0,
0,
0,
0,
SWP_NOSIZE | SWP_NOMOVE);
}
VOID WINAPI
SwitchToThisWindow(HWND hwnd, BOOL fAltTab)
{
NtUserxSwitchToThisWindow(hwnd, fAltTab);
}
/*
* @implemented
*/
HWND WINAPI
ChildWindowFromPoint(HWND hWndParent,
POINT Point)
{
return (HWND) NtUserChildWindowFromPointEx(hWndParent, Point.x, Point.y, 0);
}
/*
* @implemented
*/
HWND WINAPI
ChildWindowFromPointEx(HWND hwndParent,
POINT pt,
UINT uFlags)
{
return (HWND) NtUserChildWindowFromPointEx(hwndParent, pt.x, pt.y, uFlags);
}
/*
* @implemented
*/
BOOL WINAPI
CloseWindow(HWND hWnd)
{
/* NOTE: CloseWindow does minimizes, and doesn't close. */
SetActiveWindow(hWnd);
return ShowWindow(hWnd, SW_SHOWMINIMIZED);
}
FORCEINLINE
VOID
RtlInitLargeString(
OUT PLARGE_STRING plstr,
LPCVOID psz,
BOOL bUnicode)
{
if(bUnicode)
{
RtlInitLargeUnicodeString((PLARGE_UNICODE_STRING)plstr, (PWSTR)psz, 0);
}
else
{
RtlInitLargeAnsiString((PLARGE_ANSI_STRING)plstr, (PSTR)psz, 0);
}
}
VOID
NTAPI
RtlFreeLargeString(
IN PLARGE_STRING LargeString)
{
if (LargeString->Buffer)
{
RtlFreeHeap(GetProcessHeap(), 0, LargeString->Buffer);
RtlZeroMemory(LargeString, sizeof(LARGE_STRING));
}
}
DWORD
FASTCALL
RtlGetExpWinVer( HMODULE hModule )
{
DWORD dwMajorVersion = 3; // Set default to Windows 3.10.
DWORD dwMinorVersion = 10;
PIMAGE_NT_HEADERS pinth;
if ( hModule && !((ULONG_PTR)hModule >> 16))
{
pinth = RtlImageNtHeader( hModule );
if ( pinth )
{
dwMajorVersion = pinth->OptionalHeader.MajorSubsystemVersion;
if ( dwMajorVersion == 1 )
{
dwMajorVersion = 3;
}
else
{
dwMinorVersion = pinth->OptionalHeader.MinorSubsystemVersion;
}
}
}
return MAKELONG(MAKEWORD(dwMinorVersion, dwMajorVersion), 0);
}
HWND WINAPI
User32CreateWindowEx(DWORD dwExStyle,
LPCSTR lpClassName,
LPCSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam,
DWORD dwFlags)
{
LARGE_STRING WindowName;
LARGE_STRING lstrClassName, *plstrClassName;
LARGE_STRING lstrClassVersion, *plstrClassVersion;
UNICODE_STRING ClassName;
UNICODE_STRING ClassVersion;
WNDCLASSEXA wceA;
WNDCLASSEXW wceW;
HMODULE hLibModule = NULL;
DWORD dwLastError;
BOOL Unicode, ClassFound = FALSE;
HWND Handle = NULL;
LPCWSTR lpszClsVersion;
LPCWSTR lpLibFileName = NULL;
HANDLE pCtx = NULL;
DWORD dwFlagsVer;
#if 0
DbgPrint("[window] User32CreateWindowEx style %d, exstyle %d, parent %d\n", dwStyle, dwExStyle, hWndParent);
#endif
dwFlagsVer = RtlGetExpWinVer( hInstance ? hInstance : GetModuleHandleW(NULL) );
TRACE("Module Version %x\n",dwFlagsVer);
if (!RegisterDefaultClasses)
{
TRACE("RegisterSystemControls\n");
RegisterSystemControls();
}
Unicode = !(dwFlags & NUCWE_ANSI);
if (IS_ATOM(lpClassName))
{
plstrClassName = (PVOID)lpClassName;
}
else
{
if (Unicode)
{
RtlInitUnicodeString(&ClassName, (PCWSTR)lpClassName);
}
else
{
if (!RtlCreateUnicodeStringFromAsciiz(&ClassName, (PCSZ)lpClassName))
{
SetLastError(ERROR_OUTOFMEMORY);
return NULL;
}
}
/* Copy it to a LARGE_STRING */
lstrClassName.Buffer = ClassName.Buffer;
lstrClassName.Length = ClassName.Length;
lstrClassName.MaximumLength = ClassName.MaximumLength;
plstrClassName = &lstrClassName;
}
/* Initialize a LARGE_STRING */
RtlInitLargeString(&WindowName, lpWindowName, Unicode);
// HACK: The current implementation expects the Window name to be UNICODE
if (!Unicode)
{
NTSTATUS Status;
PSTR AnsiBuffer = WindowName.Buffer;
ULONG AnsiLength = WindowName.Length;
WindowName.Length = 0;
WindowName.MaximumLength = AnsiLength * sizeof(WCHAR);
WindowName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
0,
WindowName.MaximumLength);
if (!WindowName.Buffer)
{
SetLastError(ERROR_OUTOFMEMORY);
goto cleanup;
}
Status = RtlMultiByteToUnicodeN(WindowName.Buffer,
WindowName.MaximumLength,
&WindowName.Length,
AnsiBuffer,
AnsiLength);
if (!NT_SUCCESS(Status))
{
goto cleanup;
}
}
if (!hMenu && (dwStyle & (WS_OVERLAPPEDWINDOW | WS_POPUP)))
{
if (Unicode)
{
wceW.cbSize = sizeof(wceW);
if (GetClassInfoExW(hInstance, (LPCWSTR)lpClassName, &wceW) && wceW.lpszMenuName)
{
hMenu = LoadMenuW(hInstance, wceW.lpszMenuName);
}
}
else
{
wceA.cbSize = sizeof(wceA);
if (GetClassInfoExA(hInstance, lpClassName, &wceA) && wceA.lpszMenuName)
{
hMenu = LoadMenuA(hInstance, wceA.lpszMenuName);
}
}
}
if (!Unicode) dwExStyle |= WS_EX_SETANSICREATOR;
lpszClsVersion = ClassNameToVersion(lpClassName, NULL, &lpLibFileName, &pCtx, !Unicode);
if (!lpszClsVersion)
{
plstrClassVersion = plstrClassName;
}
else
{
RtlInitUnicodeString(&ClassVersion, lpszClsVersion);
lstrClassVersion.Buffer = ClassVersion.Buffer;
lstrClassVersion.Length = ClassVersion.Length;
lstrClassVersion.MaximumLength = ClassVersion.MaximumLength;
plstrClassVersion = &lstrClassVersion;
}
for (;;)
{
Handle = NtUserCreateWindowEx(dwExStyle,
plstrClassName,
plstrClassVersion,
&WindowName,
dwStyle,
x,
y,
nWidth,
nHeight,
hWndParent,
hMenu,
hInstance,
lpParam,
dwFlagsVer,
pCtx );
if (Handle) break;
if (!lpLibFileName) break;
if (!ClassFound)
{
dwLastError = GetLastError();
if (dwLastError == ERROR_CANNOT_FIND_WND_CLASS)
{
ClassFound = VersionRegisterClass(ClassName.Buffer, lpLibFileName, pCtx, &hLibModule);
if (ClassFound) continue;
}
}
if (hLibModule)
{
dwLastError = GetLastError();
FreeLibrary(hLibModule);
SetLastError(dwLastError);
hLibModule = NULL;
}
break;
}
#if 0
DbgPrint("[window] NtUserCreateWindowEx() == %d\n", Handle);
#endif
cleanup:
if (!Unicode)
{
if (!IS_ATOM(lpClassName))
RtlFreeUnicodeString(&ClassName);
RtlFreeLargeString(&WindowName);
}
return Handle;
}
/*
* @implemented
*/
HWND
WINAPI
DECLSPEC_HOTPATCH
CreateWindowExA(DWORD dwExStyle,
LPCSTR lpClassName,
LPCSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam)
{
MDICREATESTRUCTA mdi;
HWND hwnd;
if (!RegisterDefaultClasses)
{
TRACE("CreateWindowExA RegisterSystemControls\n");
RegisterSystemControls();
}
if (dwExStyle & WS_EX_MDICHILD)
{
POINT mPos[2];
UINT id = 0;
HWND top_child;
PWND pWndParent;
pWndParent = ValidateHwnd(hWndParent);
if (!pWndParent) return NULL;
if (pWndParent->fnid != FNID_MDICLIENT) // wine uses WIN_ISMDICLIENT
{
WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", hWndParent);
return NULL;
}
/* lpParams of WM_[NC]CREATE is different for MDI children.
* MDICREATESTRUCT members have the originally passed values.
*/
mdi.szClass = lpClassName;
mdi.szTitle = lpWindowName;
mdi.hOwner = hInstance;
mdi.x = x;
mdi.y = y;
mdi.cx = nWidth;
mdi.cy = nHeight;
mdi.style = dwStyle;
mdi.lParam = (LPARAM)lpParam;
lpParam = (LPVOID)&mdi;
if (pWndParent->style & MDIS_ALLCHILDSTYLES)
{
if (dwStyle & WS_POPUP)
{
WARN("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
return(0);
}
dwStyle |= (WS_CHILD | WS_CLIPSIBLINGS);
}
else
{
dwStyle &= ~WS_POPUP;
dwStyle |= (WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
}
top_child = GetWindow(hWndParent, GW_CHILD);
if (top_child)
{
/* Restore current maximized child */
if((dwStyle & WS_VISIBLE) && IsZoomed(top_child))
{
TRACE("Restoring current maximized child %p\n", top_child);
SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
ShowWindow(top_child, SW_RESTORE);
SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
}
}
MDI_CalcDefaultChildPos(hWndParent, -1, mPos, 0, &id);
if (!(dwStyle & WS_POPUP)) hMenu = UlongToHandle(id);
if (dwStyle & (WS_CHILD | WS_POPUP))
{
if (x == CW_USEDEFAULT || x == CW_USEDEFAULT16)
{
x = mPos[0].x;
y = mPos[0].y;
}
if (nWidth == CW_USEDEFAULT || nWidth == CW_USEDEFAULT16 || !nWidth)
nWidth = mPos[1].x;
if (nHeight == CW_USEDEFAULT || nHeight == CW_USEDEFAULT16 || !nHeight)
nHeight = mPos[1].y;
}
}
hwnd = User32CreateWindowEx(dwExStyle,
lpClassName,
lpWindowName,
dwStyle,
x,
y,
nWidth,
nHeight,
hWndParent,
hMenu,
hInstance,
lpParam,
NUCWE_ANSI);
return hwnd;
}
/*
* @implemented
*/
HWND
WINAPI
DECLSPEC_HOTPATCH
CreateWindowExW(DWORD dwExStyle,
LPCWSTR lpClassName,
LPCWSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam)
{
MDICREATESTRUCTW mdi;
HWND hwnd;
if (!RegisterDefaultClasses)
{
ERR("CreateWindowExW RegisterSystemControls\n");
RegisterSystemControls();
}
if (dwExStyle & WS_EX_MDICHILD)
{
POINT mPos[2];
UINT id = 0;
HWND top_child;
PWND pWndParent;
pWndParent = ValidateHwnd(hWndParent);
if (!pWndParent) return NULL;
if (pWndParent->fnid != FNID_MDICLIENT)
{
WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", hWndParent);
return NULL;
}
/* lpParams of WM_[NC]CREATE is different for MDI children.
* MDICREATESTRUCT members have the originally passed values.
*/
mdi.szClass = lpClassName;
mdi.szTitle = lpWindowName;
mdi.hOwner = hInstance;
mdi.x = x;
mdi.y = y;
mdi.cx = nWidth;
mdi.cy = nHeight;
mdi.style = dwStyle;
mdi.lParam = (LPARAM)lpParam;
lpParam = (LPVOID)&mdi;
if (pWndParent->style & MDIS_ALLCHILDSTYLES)
{
if (dwStyle & WS_POPUP)
{
WARN("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
return(0);
}
dwStyle |= (WS_CHILD | WS_CLIPSIBLINGS);
}
else
{
dwStyle &= ~WS_POPUP;
dwStyle |= (WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
}
top_child = GetWindow(hWndParent, GW_CHILD);
if (top_child)
{
/* Restore current maximized child */
if((dwStyle & WS_VISIBLE) && IsZoomed(top_child))
{
TRACE("Restoring current maximized child %p\n", top_child);
SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 );
ShowWindow(top_child, SW_RESTORE);
SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 );
}
}
MDI_CalcDefaultChildPos(hWndParent, -1, mPos, 0, &id);
if (!(dwStyle & WS_POPUP)) hMenu = UlongToHandle(id);
if (dwStyle & (WS_CHILD | WS_POPUP))
{
if (x == CW_USEDEFAULT || x == CW_USEDEFAULT16)
{
x = mPos[0].x;
y = mPos[0].y;
}
if (nWidth == CW_USEDEFAULT || nWidth == CW_USEDEFAULT16 || !nWidth)
nWidth = mPos[1].x;
if (nHeight == CW_USEDEFAULT || nHeight == CW_USEDEFAULT16 || !nHeight)
nHeight = mPos[1].y;
}
}
hwnd = User32CreateWindowEx(dwExStyle,
(LPCSTR)lpClassName,
(LPCSTR)lpWindowName,
dwStyle,
x,
y,
nWidth,
nHeight,
hWndParent,
hMenu,
hInstance,
lpParam,
0);
return hwnd;
}
/*
* @unimplemented
*/
HDWP WINAPI
DeferWindowPos(HDWP hWinPosInfo,
HWND hWnd,
HWND hWndInsertAfter,
int x,
int y,
int cx,
int cy,
UINT uFlags)
{
return NtUserDeferWindowPos(hWinPosInfo, hWnd, hWndInsertAfter, x, y, cx, cy, uFlags);
}
/*
* @unimplemented
*/
BOOL WINAPI
EndDeferWindowPos(HDWP hWinPosInfo)
{
return NtUserEndDeferWindowPosEx(hWinPosInfo, 0);
}
/*
* @implemented
*/
HWND WINAPI
GetDesktopWindow(VOID)
{
PWND Wnd;
HWND Ret = NULL;
_SEH2_TRY
{
Wnd = GetThreadDesktopWnd();
if (Wnd != NULL)
Ret = UserHMGetHandle(Wnd);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Do nothing */
}
_SEH2_END;
return Ret;
}
static BOOL
User32EnumWindows(HDESK hDesktop,
HWND hWndparent,
WNDENUMPROC lpfn,
LPARAM lParam,
DWORD dwThreadId,
BOOL bChildren)
{
DWORD i, dwCount = 0;
HWND* pHwnd = NULL;
HANDLE hHeap;
NTSTATUS Status;
if (!lpfn)
{
SetLastError ( ERROR_INVALID_PARAMETER );
return FALSE;
}
/* FIXME instead of always making two calls, should we use some
sort of persistent buffer and only grow it ( requiring a 2nd
call ) when the buffer wasn't already big enough? */
/* first get how many window entries there are */
Status = NtUserBuildHwndList(hDesktop,
hWndparent,
bChildren,
dwThreadId,
lParam,
NULL,
&dwCount);
if (!NT_SUCCESS(Status))
return FALSE;
if (!dwCount)
{
if (!dwThreadId)
return FALSE;
else
return TRUE;
}
/* allocate buffer to receive HWND handles */
hHeap = GetProcessHeap();
pHwnd = HeapAlloc(hHeap, 0, sizeof(HWND)*(dwCount+1));
if (!pHwnd)
{
SetLastError ( ERROR_NOT_ENOUGH_MEMORY );
return FALSE;
}
/* now call kernel again to fill the buffer this time */
Status = NtUserBuildHwndList(hDesktop,
hWndparent,
bChildren,
dwThreadId,
lParam,
pHwnd,
&dwCount);
if (!NT_SUCCESS(Status))
{
if (pHwnd)
HeapFree(hHeap, 0, pHwnd);
return FALSE;
}
/* call the user's callback function until we're done or
they tell us to quit */
for ( i = 0; i < dwCount; i++ )
{
/* FIXME I'm only getting NULLs from Thread Enumeration, and it's
* probably because I'm not doing it right in NtUserBuildHwndList.
* Once that's fixed, we shouldn't have to check for a NULL HWND
* here
* This is now fixed in revision 50205. (jt)
*/
if (!pHwnd[i]) /* don't enumerate a NULL HWND */
continue;
if (!(*lpfn)(pHwnd[i], lParam))
{
HeapFree ( hHeap, 0, pHwnd );
return FALSE;
}
}
if (pHwnd)
HeapFree(hHeap, 0, pHwnd);
return TRUE;
}
/*
* @implemented
*/
BOOL WINAPI
EnumChildWindows(HWND hWndParent,
WNDENUMPROC lpEnumFunc,
LPARAM lParam)
{
if (!hWndParent)
{
return EnumWindows(lpEnumFunc, lParam);
}
return User32EnumWindows(NULL, hWndParent, lpEnumFunc, lParam, 0, TRUE);
}
/*
* @implemented
*/
BOOL WINAPI
EnumThreadWindows(DWORD dwThreadId,
WNDENUMPROC lpfn,
LPARAM lParam)
{
if (!dwThreadId)
dwThreadId = GetCurrentThreadId();
return User32EnumWindows(NULL, NULL, lpfn, lParam, dwThreadId, FALSE);
}
/*
* @implemented
*/
BOOL WINAPI
EnumWindows(WNDENUMPROC lpEnumFunc,
LPARAM lParam)
{
return User32EnumWindows(NULL, NULL, lpEnumFunc, lParam, 0, FALSE);
}
/*
* @implemented
*/
BOOL WINAPI
EnumDesktopWindows(HDESK hDesktop,
WNDENUMPROC lpfn,
LPARAM lParam)
{
return User32EnumWindows(hDesktop, NULL, lpfn, lParam, 0, FALSE);
}
/*
* @implemented
*/
HWND WINAPI
FindWindowExA(HWND hwndParent,
HWND hwndChildAfter,
LPCSTR lpszClass,
LPCSTR lpszWindow)
{
LPWSTR titleW = NULL;
HWND hwnd = 0;
if (lpszWindow)
{
DWORD len = MultiByteToWideChar( CP_ACP, 0, lpszWindow, -1, NULL, 0 );
if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
MultiByteToWideChar( CP_ACP, 0, lpszWindow, -1, titleW, len );
}
if (!IS_INTRESOURCE(lpszClass))
{
WCHAR classW[256];
if (MultiByteToWideChar( CP_ACP, 0, lpszClass, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
hwnd = FindWindowExW( hwndParent, hwndChildAfter, classW, titleW );
}
else
{
hwnd = FindWindowExW( hwndParent, hwndChildAfter, (LPCWSTR)lpszClass, titleW );
}
HeapFree( GetProcessHeap(), 0, titleW );
return hwnd;
}
/*
* @implemented
*/
HWND WINAPI
FindWindowExW(HWND hwndParent,
HWND hwndChildAfter,
LPCWSTR lpszClass,
LPCWSTR lpszWindow)
{
UNICODE_STRING ucClassName, *pucClassName = NULL;
UNICODE_STRING ucWindowName, *pucWindowName = NULL;
if (IS_ATOM(lpszClass))
{
ucClassName.Length = 0;
ucClassName.Buffer = (LPWSTR)lpszClass;
pucClassName = &ucClassName;
}
else if (lpszClass != NULL)
{
RtlInitUnicodeString(&ucClassName,
lpszClass);
pucClassName = &ucClassName;
}
if (lpszWindow != NULL)
{
RtlInitUnicodeString(&ucWindowName,
lpszWindow);
pucWindowName = &ucWindowName;
}
return NtUserFindWindowEx(hwndParent,
hwndChildAfter,
pucClassName,
pucWindowName,
0);
}
/*
* @implemented
*/
HWND WINAPI
FindWindowA(LPCSTR lpClassName, LPCSTR lpWindowName)
{
//FIXME: FindWindow does not search children, but FindWindowEx does.
// what should we do about this?
return FindWindowExA (NULL, NULL, lpClassName, lpWindowName);
}
/*
* @implemented
*/
HWND WINAPI
FindWindowW(LPCWSTR lpClassName, LPCWSTR lpWindowName)
{
/*
There was a FIXME here earlier, but I think it is just a documentation unclarity.
FindWindow only searches top level windows. What they mean is that child
windows of other windows than the desktop can be searched.
FindWindowExW never does a recursive search.
/ Joakim
*/
return FindWindowExW(NULL, NULL, lpClassName, lpWindowName);
}
/*
* @implemented
*/
BOOL WINAPI
GetAltTabInfoA(HWND hwnd,
int iItem,
PALTTABINFO pati,
LPSTR pszItemText,
UINT cchItemText)
{
return NtUserGetAltTabInfo(hwnd,iItem,pati,(LPWSTR)pszItemText,cchItemText,TRUE);
}
/*
* @implemented
*/
BOOL WINAPI
GetAltTabInfoW(HWND hwnd,
int iItem,
PALTTABINFO pati,
LPWSTR pszItemText,
UINT cchItemText)
{
return NtUserGetAltTabInfo(hwnd,iItem,pati,pszItemText,cchItemText,FALSE);
}
/*
* @implemented
*/
HWND WINAPI
GetAncestor(HWND hwnd, UINT gaFlags)
{
HWND Ret = NULL;
PWND Ancestor, Wnd;
Wnd = ValidateHwnd(hwnd);
if (!Wnd)
return NULL;
_SEH2_TRY
{
Ancestor = NULL;
switch (gaFlags)
{
case GA_PARENT:
if (Wnd->spwndParent != NULL)
Ancestor = DesktopPtrToUser(Wnd->spwndParent);
break;
default:
/* FIXME: Call win32k for now */
Wnd = NULL;
break;
}
if (Ancestor != NULL)
Ret = UserHMGetHandle(Ancestor);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Do nothing */
}
_SEH2_END;
if (!Wnd) /* Fall back */
Ret = NtUserGetAncestor(hwnd, gaFlags);
return Ret;
}
/*
* @implemented
*/
BOOL WINAPI
GetClientRect(HWND hWnd, LPRECT lpRect)
{
PWND Wnd = ValidateHwnd(hWnd);
if (!Wnd) return FALSE;
if (Wnd->style & WS_MINIMIZED)
{
lpRect->left = lpRect->top = 0;
lpRect->right = GetSystemMetrics(SM_CXMINIMIZED);
lpRect->bottom = GetSystemMetrics(SM_CYMINIMIZED);
return TRUE;
}
if ( hWnd != GetDesktopWindow()) // Wnd->fnid != FNID_DESKTOP )
{
/* lpRect->left = lpRect->top = 0;
lpRect->right = Wnd->rcClient.right - Wnd->rcClient.left;
lpRect->bottom = Wnd->rcClient.bottom - Wnd->rcClient.top;
*/
*lpRect = Wnd->rcClient;
OffsetRect(lpRect, -Wnd->rcClient.left, -Wnd->rcClient.top);
}
else
{
lpRect->left = lpRect->top = 0;
lpRect->right = Wnd->rcClient.right;
lpRect->bottom = Wnd->rcClient.bottom;
/* Do this until Init bug is fixed. This sets 640x480, see InitMetrics.
lpRect->right = GetSystemMetrics(SM_CXSCREEN);
lpRect->bottom = GetSystemMetrics(SM_CYSCREEN);
*/ }
return TRUE;
}
/*
* @implemented
*/
HWND WINAPI
GetLastActivePopup(HWND hWnd)
{
PWND Wnd;
HWND Ret = hWnd;
Wnd = ValidateHwnd(hWnd);
if (Wnd != NULL)
{
_SEH2_TRY
{
if (Wnd->spwndLastActive)
{
PWND LastActive = DesktopPtrToUser(Wnd->spwndLastActive);
Ret = UserHMGetHandle(LastActive);
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Do nothing */
}
_SEH2_END;
}
return Ret;
}
/*
* @implemented
*/
HWND WINAPI
GetParent(HWND hWnd)
{
PWND Wnd, WndParent;
HWND Ret = NULL;
Wnd = ValidateHwnd(hWnd);
if (Wnd != NULL)
{
_SEH2_TRY
{
WndParent = NULL;
if (Wnd->style & WS_POPUP)
{
if (Wnd->spwndOwner != NULL)
WndParent = DesktopPtrToUser(Wnd->spwndOwner);
}
else if (Wnd->style & WS_CHILD)
{
if (Wnd->spwndParent != NULL)
WndParent = DesktopPtrToUser(Wnd->spwndParent);
}
if (WndParent != NULL)
Ret = UserHMGetHandle(WndParent);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Do nothing */
}
_SEH2_END;
}
return Ret;
}
/*
* @implemented
*/
BOOL WINAPI
GetProcessDefaultLayout(DWORD *pdwDefaultLayout)
{
return (BOOL)NtUserCallOneParam( (DWORD_PTR)pdwDefaultLayout, ONEPARAM_ROUTINE_GETPROCDEFLAYOUT);
}
/*
* @implemented
*/
HWND WINAPI
GetWindow(HWND hWnd,
UINT uCmd)
{
PWND Wnd, FoundWnd;
HWND Ret = NULL;
Wnd = ValidateHwnd(hWnd);
if (!Wnd)
return NULL;
_SEH2_TRY
{
FoundWnd = NULL;
switch (uCmd)
{
case GW_OWNER:
if (Wnd->spwndOwner != NULL)
FoundWnd = DesktopPtrToUser(Wnd->spwndOwner);
break;
case GW_HWNDFIRST:
if(Wnd->spwndParent != NULL)
{
FoundWnd = DesktopPtrToUser(Wnd->spwndParent);
if (FoundWnd->spwndChild != NULL)
FoundWnd = DesktopPtrToUser(FoundWnd->spwndChild);
}
break;
case GW_HWNDNEXT:
if (Wnd->spwndNext != NULL)
FoundWnd = DesktopPtrToUser(Wnd->spwndNext);
break;
case GW_HWNDPREV:
if (Wnd->spwndPrev != NULL)
FoundWnd = DesktopPtrToUser(Wnd->spwndPrev);
break;
case GW_CHILD:
if (Wnd->spwndChild != NULL)
FoundWnd = DesktopPtrToUser(Wnd->spwndChild);
break;
case GW_HWNDLAST:
FoundWnd = Wnd;
while ( FoundWnd->spwndNext != NULL)
FoundWnd = DesktopPtrToUser(FoundWnd->spwndNext);
break;
default:
Wnd = NULL;
break;
}
if (FoundWnd != NULL)
Ret = UserHMGetHandle(FoundWnd);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Do nothing */
}
_SEH2_END;
return Ret;
}
/*
* @implemented
*/
HWND WINAPI
GetTopWindow(HWND hWnd)
{
if (!hWnd) hWnd = GetDesktopWindow();
return GetWindow(hWnd, GW_CHILD);
}
/*
* @implemented
*/
BOOL
WINAPI
DECLSPEC_HOTPATCH
GetWindowInfo(HWND hWnd,
PWINDOWINFO pwi)
{
PWND pWnd;
PCLS pCls = NULL;
SIZE Size = {0,0};
BOOL Ret = FALSE;
if ( !pwi || pwi->cbSize != sizeof(WINDOWINFO))
SetLastError(ERROR_INVALID_PARAMETER); // Just set the error and go!
pWnd = ValidateHwnd(hWnd);
if (!pWnd)
return Ret;
UserGetWindowBorders(pWnd->style, pWnd->ExStyle, &Size, FALSE);
_SEH2_TRY
{
pCls = DesktopPtrToUser(pWnd->pcls);
pwi->rcWindow = pWnd->rcWindow;
pwi->rcClient = pWnd->rcClient;
pwi->dwStyle = pWnd->style;
pwi->dwExStyle = pWnd->ExStyle;
pwi->cxWindowBorders = Size.cx;
pwi->cyWindowBorders = Size.cy;
pwi->dwWindowStatus = 0;
if (pWnd->state & WNDS_ACTIVEFRAME || (GetActiveWindow() == hWnd))
pwi->dwWindowStatus = WS_ACTIVECAPTION;
pwi->atomWindowType = (pCls ? pCls->atomClassName : 0 );
if ( pWnd->state2 & WNDS2_WIN50COMPAT )
{
pwi->wCreatorVersion = 0x500;
}
else if ( pWnd->state2 & WNDS2_WIN40COMPAT )
{
pwi->wCreatorVersion = 0x400;
}
else if ( pWnd->state2 & WNDS2_WIN31COMPAT )
{
pwi->wCreatorVersion = 0x30A;
}
else
{
pwi->wCreatorVersion = 0x300;
}
Ret = TRUE;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Do nothing */
}
_SEH2_END;
return Ret;
}
/*
* @implemented
*/
UINT WINAPI
GetWindowModuleFileNameA(HWND hwnd,
LPSTR lpszFileName,
UINT cchFileNameMax)
{
PWND Wnd = ValidateHwnd(hwnd);
if (!Wnd)
return 0;
return GetModuleFileNameA(Wnd->hModule, lpszFileName, cchFileNameMax);
}
/*
* @implemented
*/
UINT WINAPI
GetWindowModuleFileNameW(HWND hwnd,
LPWSTR lpszFileName,
UINT cchFileNameMax)
{
PWND Wnd = ValidateHwnd(hwnd);
if (!Wnd)
return 0;
return GetModuleFileNameW( Wnd->hModule, lpszFileName, cchFileNameMax );
}
/*
* @implemented
*/
BOOL WINAPI
GetWindowRect(HWND hWnd,
LPRECT lpRect)
{
PWND Wnd = ValidateHwnd(hWnd);
if (!Wnd) return FALSE;
if ( hWnd != GetDesktopWindow()) // Wnd->fnid != FNID_DESKTOP )
{
*lpRect = Wnd->rcWindow;
}
else
{
lpRect->left = lpRect->top = 0;
lpRect->right = Wnd->rcWindow.right;
lpRect->bottom = Wnd->rcWindow.bottom;
/* Do this until Init bug is fixed. This sets 640x480, see InitMetrics.
lpRect->right = GetSystemMetrics(SM_CXSCREEN);
lpRect->bottom = GetSystemMetrics(SM_CYSCREEN);
*/ }
return TRUE;
}
/*
* @implemented
*/
int WINAPI
GetWindowTextA(HWND hWnd, LPSTR lpString, int nMaxCount)
{
PWND Wnd;
INT Length = 0;
if (lpString == NULL || nMaxCount == 0)
return 0;
Wnd = ValidateHwnd(hWnd);
if (!Wnd)
return 0;
lpString[0] = '\0';
if (!TestWindowProcess(Wnd))
{
_SEH2_TRY
{
Length = DefWindowProcA(hWnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Length = 0;
}
_SEH2_END;
}
else
{
Length = SendMessageA(hWnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString);
}
//ERR("GWTA Len %d : %s\n",Length,lpString);
return Length;
}
/*
* @implemented
*/
int WINAPI
GetWindowTextLengthA(HWND hWnd)
{
PWND Wnd;
Wnd = ValidateHwnd(hWnd);
if (!Wnd)
return 0;
if (!TestWindowProcess(Wnd))
{
return DefWindowProcA(hWnd, WM_GETTEXTLENGTH, 0, 0);
}
else
{
return SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
}
}
/*
* @implemented
*/
int WINAPI
GetWindowTextLengthW(HWND hWnd)
{
PWND Wnd;
Wnd = ValidateHwnd(hWnd);
if (!Wnd)
return 0;
if (!TestWindowProcess(Wnd))
{
return DefWindowProcW(hWnd, WM_GETTEXTLENGTH, 0, 0);
}
else
{
return SendMessageW(hWnd, WM_GETTEXTLENGTH, 0, 0);
}
}
/*
* @implemented
*/
int WINAPI
GetWindowTextW(HWND hWnd, LPWSTR lpString, int nMaxCount)
{
PWND Wnd;
INT Length = 0;
if (lpString == NULL || nMaxCount == 0)
return 0;
Wnd = ValidateHwnd(hWnd);
if (!Wnd)
return 0;
lpString[0] = L'\0';
if (!TestWindowProcess(Wnd))
{
_SEH2_TRY
{
Length = DefWindowProcW(hWnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Length = 0;
}
_SEH2_END;
}
else
{
Length = SendMessageW(hWnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString);
}
//ERR("GWTW Len %d : %S\n",Length,lpString);
return Length;
}
DWORD WINAPI
GetWindowThreadProcessId(HWND hWnd,
LPDWORD lpdwProcessId)
{
DWORD Ret = 0;
PTHREADINFO ti;
PWND pWnd = ValidateHwnd(hWnd);
if (!pWnd) return Ret;
ti = pWnd->head.pti;
if (ti)
{
if (ti == GetW32ThreadInfo())
{ // We are current.
//FIXME("Current!\n");
if (lpdwProcessId)
*lpdwProcessId = (DWORD_PTR)NtCurrentTeb()->ClientId.UniqueProcess;
Ret = (DWORD_PTR)NtCurrentTeb()->ClientId.UniqueThread;
}
else
{ // Ask kernel for info.
//FIXME("Kernel call!\n");
if (lpdwProcessId)
*lpdwProcessId = NtUserQueryWindow(hWnd, QUERY_WINDOW_UNIQUE_PROCESS_ID);
Ret = NtUserQueryWindow(hWnd, QUERY_WINDOW_UNIQUE_THREAD_ID);
}
}
return Ret;
}
/*
* @implemented
*/
BOOL WINAPI
IsChild(HWND hWndParent,
HWND hWnd)
{
PWND WndParent, DesktopWnd, Wnd;
BOOL Ret = FALSE;
WndParent = ValidateHwnd(hWndParent);
if (!WndParent)
return FALSE;
Wnd = ValidateHwnd(hWnd);
if (!Wnd)
return FALSE;
DesktopWnd = GetThreadDesktopWnd();
if (!DesktopWnd)
return FALSE;
_SEH2_TRY
{
while (Wnd != NULL && ((Wnd->style & (WS_POPUP|WS_CHILD)) == WS_CHILD))
{
if (Wnd->spwndParent != NULL)
{
Wnd = DesktopPtrToUser(Wnd->spwndParent);
if (Wnd == WndParent)
{
Ret = TRUE;
break;
}
}
else
break;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Do nothing */
}
_SEH2_END;
return Ret;
}
/*
* @implemented
*/
BOOL WINAPI
IsIconic(HWND hWnd)
{
PWND Wnd = ValidateHwnd(hWnd);
if (Wnd != NULL)
return (Wnd->style & WS_MINIMIZE) != 0;
return FALSE;
}
/*
* @implemented
*/
BOOL WINAPI
IsWindow(HWND hWnd)
{
PWND Wnd = ValidateHwndNoErr(hWnd);
if (Wnd != NULL)
{
if (Wnd->state & WNDS_DESTROYED ||
Wnd->state2 & WNDS2_INDESTROY)
return FALSE;
return TRUE;
}
return FALSE;
}
/*
* @implemented
*/
BOOL WINAPI
IsWindowUnicode(HWND hWnd)
{
PWND Wnd = ValidateHwnd(hWnd);
if (Wnd != NULL)
return Wnd->Unicode;
return FALSE;
}
/*
* @implemented
*/
BOOL WINAPI
IsWindowVisible(HWND hWnd)
{
BOOL Ret = FALSE;
PWND Wnd = ValidateHwnd(hWnd);
if (Wnd != NULL)
{
_SEH2_TRY
{
Ret = TRUE;
do
{
if (!(Wnd->style & WS_VISIBLE))
{
Ret = FALSE;
break;
}
if (Wnd->spwndParent != NULL)
Wnd = DesktopPtrToUser(Wnd->spwndParent);
else
break;
} while (Wnd != NULL);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Ret = FALSE;
}
_SEH2_END;
}
return Ret;
}
/*
* @implemented
*/
BOOL WINAPI
IsWindowEnabled(HWND hWnd)
{
// AG: I don't know if child windows are affected if the parent is
// disabled. I think they stop processing messages but stay appearing
// as enabled.
return !(GetWindowLongPtrW(hWnd, GWL_STYLE) & WS_DISABLED);
}
/*
* @implemented
*/
BOOL WINAPI
IsZoomed(HWND hWnd)
{
return (GetWindowLongPtrW(hWnd, GWL_STYLE) & WS_MAXIMIZE) != 0;
}
/*
* @implemented
*/
BOOL WINAPI
LockSetForegroundWindow(UINT uLockCode)
{
return NtUserxLockSetForegroundWindow(uLockCode);
}
/*
* @implemented
*/
BOOL WINAPI
AnimateWindow(HWND hwnd,
DWORD dwTime,
DWORD dwFlags)
{
/* FIXME Add animation code */
/* If trying to show/hide and it's already *
* shown/hidden or invalid window, fail with *
* invalid parameter */
BOOL visible;
visible = IsWindowVisible(hwnd);
if(!IsWindow(hwnd) ||
(visible && !(dwFlags & AW_HIDE)) ||
(!visible && (dwFlags & AW_HIDE)))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
ShowWindow(hwnd, (dwFlags & AW_HIDE) ? SW_HIDE : ((dwFlags & AW_ACTIVATE) ? SW_SHOW : SW_SHOWNA));
return TRUE;
}
/*
* @implemented
*/
BOOL WINAPI
OpenIcon(HWND hWnd)
{
if (!(GetWindowLongPtrW(hWnd, GWL_STYLE) & WS_MINIMIZE))
return FALSE;
ShowWindow(hWnd,SW_RESTORE);
return TRUE;
}
/*
* @implemented
*/
HWND WINAPI
RealChildWindowFromPoint(HWND hwndParent,
POINT ptParentClientCoords)
{
return NtUserRealChildWindowFromPoint(hwndParent, ptParentClientCoords.x, ptParentClientCoords.y);
}
/*
* @unimplemented
*/
BOOL WINAPI
SetForegroundWindow(HWND hWnd)
{
return NtUserxSetForegroundWindow(hWnd);
}
/*
* @implemented
*/
BOOL WINAPI
SetProcessDefaultLayout(DWORD dwDefaultLayout)
{
return NtUserCallOneParam( (DWORD_PTR)dwDefaultLayout, ONEPARAM_ROUTINE_SETPROCDEFLAYOUT);
}
/*
* @implemented
*/
BOOL
WINAPI
DECLSPEC_HOTPATCH
SetWindowTextA(HWND hWnd,
LPCSTR lpString)
{
PWND pwnd;
pwnd = ValidateHwnd(hWnd);
if (pwnd)
{
if (!TestWindowProcess(pwnd))
{
/* do not send WM_GETTEXT messages to other processes */
return (DefWindowProcA(hWnd, WM_SETTEXT, 0, (LPARAM)lpString) >= 0);
}
return (SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)lpString) >= 0);
}
return FALSE;
}
/*
* @implemented
*/
BOOL
WINAPI
DECLSPEC_HOTPATCH
SetWindowTextW(HWND hWnd,
LPCWSTR lpString)
{
PWND pwnd;
pwnd = ValidateHwnd(hWnd);
if (pwnd)
{
if (!TestWindowProcess(pwnd))
{
/* do not send WM_GETTEXT messages to other processes */
return (DefWindowProcW(hWnd, WM_SETTEXT, 0, (LPARAM)lpString) >= 0);
}
return (SendMessageW(hWnd, WM_SETTEXT, 0, (LPARAM)lpString) >= 0);
}
return FALSE;
}
/*
* @implemented
*/
BOOL WINAPI
ShowOwnedPopups(HWND hWnd, BOOL fShow)
{
return NtUserxShowOwnedPopups(hWnd, fShow);
}
/*
* @implemented
*/
BOOL WINAPI
UpdateLayeredWindow( HWND hwnd,
HDC hdcDst,
POINT *pptDst,
SIZE *psize,
HDC hdcSrc,
POINT *pptSrc,
COLORREF crKey,
BLENDFUNCTION *pbl,
DWORD dwFlags)
{
if (dwFlags & ULW_EX_NORESIZE) /* only valid for UpdateLayeredWindowIndirect */
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
return NtUserUpdateLayeredWindow( hwnd,
hdcDst,
pptDst,
psize,
hdcSrc,
pptSrc,
crKey,
pbl,
dwFlags,
NULL);
}
/*
* @implemented
*/
BOOL WINAPI
UpdateLayeredWindowIndirect(HWND hwnd,
const UPDATELAYEREDWINDOWINFO *info)
{
if (info && info->cbSize == sizeof(*info))
{
return NtUserUpdateLayeredWindow( hwnd,
info->hdcDst,
(POINT *)info->pptDst,
(SIZE *)info->psize,
info->hdcSrc,
(POINT *)info->pptSrc,
info->crKey,
(BLENDFUNCTION *)info->pblend,
info->dwFlags,
(RECT *)info->prcDirty);
}
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
/*
* @implemented
*/
BOOL WINAPI
SetWindowContextHelpId(HWND hwnd,
DWORD dwContextHelpId)
{
return NtUserxSetWindowContextHelpId(hwnd, dwContextHelpId);
}
/*
* @implemented
*/
DWORD WINAPI
GetWindowContextHelpId(HWND hwnd)
{
return NtUserxGetWindowContextHelpId(hwnd);
}
/*
* @implemented
*/
int WINAPI
InternalGetWindowText(HWND hWnd, LPWSTR lpString, int nMaxCount)
{
INT Ret = NtUserInternalGetWindowText(hWnd, lpString, nMaxCount);
if (Ret == 0 && lpString)
*lpString = L'\0';
return Ret;
}
/*
* @implemented
*/
BOOL WINAPI
IsHungAppWindow(HWND hwnd)
{
PWND Window;
UNICODE_STRING ClassName;
WCHAR szClass[16];
static const UNICODE_STRING GhostClass = RTL_CONSTANT_STRING(L"Ghost");
/* Ghost is a hung window */
RtlInitEmptyUnicodeString(&ClassName, szClass, sizeof(szClass));
Window = ValidateHwnd(hwnd);
if (Window && Window->fnid == FNID_GHOST &&
NtUserGetClassName(hwnd, FALSE, &ClassName) &&
RtlEqualUnicodeString(&ClassName, &GhostClass, TRUE))
{
return TRUE;
}
return (NtUserQueryWindow(hwnd, QUERY_WINDOW_ISHUNG) != 0);
}
/*
* @implemented
*/
VOID WINAPI
SetLastErrorEx(DWORD dwErrCode, DWORD dwType)
{
SetLastError(dwErrCode);
}
/*
* @implemented
*/
HWND WINAPI
GetFocus(VOID)
{
return (HWND)NtUserGetThreadState(THREADSTATE_FOCUSWINDOW);
}
DWORD WINAPI
GetRealWindowOwner(HWND hwnd)
{
return NtUserQueryWindow(hwnd, QUERY_WINDOW_REAL_ID);
}
/*
* @implemented
*/
HWND WINAPI
SetTaskmanWindow(HWND hWnd)
{
return NtUserxSetTaskmanWindow(hWnd);
}
/*
* @implemented
*/
HWND WINAPI
SetProgmanWindow(HWND hWnd)
{
return NtUserxSetProgmanWindow(hWnd);
}
/*
* @implemented
*/
HWND WINAPI
GetProgmanWindow(VOID)
{
return (HWND)NtUserGetThreadState(THREADSTATE_PROGMANWINDOW);
}
/*
* @implemented
*/
HWND WINAPI
GetTaskmanWindow(VOID)
{
return (HWND)NtUserGetThreadState(THREADSTATE_TASKMANWINDOW);
}
/*
* @implemented
*/
BOOL WINAPI
ScrollWindow(HWND hWnd,
int dx,
int dy,
CONST RECT *lpRect,
CONST RECT *prcClip)
{
return NtUserScrollWindowEx(hWnd,
dx,
dy,
lpRect,
prcClip,
0,
NULL,
(lpRect ? 0 : SW_SCROLLCHILDREN) | (SW_ERASE|SW_INVALIDATE|SW_SCROLLWNDDCE)) != ERROR;
}
/* ScrollWindow uses the window DC, ScrollWindowEx doesn't */
/*
* @implemented
*/
INT WINAPI
ScrollWindowEx(HWND hWnd,
int dx,
int dy,
CONST RECT *prcScroll,
CONST RECT *prcClip,
HRGN hrgnUpdate,
LPRECT prcUpdate,
UINT flags)
{
if (flags & SW_SMOOTHSCROLL)
{
FIXME("SW_SMOOTHSCROLL not supported.");
// Fall through....
}
return NtUserScrollWindowEx(hWnd,
dx,
dy,
prcScroll,
prcClip,
hrgnUpdate,
prcUpdate,
flags);
}
/*
* @implemented
*/
BOOL WINAPI
AnyPopup(VOID)
{
int i;
BOOL retvalue;
HWND *list = WIN_ListChildren( GetDesktopWindow() );
if (!list) return FALSE;
for (i = 0; list[i]; i++)
{
if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
}
retvalue = (list[i] != 0);
HeapFree( GetProcessHeap(), 0, list );
return retvalue;
}
/*
* @implemented
*/
BOOL WINAPI
IsWindowInDestroy(HWND hWnd)
{
PWND pwnd;
pwnd = ValidateHwnd(hWnd);
if (!pwnd)
return FALSE;
return ((pwnd->state2 & WNDS2_INDESTROY) == WNDS2_INDESTROY);
}
/*
* @implemented
*/
VOID WINAPI
DisableProcessWindowsGhosting(VOID)
{
NtUserxEnableProcessWindowGhosting(FALSE);
}
/* EOF */