reactos/win32ss/user/user32/windows/window.c
Katayama Hirofumi MZ c2a51c7249
[NTUSER][USER32] Make NtUserBuildHwndList exclusive (#4485)
- Modify prototype of NtUserBuildHwndList function.
- Wrap the code by UserEnterExclusive(); and UserLeave();.
CORE-18173
2022-05-05 08:49:00 +09:00

2035 lines
45 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 && !LOWORD((ULONG_PTR)hModule))
{
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);
goto skip_mdi;
}
/* 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;
}
}
skip_mdi:
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);
goto skip_mdi;
}
/* 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;
}
}
skip_mdi:
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, FALSE);
}
/*
* @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,
dwCount,
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,
dwCount,
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)
{
return !!NtUserQueryWindow(hwnd, QUERY_WINDOW_ISHUNG);
}
/*
* @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.\n");
// 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 */