mirror of
https://github.com/reactos/reactos.git
synced 2024-10-01 23:14:53 +00:00
b784074c2f
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-g568b6d0558
-------------- [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-g177ae91bf6
-------------- [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-g915a5764a9
-------------- [USER32] Fix null return. See CORE-16769. cherry picked from commit 0.4.14-dev-1240-gd8add40e89
2048 lines
46 KiB
C
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 */
|
|
|