https://git.reactos.org/?p=reactos.git;a=commitdiff;h=245513e7eceb3cb445c51a989769c967260d4882
commit 245513e7eceb3cb445c51a989769c967260d4882 Author: Justin Miller <justin.mil...@reactos.org> AuthorDate: Wed Jan 29 02:08:11 2025 -0800 Commit: Justin Miller <justinmiller...@gmail.com> CommitDate: Sun Mar 9 04:07:55 2025 -0700 [USER32_VISTA] Import input.c misc.c win.c from wine-10.0 --- win32ss/user/user32_vista/wine/input.c | 889 ++++++++++++++++ win32ss/user/user32_vista/wine/misc.c | 545 ++++++++++ win32ss/user/user32_vista/wine/win.c | 1731 ++++++++++++++++++++++++++++++++ 3 files changed, 3165 insertions(+) diff --git a/win32ss/user/user32_vista/wine/input.c b/win32ss/user/user32_vista/wine/input.c new file mode 100644 index 00000000000..38c44d7d831 --- /dev/null +++ b/win32ss/user/user32_vista/wine/input.c @@ -0,0 +1,889 @@ +/* + * USER Input processing + * + * Copyright 1993 Bob Amstadt + * Copyright 1996 Albrecht Kleine + * Copyright 1997 David Faure + * Copyright 1998 Morten Welinder + * Copyright 1998 Ulrich Weigand + * Copyright 2012 Henri Verbeet + * Copyright 2018 Zebediah Figura for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "user_private.h" +#include "dbt.h" +#include "wine/debug.h" +#include "wine/plugplay.h" + +WINE_DEFAULT_DEBUG_CHANNEL(win); +WINE_DECLARE_DEBUG_CHANNEL(keyboard); + +/*********************************************************************** + * get_locale_kbd_layout + */ +static HKL get_locale_kbd_layout(void) +{ + ULONG_PTR layout; + + /* FIXME: + * + * layout = main_key_tab[kbd_layout].lcid; + * + * Winword uses return value of GetKeyboardLayout as a codepage + * to translate ANSI keyboard messages to unicode. But we have + * a problem with it: for instance Polish keyboard layout is + * identical to the US one, and therefore instead of the Polish + * locale id we return the US one. + */ + + layout = GetUserDefaultLCID(); + layout = MAKELONG( layout, layout ); + return (HKL)layout; +} + + +/*********************************************************************** + * keybd_event (USER32.@) + */ +void WINAPI keybd_event( BYTE bVk, BYTE bScan, + DWORD dwFlags, ULONG_PTR dwExtraInfo ) +{ + INPUT input; + + input.type = INPUT_KEYBOARD; + input.ki.wVk = bVk; + input.ki.wScan = bScan; + input.ki.dwFlags = dwFlags; + input.ki.time = 0; + input.ki.dwExtraInfo = dwExtraInfo; + NtUserSendInput( 1, &input, sizeof(input) ); +} + + +/*********************************************************************** + * mouse_event (USER32.@) + */ +void WINAPI mouse_event( DWORD dwFlags, DWORD dx, DWORD dy, + DWORD dwData, ULONG_PTR dwExtraInfo ) +{ + INPUT input; + + input.type = INPUT_MOUSE; + input.mi.dx = dx; + input.mi.dy = dy; + input.mi.mouseData = dwData; + input.mi.dwFlags = dwFlags; + input.mi.time = 0; + input.mi.dwExtraInfo = dwExtraInfo; + NtUserSendInput( 1, &input, sizeof(input) ); +} + + +/*********************************************************************** + * GetCursorPos (USER32.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH GetCursorPos( POINT *pt ) +{ + return NtUserGetCursorPos( pt ); +} + + +/********************************************************************** + * ReleaseCapture (USER32.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH ReleaseCapture(void) +{ + return NtUserReleaseCapture(); +} + + +/********************************************************************** + * GetCapture (USER32.@) + */ +HWND WINAPI GetCapture(void) +{ + GUITHREADINFO info; + info.cbSize = sizeof(info); + return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndCapture : 0; +} + + +/***************************************************************** + * DestroyCaret (USER32.@) + */ +BOOL WINAPI DestroyCaret(void) +{ + return NtUserDestroyCaret(); +} + + +/***************************************************************** + * SetCaretPos (USER32.@) + */ +BOOL WINAPI SetCaretPos( int x, int y ) +{ + return NtUserSetCaretPos( x, y ); +} + + +/***************************************************************** + * SetCaretBlinkTime (USER32.@) + */ +BOOL WINAPI SetCaretBlinkTime( unsigned int time ) +{ + return NtUserSetCaretBlinkTime( time ); +} + + +/*********************************************************************** + * GetInputState (USER32.@) + */ +BOOL WINAPI GetInputState(void) +{ + return NtUserGetInputState(); +} + + +/****************************************************************** + * GetLastInputInfo (USER32.@) + */ +BOOL WINAPI GetLastInputInfo(PLASTINPUTINFO plii) +{ + TRACE("%p\n", plii); + + if (plii->cbSize != sizeof (*plii) ) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + plii->dwTime = NtUserGetLastInputTime(); + return TRUE; +} + + +/********************************************************************** + * VkKeyScanA (USER32.@) + * + * VkKeyScan translates an ANSI character to a virtual-key and shift code + * for the current keyboard. + * high-order byte yields : + * 0 Unshifted + * 1 Shift + * 2 Ctrl + * 3-5 Shift-key combinations that are not used for characters + * 6 Ctrl-Alt + * 7 Ctrl-Alt-Shift + * I.e. : Shift = 1, Ctrl = 2, Alt = 4. + * FIXME : works ok except for dead chars : + * VkKeyScan '^'(0x5e, 94) ... got keycode 00 ... returning 00 + * VkKeyScan '`'(0x60, 96) ... got keycode 00 ... returning 00 + */ +SHORT WINAPI VkKeyScanA(CHAR cChar) +{ + WCHAR wChar; + + if (IsDBCSLeadByte(cChar)) return -1; + + MultiByteToWideChar(CP_ACP, 0, &cChar, 1, &wChar, 1); + return VkKeyScanW(wChar); +} + +/****************************************************************************** + * VkKeyScanW (USER32.@) + */ +SHORT WINAPI VkKeyScanW(WCHAR cChar) +{ + return NtUserVkKeyScanEx( cChar, NtUserGetKeyboardLayout(0) ); +} + +/********************************************************************** + * VkKeyScanExA (USER32.@) + */ +WORD WINAPI VkKeyScanExA(CHAR cChar, HKL dwhkl) +{ + WCHAR wChar; + + if (IsDBCSLeadByte(cChar)) return -1; + + MultiByteToWideChar(CP_ACP, 0, &cChar, 1, &wChar, 1); + return NtUserVkKeyScanEx( wChar, dwhkl ); +} + +/********************************************************************** + * OemKeyScan (USER32.@) + */ +DWORD WINAPI OemKeyScan( WORD oem ) +{ + WCHAR wchr; + DWORD vkey, scan; + char oem_char = LOBYTE( oem ); + + if (!OemToCharBuffW( &oem_char, &wchr, 1 )) + return -1; + + vkey = VkKeyScanW( wchr ); + scan = MapVirtualKeyW( LOBYTE( vkey ), MAPVK_VK_TO_VSC ); + if (!scan) return -1; + + vkey &= 0xff00; + vkey <<= 8; + return vkey | scan; +} + +/****************************************************************************** + * GetKeyboardType (USER32.@) + */ +INT WINAPI GetKeyboardType(INT nTypeFlag) +{ + TRACE_(keyboard)("(%d)\n", nTypeFlag); + if (LOWORD(NtUserGetKeyboardLayout(0)) == MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN)) + { + /* scan code for `_', the key left of r-shift, in Japanese 106 keyboard */ + const UINT JP106_VSC_USCORE = 0x73; + + switch(nTypeFlag) + { + case 0: /* Keyboard type */ + return 7; /* Japanese keyboard */ + case 1: /* Keyboard Subtype */ + /* Test keyboard mappings to detect Japanese keyboard */ + if (MapVirtualKeyW(VK_OEM_102, MAPVK_VK_TO_VSC) == JP106_VSC_USCORE + && MapVirtualKeyW(JP106_VSC_USCORE, MAPVK_VSC_TO_VK) == VK_OEM_102) + return 2; /* Japanese 106 */ + else + return 0; /* AT-101 */ + case 2: /* Number of F-keys */ + return 12; /* It has 12 F-keys */ + } + } + else + { + switch(nTypeFlag) + { + case 0: /* Keyboard type */ + return 4; /* AT-101 */ + case 1: /* Keyboard Subtype */ + return 0; /* There are no defined subtypes */ + case 2: /* Number of F-keys */ + return 12; /* We're doing an 101 for now, so return 12 F-keys */ + } + } + WARN_(keyboard)("Unknown type\n"); + return 0; /* The book says 0 here, so 0 */ +} + +/****************************************************************************** + * MapVirtualKeyA (USER32.@) + */ +UINT WINAPI MapVirtualKeyA(UINT code, UINT maptype) +{ + return MapVirtualKeyExA( code, maptype, NtUserGetKeyboardLayout(0) ); +} + +/****************************************************************************** + * MapVirtualKeyW (USER32.@) + */ +UINT WINAPI MapVirtualKeyW(UINT code, UINT maptype) +{ + return NtUserMapVirtualKeyEx( code, maptype, NtUserGetKeyboardLayout(0) ); +} + +/****************************************************************************** + * MapVirtualKeyExA (USER32.@) + */ +UINT WINAPI MapVirtualKeyExA(UINT code, UINT maptype, HKL hkl) +{ + UINT ret; + + ret = NtUserMapVirtualKeyEx( code, maptype, hkl ); + if (maptype == MAPVK_VK_TO_CHAR) + { + BYTE ch = 0; + WCHAR wch = ret; + + WideCharToMultiByte( CP_ACP, 0, &wch, 1, (LPSTR)&ch, 1, NULL, NULL ); + ret = ch; + } + return ret; +} + +/**************************************************************************** + * GetKBCodePage (USER32.@) + */ +UINT WINAPI GetKBCodePage(void) +{ + return GetOEMCP(); +} + +/**************************************************************************** + * GetKeyboardLayoutNameA (USER32.@) + */ +BOOL WINAPI GetKeyboardLayoutNameA(LPSTR pszKLID) +{ + WCHAR buf[KL_NAMELENGTH]; + + if (NtUserGetKeyboardLayoutName( buf )) + return WideCharToMultiByte( CP_ACP, 0, buf, -1, pszKLID, KL_NAMELENGTH, NULL, NULL ) != 0; + return FALSE; +} + +/**************************************************************************** + * GetKeyNameTextA (USER32.@) + */ +INT WINAPI GetKeyNameTextA(LONG lParam, LPSTR lpBuffer, INT nSize) +{ + WCHAR buf[256]; + INT ret; + + if (!nSize || !NtUserGetKeyNameText( lParam, buf, ARRAYSIZE(buf) )) + { + lpBuffer[0] = 0; + return 0; + } + ret = WideCharToMultiByte(CP_ACP, 0, buf, -1, lpBuffer, nSize, NULL, NULL); + if (!ret && nSize) + { + ret = nSize - 1; + lpBuffer[ret] = 0; + } + else ret--; + + return ret; +} + +/**************************************************************************** + * ToUnicode (USER32.@) + */ +INT WINAPI ToUnicode( UINT virt, UINT scan, const BYTE *state, LPWSTR str, int size, UINT flags ) +{ + return NtUserToUnicodeEx( virt, scan, state, str, size, flags, NtUserGetKeyboardLayout(0) ); +} + +/**************************************************************************** + * ToAscii (USER32.@) + */ +INT WINAPI ToAscii( UINT virtKey, UINT scanCode, const BYTE *lpKeyState, + LPWORD lpChar, UINT flags ) +{ + return ToAsciiEx( virtKey, scanCode, lpKeyState, lpChar, flags, + NtUserGetKeyboardLayout(0) ); +} + +/**************************************************************************** + * ToAsciiEx (USER32.@) + */ +INT WINAPI ToAsciiEx( UINT virtKey, UINT scanCode, const BYTE *lpKeyState, + LPWORD lpChar, UINT flags, HKL dwhkl ) +{ + WCHAR uni_chars[2]; + INT ret, n_ret; + + ret = NtUserToUnicodeEx( virtKey, scanCode, lpKeyState, uni_chars, 2, flags, dwhkl ); + if (ret < 0) n_ret = 1; /* FIXME: make ToUnicode return 2 for dead chars */ + else n_ret = ret; + WideCharToMultiByte(CP_ACP, 0, uni_chars, n_ret, (LPSTR)lpChar, 2, NULL, NULL); + return ret; +} + +/********************************************************************** + * BlockInput (USER32.@) + */ +BOOL WINAPI BlockInput(BOOL fBlockIt) +{ + FIXME_(keyboard)("(%d): stub\n", fBlockIt); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + + return FALSE; +} + + +/*********************************************************************** + * LoadKeyboardLayoutW (USER32.@) + */ +HKL WINAPI LoadKeyboardLayoutW( const WCHAR *name, UINT flags ) +{ + WCHAR layout_path[MAX_PATH], value[5]; + LCID locale = GetUserDefaultLCID(); + DWORD id, value_size, tmp; + HKEY hkey; + HKL layout; + + FIXME_(keyboard)( "name %s, flags %x, semi-stub!\n", debugstr_w( name ), flags ); + + tmp = wcstoul( name, NULL, 16 ); + if (HIWORD( tmp )) layout = UlongToHandle( tmp ); + else layout = UlongToHandle( MAKELONG( LOWORD( tmp ), LOWORD( tmp ) ) ); + + if (!((UINT_PTR)layout >> 28)) id = LOWORD( tmp ); + else id = HIWORD( layout ); /* IME or aliased layout */ + + wcscpy( layout_path, L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\" ); + wcscat( layout_path, name ); + + if (!RegOpenKeyW( HKEY_LOCAL_MACHINE, layout_path, &hkey )) + { + value_size = sizeof(value); + if (!RegGetValueW( hkey, NULL, L"Layout Id", RRF_RT_REG_SZ, NULL, (void *)&value, &value_size )) + id = 0xf000 | (wcstoul( value, NULL, 16 ) & 0xfff); + + RegCloseKey( hkey ); + } + + layout = UlongToHandle( MAKELONG( locale, id ) ); + if ((flags & KLF_ACTIVATE) && NtUserActivateKeyboardLayout( layout, 0 )) return layout; + + /* FIXME: semi-stub: returning default layout */ + return get_locale_kbd_layout(); +} + +/*********************************************************************** + * LoadKeyboardLayoutA (USER32.@) + */ +HKL WINAPI LoadKeyboardLayoutA(LPCSTR pwszKLID, UINT Flags) +{ + HKL ret; + UNICODE_STRING pwszKLIDW; + + if (pwszKLID) RtlCreateUnicodeStringFromAsciiz(&pwszKLIDW, pwszKLID); + else pwszKLIDW.Buffer = NULL; + + ret = LoadKeyboardLayoutW(pwszKLIDW.Buffer, Flags); + RtlFreeUnicodeString(&pwszKLIDW); + return ret; +} + + +/*********************************************************************** + * LoadKeyboardLayoutEx (USER32.@) + */ +HKL WINAPI LoadKeyboardLayoutEx( HKL layout, const WCHAR *name, UINT flags ) +{ + FIXME_(keyboard)( "layout %p, name %s, flags %x, semi-stub!\n", layout, debugstr_w( name ), flags ); + + if (!layout) return NULL; + return LoadKeyboardLayoutW( name, flags ); +} + +/*********************************************************************** + * UnloadKeyboardLayout (USER32.@) + */ +BOOL WINAPI UnloadKeyboardLayout( HKL layout ) +{ + FIXME_(keyboard)( "layout %p, stub!\n", layout ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + + +static DWORD CALLBACK devnotify_window_callbackW(HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header) +{ + SendMessageTimeoutW(handle, WM_DEVICECHANGE, flags, (LPARAM)header, SMTO_ABORTIFHUNG, 2000, NULL); + return 0; +} + +static DWORD CALLBACK devnotify_window_callbackA(HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header) +{ + if (flags & 0x8000) + { + switch (header->dbch_devicetype) + { + case DBT_DEVTYP_DEVICEINTERFACE: + { + const DEV_BROADCAST_DEVICEINTERFACE_W *ifaceW = (const DEV_BROADCAST_DEVICEINTERFACE_W *)header; + size_t lenW = wcslen( ifaceW->dbcc_name ); + DEV_BROADCAST_DEVICEINTERFACE_A *ifaceA; + DWORD lenA; + + if (!(ifaceA = malloc( offsetof(DEV_BROADCAST_DEVICEINTERFACE_A, dbcc_name[lenW * 3 + 1]) ))) + return 0; + lenA = WideCharToMultiByte( CP_ACP, 0, ifaceW->dbcc_name, lenW + 1, + ifaceA->dbcc_name, lenW * 3 + 1, NULL, NULL ); + + ifaceA->dbcc_size = offsetof(DEV_BROADCAST_DEVICEINTERFACE_A, dbcc_name[lenA + 1]); + ifaceA->dbcc_devicetype = ifaceW->dbcc_devicetype; + ifaceA->dbcc_reserved = ifaceW->dbcc_reserved; + ifaceA->dbcc_classguid = ifaceW->dbcc_classguid; + SendMessageTimeoutA( handle, WM_DEVICECHANGE, flags, (LPARAM)ifaceA, SMTO_ABORTIFHUNG, 2000, NULL ); + free( ifaceA ); + return 0; + } + + case DBT_DEVTYP_HANDLE: + { + const DEV_BROADCAST_HANDLE *handleW = (const DEV_BROADCAST_HANDLE *)header; + UINT sizeW = handleW->dbch_size - offsetof(DEV_BROADCAST_HANDLE, dbch_data[0]), len, offset; + DEV_BROADCAST_HANDLE *handleA; + + if (!(handleA = malloc( offsetof(DEV_BROADCAST_HANDLE, dbch_data[sizeW * 3 + 1]) ))) return 0; + memcpy( handleA, handleW, offsetof(DEV_BROADCAST_HANDLE, dbch_data[0]) ); + offset = min( sizeW, handleW->dbch_nameoffset ); + + memcpy( handleA->dbch_data, handleW->dbch_data, offset ); + len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(handleW->dbch_data + offset), (sizeW - offset) / sizeof(WCHAR), + (char *)handleA->dbch_data + offset, sizeW * 3 + 1 - offset, NULL, NULL ); + handleA->dbch_size = offsetof(DEV_BROADCAST_HANDLE, dbch_data[offset + len + 1]); + + SendMessageTimeoutA( handle, WM_DEVICECHANGE, flags, (LPARAM)handleA, SMTO_ABORTIFHUNG, 2000, NULL ); + free( handleA ); + return 0; + } + + case DBT_DEVTYP_OEM: + break; + default: + FIXME( "unimplemented W to A mapping for %#lx\n", header->dbch_devicetype ); + } + } + + SendMessageTimeoutA( handle, WM_DEVICECHANGE, flags, (LPARAM)header, SMTO_ABORTIFHUNG, 2000, NULL ); + return 0; +} + +static DWORD CALLBACK devnotify_service_callback(HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header) +{ + FIXME("Support for service handles is not yet implemented!\n"); + return 0; +} + +/*********************************************************************** + * RegisterDeviceNotificationA (USER32.@) + * + * See RegisterDeviceNotificationW. + */ +HDEVNOTIFY WINAPI RegisterDeviceNotificationA( HANDLE handle, void *filter, DWORD flags ) +{ + return RegisterDeviceNotificationW( handle, filter, flags ); +} + +/*********************************************************************** + * RegisterDeviceNotificationW (USER32.@) + */ +HDEVNOTIFY WINAPI RegisterDeviceNotificationW( HANDLE handle, void *filter, DWORD flags ) +{ + DEV_BROADCAST_HDR *header = filter; + device_notify_callback callback; + + TRACE("handle %p, filter %p, flags %#lx\n", handle, filter, flags); + + if (flags & ~(DEVICE_NOTIFY_SERVICE_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES)) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return NULL; + } + + if (!(flags & DEVICE_NOTIFY_SERVICE_HANDLE) && !IsWindow( handle )) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return NULL; + } + + if (flags & DEVICE_NOTIFY_SERVICE_HANDLE) + callback = devnotify_service_callback; + else if (IsWindowUnicode( handle )) + callback = devnotify_window_callbackW; + else + callback = devnotify_window_callbackA; + + if (!header) + { + DEV_BROADCAST_HDR dummy = {0}; + return I_ScRegisterDeviceNotification( handle, &dummy, callback ); + } + if (header->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) + { + DEV_BROADCAST_DEVICEINTERFACE_W iface = *(DEV_BROADCAST_DEVICEINTERFACE_W *)header; + + if (flags & DEVICE_NOTIFY_ALL_INTERFACE_CLASSES) + iface.dbcc_size = offsetof( DEV_BROADCAST_DEVICEINTERFACE_W, dbcc_classguid ); + else + iface.dbcc_size = offsetof( DEV_BROADCAST_DEVICEINTERFACE_W, dbcc_name ); + + return I_ScRegisterDeviceNotification( handle, (DEV_BROADCAST_HDR *)&iface, callback ); + } + if (header->dbch_devicetype == DBT_DEVTYP_HANDLE) + { + FIXME( "DBT_DEVTYP_HANDLE not implemented\n" ); + return I_ScRegisterDeviceNotification( handle, header, callback ); + } + + FIXME( "type %#lx not implemented\n", header->dbch_devicetype ); + SetLastError( ERROR_INVALID_DATA ); + return NULL; +} + +/*********************************************************************** + * UnregisterDeviceNotification (USER32.@) + */ +BOOL WINAPI UnregisterDeviceNotification( HDEVNOTIFY handle ) +{ + TRACE("%p\n", handle); + + return I_ScUnregisterDeviceNotification( handle ); +} + +/*********************************************************************** + * GetRawInputDeviceInfoA (USER32.@) + */ +UINT WINAPI GetRawInputDeviceInfoA( HANDLE device, UINT command, void *data, UINT *size ) +{ + TRACE( "device %p, command %#x, data %p, size %p.\n", device, command, data, size ); + + /* RIDI_DEVICENAME size is in chars, not bytes */ + if (command == RIDI_DEVICENAME) + { + WCHAR *nameW; + UINT ret, sizeW; + + if (!size) return ~0U; + + sizeW = *size; + + if (data && sizeW > 0) + nameW = HeapAlloc( GetProcessHeap(), 0, sizeof(WCHAR) * sizeW ); + else + nameW = NULL; + + ret = NtUserGetRawInputDeviceInfo( device, command, nameW, &sizeW ); + + if (ret && ret != ~0U) + WideCharToMultiByte( CP_ACP, 0, nameW, -1, data, *size, NULL, NULL ); + + *size = sizeW; + + HeapFree( GetProcessHeap(), 0, nameW ); + + return ret; + } + + return NtUserGetRawInputDeviceInfo( device, command, data, size ); +} + +/*********************************************************************** + * DefRawInputProc (USER32.@) + */ +LRESULT WINAPI DefRawInputProc( RAWINPUT **data, INT data_count, UINT header_size ) +{ + TRACE( "data %p, data_count %d, header_size %u.\n", data, data_count, header_size ); + + return header_size == sizeof(RAWINPUTHEADER) ? 0 : -1; +} + +/***************************************************************************** + * CloseTouchInputHandle (USER32.@) + */ +BOOL WINAPI CloseTouchInputHandle( HTOUCHINPUT handle ) +{ + FIXME( "handle %p stub!\n", handle ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + +/***************************************************************************** + * GetTouchInputInfo (USER32.@) + */ +BOOL WINAPI GetTouchInputInfo( HTOUCHINPUT handle, UINT count, TOUCHINPUT *ptr, int size ) +{ + FIXME( "handle %p, count %u, ptr %p, size %u stub!\n", handle, count, ptr, size ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + +/********************************************************************** + * IsTouchWindow (USER32.@) + */ +BOOL WINAPI IsTouchWindow( HWND hwnd, ULONG *flags ) +{ + FIXME( "hwnd %p, flags %p stub!\n", hwnd, flags ); + return FALSE; +} + +/***************************************************************************** + * RegisterTouchWindow (USER32.@) + */ +BOOL WINAPI RegisterTouchWindow( HWND hwnd, ULONG flags ) +{ + FIXME( "hwnd %p, flags %#lx stub!\n", hwnd, flags ); + return TRUE; +} + +/***************************************************************************** + * UnregisterTouchWindow (USER32.@) + */ +BOOL WINAPI UnregisterTouchWindow( HWND hwnd ) +{ + FIXME( "hwnd %p stub!\n", hwnd ); + return TRUE; +} + +/***************************************************************************** + * GetGestureInfo (USER32.@) + */ +BOOL WINAPI CloseGestureInfoHandle( HGESTUREINFO handle ) +{ + FIXME( "handle %p stub!\n", handle ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + +/***************************************************************************** + * GetGestureInfo (USER32.@) + */ +BOOL WINAPI GetGestureExtraArgs( HGESTUREINFO handle, UINT count, BYTE *args ) +{ + FIXME( "handle %p, count %u, args %p stub!\n", handle, count, args ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + +/***************************************************************************** + * GetGestureInfo (USER32.@) + */ +BOOL WINAPI GetGestureInfo( HGESTUREINFO handle, GESTUREINFO *ptr ) +{ + FIXME( "handle %p, ptr %p stub!\n", handle, ptr ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + +/***************************************************************************** + * GetGestureConfig (USER32.@) + */ +BOOL WINAPI GetGestureConfig( HWND hwnd, DWORD reserved, DWORD flags, UINT *count, + GESTURECONFIG *config, UINT size ) +{ + FIXME( "handle %p, reserved %#lx, flags %#lx, count %p, config %p, size %u stub!\n", + hwnd, reserved, flags, count, config, size ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + +/********************************************************************** + * SetGestureConfig (USER32.@) + */ +BOOL WINAPI SetGestureConfig( HWND hwnd, DWORD reserved, UINT count, + GESTURECONFIG *config, UINT size ) +{ + FIXME( "handle %p, reserved %#lx, count %u, config %p, size %u stub!\n", + hwnd, reserved, count, config, size ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + +BOOL WINAPI GetPointerTouchInfo( UINT32 id, POINTER_TOUCH_INFO *info ) +{ + FIXME( "id %u, info %p stub!\n", id, info ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + +BOOL WINAPI GetPointerTouchInfoHistory( UINT32 id, UINT32 *count, POINTER_TOUCH_INFO *info ) +{ + FIXME( "id %u, count %p, info %p stub!\n", id, count, info ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + + +/******************************************************************* + * SetForegroundWindow (USER32.@) + */ +BOOL WINAPI SetForegroundWindow( HWND hwnd ) +{ + return NtUserSetForegroundWindow( hwnd ); +} + + +/******************************************************************* + * GetActiveWindow (USER32.@) + */ +HWND WINAPI GetActiveWindow(void) +{ + GUITHREADINFO info; + info.cbSize = sizeof(info); + return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndActive : 0; +} + + +/***************************************************************** + * GetFocus (USER32.@) + */ +HWND WINAPI GetFocus(void) +{ + GUITHREADINFO info; + info.cbSize = sizeof(info); + return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndFocus : 0; +} + + +/******************************************************************* + * SetShellWindow (USER32.@) + */ +BOOL WINAPI SetShellWindow( HWND hwnd ) +{ + return NtUserSetShellWindowEx( hwnd, hwnd ); +} + + +/******************************************************************* + * GetShellWindow (USER32.@) + */ +HWND WINAPI GetShellWindow(void) +{ + return NtUserGetShellWindow(); +} + + +/*********************************************************************** + * SetProgmanWindow (USER32.@) + */ +HWND WINAPI SetProgmanWindow( HWND hwnd ) +{ + return NtUserSetProgmanWindow( hwnd ); +} + + +/*********************************************************************** + * GetProgmanWindow (USER32.@) + */ +HWND WINAPI GetProgmanWindow(void) +{ + return NtUserGetProgmanWindow(); +} + + +/*********************************************************************** + * SetTaskmanWindow (USER32.@) + */ +HWND WINAPI SetTaskmanWindow( HWND hwnd ) +{ + return NtUserSetTaskmanWindow( hwnd ); +} + +/*********************************************************************** + * GetTaskmanWindow (USER32.@) + */ +HWND WINAPI GetTaskmanWindow(void) +{ + return NtUserGetTaskmanWindow(); +} + +HSYNTHETICPOINTERDEVICE WINAPI CreateSyntheticPointerDevice(POINTER_INPUT_TYPE type, ULONG max_count, POINTER_FEEDBACK_MODE mode) +{ + FIXME( "type %ld, max_count %ld, mode %d stub!\n", type, max_count, mode); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return NULL; +} diff --git a/win32ss/user/user32_vista/wine/misc.c b/win32ss/user/user32_vista/wine/misc.c new file mode 100644 index 00000000000..6333fcb48b4 --- /dev/null +++ b/win32ss/user/user32_vista/wine/misc.c @@ -0,0 +1,545 @@ +/* + * Misc USER functions + * + * Copyright 1995 Thomas Sandford + * Copyright 1997 Marcus Meissner + * Copyright 1998 Turchanov Sergey + * Copyright 2019 Micah N Gorrell for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> + +#include "windef.h" +#include "wine/windef16.h" +#include "winbase.h" +#include "wingdi.h" +#include "controls.h" +#include "imm.h" +#include "user_private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(win); + +BOOL WINAPI ImmSetActiveContext(HWND, HIMC, BOOL); + +#define IMM_INIT_MAGIC 0x19650412 +static LRESULT (WINAPI *imm_ime_wnd_proc)( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, BOOL ansi); + +/* USER signal proc flags and codes */ +/* See UserSignalProc for comments */ +#define USIG_FLAGS_WIN32 0x0001 +#define USIG_FLAGS_GUI 0x0002 +#define USIG_FLAGS_FEEDBACK 0x0004 +#define USIG_FLAGS_FAULT 0x0008 + +#define USIG_DLL_UNLOAD_WIN16 0x0001 +#define USIG_DLL_UNLOAD_WIN32 0x0002 +#define USIG_FAULT_DIALOG_PUSH 0x0003 +#define USIG_FAULT_DIALOG_POP 0x0004 +#define USIG_DLL_UNLOAD_ORPHANS 0x0005 +#define USIG_THREAD_INIT 0x0010 +#define USIG_THREAD_EXIT 0x0020 +#define USIG_PROCESS_CREATE 0x0100 +#define USIG_PROCESS_INIT 0x0200 +#define USIG_PROCESS_EXIT 0x0300 +#define USIG_PROCESS_DESTROY 0x0400 +#define USIG_PROCESS_RUNNING 0x0500 +#define USIG_PROCESS_LOADED 0x0600 + +/*********************************************************************** + * SignalProc32 (USER.391) + * UserSignalProc (USER32.@) + * + * The exact meaning of the USER signals is undocumented, but this + * should cover the basic idea: + * + * USIG_DLL_UNLOAD_WIN16 + * This is sent when a 16-bit module is unloaded. + * + * USIG_DLL_UNLOAD_WIN32 + * This is sent when a 32-bit module is unloaded. + * + * USIG_DLL_UNLOAD_ORPHANS + * This is sent after the last Win3.1 module is unloaded, + * to allow removal of orphaned menus. + * + * USIG_FAULT_DIALOG_PUSH + * USIG_FAULT_DIALOG_POP + * These are called to allow USER to prepare for displaying a + * fault dialog, even though the fault might have happened while + * inside a USER critical section. + * + * USIG_THREAD_INIT + * This is called from the context of a new thread, as soon as it + * has started to run. + * + * USIG_THREAD_EXIT + * This is called, still in its context, just before a thread is + * about to terminate. + * + * USIG_PROCESS_CREATE + * This is called, in the parent process context, after a new process + * has been created. + * + * USIG_PROCESS_INIT + * This is called in the new process context, just after the main thread + * has started execution (after the main thread's USIG_THREAD_INIT has + * been sent). + * + * USIG_PROCESS_LOADED + * This is called after the executable file has been loaded into the + * new process context. + * + * USIG_PROCESS_RUNNING + * This is called immediately before the main entry point is called. + * + * USIG_PROCESS_EXIT + * This is called in the context of a process that is about to + * terminate (but before the last thread's USIG_THREAD_EXIT has + * been sent). + * + * USIG_PROCESS_DESTROY + * This is called after a process has terminated. + * + * + * The meaning of the dwFlags bits is as follows: + * + * USIG_FLAGS_WIN32 + * Current process is 32-bit. + * + * USIG_FLAGS_GUI + * Current process is a (Win32) GUI process. + * + * USIG_FLAGS_FEEDBACK + * Current process needs 'feedback' (determined from the STARTUPINFO + * flags STARTF_FORCEONFEEDBACK / STARTF_FORCEOFFFEEDBACK). + * + * USIG_FLAGS_FAULT + * The signal is being sent due to a fault. + */ +WORD WINAPI UserSignalProc( UINT uCode, DWORD dwThreadOrProcessID, + DWORD dwFlags, HMODULE16 hModule ) +{ + FIXME("(%04x, %08lx, %04lx, %04x)\n", + uCode, dwThreadOrProcessID, dwFlags, hModule ); + /* FIXME: Should chain to GdiSignalProc now. */ + return 0; +} + + +/********************************************************************** + * SetLastErrorEx [USER32.@] + * + * Sets the last-error code. + * + * RETURNS + * None. + */ +void WINAPI SetLastErrorEx( + DWORD error, /* [in] Per-thread error code */ + DWORD type) /* [in] Error type */ +{ + TRACE("(0x%08lx, 0x%08lx)\n", error,type); + switch(type) { + case 0: + break; + case SLE_ERROR: + case SLE_MINORERROR: + case SLE_WARNING: + /* Fall through for now */ + default: + FIXME("(error=%08lx, type=%08lx): Unhandled type\n", error,type); + break; + } + SetLastError( error ); +} + +/****************************************************************************** + * GetAltTabInfoA [USER32.@] + */ +BOOL WINAPI GetAltTabInfoA(HWND hwnd, int iItem, PALTTABINFO pati, LPSTR pszItemText, UINT cchItemText) +{ + FIXME("(%p, 0x%08x, %p, %p, 0x%08x)\n", hwnd, iItem, pati, pszItemText, cchItemText); + return FALSE; +} + +/****************************************************************************** + * GetAltTabInfoW [USER32.@] + */ +BOOL WINAPI GetAltTabInfoW(HWND hwnd, int iItem, PALTTABINFO pati, LPWSTR pszItemText, UINT cchItemText) +{ + FIXME("(%p, 0x%08x, %p, %p, 0x%08x)\n", hwnd, iItem, pati, pszItemText, cchItemText); + return FALSE; +} + +/****************************************************************************** + * SetDebugErrorLevel [USER32.@] + * Sets the minimum error level for generating debugging events + * + * PARAMS + * dwLevel [I] Debugging error level + * + * RETURNS + * Nothing. + */ +VOID WINAPI SetDebugErrorLevel( DWORD dwLevel ) +{ + FIXME("(%ld): stub\n", dwLevel); +} + + +/*********************************************************************** + * SetWindowStationUser (USER32.@) + */ +DWORD WINAPI SetWindowStationUser(DWORD x1,DWORD x2) +{ + FIXME("(0x%08lx,0x%08lx),stub!\n",x1,x2); + return 1; +} + +/*********************************************************************** + * RegisterLogonProcess (USER32.@) + */ +DWORD WINAPI RegisterLogonProcess(HANDLE hprocess,BOOL x) +{ + FIXME("(%p,%d),stub!\n",hprocess,x); + return 1; +} + +/*********************************************************************** + * SetLogonNotifyWindow (USER32.@) + */ +DWORD WINAPI SetLogonNotifyWindow(HWINSTA hwinsta,HWND hwnd) +{ + FIXME("(%p,%p),stub!\n",hwinsta,hwnd); + return 1; +} + +/*********************************************************************** + * RegisterSystemThread (USER32.@) + */ +void WINAPI RegisterSystemThread(DWORD flags, DWORD reserved) +{ + FIXME("(%08lx, %08lx)\n", flags, reserved); +} + +/*********************************************************************** + * RegisterShellHookWindow [USER32.@] + */ +BOOL WINAPI RegisterShellHookWindow(HWND hWnd) +{ + FIXME("(%p): stub\n", hWnd); + return FALSE; +} + + +/*********************************************************************** + * DeregisterShellHookWindow [USER32.@] + */ +BOOL WINAPI DeregisterShellHookWindow(HWND hWnd) +{ + FIXME("(%p): stub\n", hWnd); + return FALSE; +} + + +/*********************************************************************** + * RegisterTasklist [USER32.@] + */ +DWORD WINAPI RegisterTasklist (DWORD x) +{ + FIXME("0x%08lx\n",x); + return TRUE; +} + +/*********************************************************************** + * GetAppCompatFlags (USER32.@) + */ +DWORD WINAPI GetAppCompatFlags( HTASK hTask ) +{ + FIXME("(%p) stub\n", hTask); + return 0; +} + +/*********************************************************************** + * GetAppCompatFlags2 (USER32.@) + */ +DWORD WINAPI GetAppCompatFlags2( HTASK hTask ) +{ + FIXME("(%p) stub\n", hTask); + return 0; +} + + +/*********************************************************************** + * AlignRects (USER32.@) + */ +BOOL WINAPI AlignRects(LPRECT rect, DWORD b, DWORD c, DWORD d) +{ + FIXME("(%p, %ld, %ld, %ld): stub\n", rect, b, c, d); + if (rect) + FIXME("rect: %s\n", wine_dbgstr_rect(rect)); + /* Calls OffsetRect */ + return FALSE; +} + + +/*********************************************************************** + * LoadLocalFonts (USER32.@) + */ +VOID WINAPI LoadLocalFonts(VOID) +{ + /* are loaded. */ + return; +} + + +/*********************************************************************** + * User32InitializeImmEntryTable + */ +BOOL WINAPI User32InitializeImmEntryTable(DWORD magic) +{ + HMODULE imm32 = GetModuleHandleW(L"imm32.dll"); + + TRACE("(%lx)\n", magic); + + if (!imm32 || magic != IMM_INIT_MAGIC) + return FALSE; + + if (imm_ime_wnd_proc) + return TRUE; + + /* this part is not compatible with native imm32.dll */ + imm_ime_wnd_proc = (void*)GetProcAddress(imm32, "__wine_ime_wnd_proc"); + if (!imm_ime_wnd_proc) + FIXME("native imm32.dll not supported\n"); + return TRUE; +} + +/********************************************************************** + * WINNLSGetIMEHotkey [USER32.@] + * + */ +UINT WINAPI WINNLSGetIMEHotkey(HWND hwnd) +{ + FIXME("hwnd %p: stub!\n", hwnd); + return 0; /* unknown */ +} + +/********************************************************************** + * WINNLSEnableIME [USER32.@] + * + */ +BOOL WINAPI WINNLSEnableIME(HWND hwnd, BOOL enable) +{ + FIXME("hwnd %p enable %d: stub!\n", hwnd, enable); + return TRUE; /* success (?) */ +} + +/********************************************************************** + * WINNLSGetEnableStatus [USER32.@] + * + */ +BOOL WINAPI WINNLSGetEnableStatus(HWND hwnd) +{ + FIXME("hwnd %p: stub!\n", hwnd); + return TRUE; /* success (?) */ +} + +/********************************************************************** + * SendIMEMessageExA [USER32.@] + * + */ +LRESULT WINAPI SendIMEMessageExA(HWND hwnd, LPARAM lparam) +{ + FIXME("(%p,%Ix): stub\n", hwnd, lparam); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return 0; +} + +/********************************************************************** + * SendIMEMessageExW [USER32.@] + * + */ +LRESULT WINAPI SendIMEMessageExW(HWND hwnd, LPARAM lparam) +{ + FIXME("(%p,%Ix): stub\n", hwnd, lparam); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return 0; +} + +/********************************************************************** + * DisableProcessWindowsGhosting [USER32.@] + * + */ +VOID WINAPI DisableProcessWindowsGhosting(VOID) +{ + FIXME(": stub\n"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return; +} + +/********************************************************************** + * UserHandleGrantAccess [USER32.@] + * + */ +BOOL WINAPI UserHandleGrantAccess(HANDLE handle, HANDLE job, BOOL grant) +{ + FIXME("(%p,%p,%d): stub\n", handle, job, grant); + return TRUE; +} + +/********************************************************************** + * RegisterPowerSettingNotification [USER32.@] + */ +HPOWERNOTIFY WINAPI RegisterPowerSettingNotification(HANDLE recipient, const GUID *guid, DWORD flags) +{ + FIXME("(%p,%s,%lx): stub\n", recipient, debugstr_guid(guid), flags); + return (HPOWERNOTIFY)0xdeadbeef; +} + +/********************************************************************** + * UnregisterPowerSettingNotification [USER32.@] + */ +BOOL WINAPI UnregisterPowerSettingNotification(HPOWERNOTIFY handle) +{ + FIXME("(%p): stub\n", handle); + return TRUE; +} + +/********************************************************************** + * RegisterSuspendResumeNotification (USER32.@) + */ +HPOWERNOTIFY WINAPI RegisterSuspendResumeNotification(HANDLE recipient, DWORD flags) +{ + FIXME("%p, %#lx: stub.\n", recipient, flags); + return (HPOWERNOTIFY)0xdeadbeef; +} + +/********************************************************************** + * UnregisterSuspendResumeNotification (USER32.@) + */ +BOOL WINAPI UnregisterSuspendResumeNotification(HPOWERNOTIFY handle) +{ + FIXME("%p: stub.\n", handle); + return TRUE; +} + +/********************************************************************** + * IsWindowRedirectedForPrint [USER32.@] + */ +BOOL WINAPI IsWindowRedirectedForPrint( HWND hwnd ) +{ + FIXME("(%p): stub\n", hwnd); + return FALSE; +} + +/********************************************************************** + * RegisterPointerDeviceNotifications [USER32.@] + */ +BOOL WINAPI RegisterPointerDeviceNotifications(HWND hwnd, BOOL notifyrange) +{ + FIXME("(%p %d): stub\n", hwnd, notifyrange); + return TRUE; +} + +/********************************************************************** + * GetPointerDevices [USER32.@] + */ +BOOL WINAPI GetPointerDevices(UINT32 *device_count, POINTER_DEVICE_INFO *devices) +{ + FIXME("(%p %p): partial stub\n", device_count, devices); + + if (!device_count) + return FALSE; + + if (devices) + return FALSE; + + *device_count = 0; + return TRUE; +} + +/********************************************************************** + * RegisterTouchHitTestingWindow [USER32.@] + */ +BOOL WINAPI RegisterTouchHitTestingWindow(HWND hwnd, ULONG value) +{ + FIXME("(%p %ld): stub\n", hwnd, value); + return TRUE; +} + +/********************************************************************** + * EvaluateProximityToRect [USER32.@] + */ +BOOL WINAPI EvaluateProximityToRect(const RECT *box, + const TOUCH_HIT_TESTING_INPUT *input, + TOUCH_HIT_TESTING_PROXIMITY_EVALUATION *proximity) +{ + FIXME("(%p,%p,%p): stub\n", box, input, proximity); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +/********************************************************************** + * PackTouchHitTestingProximityEvaluation [USER32.@] + */ +LRESULT WINAPI PackTouchHitTestingProximityEvaluation(const TOUCH_HIT_TESTING_INPUT *input, + const TOUCH_HIT_TESTING_PROXIMITY_EVALUATION *proximity) +{ + FIXME("(%p,%p): stub\n", input, proximity); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return 0; +} + +/********************************************************************** + * GetPointerType [USER32.@] + */ +BOOL WINAPI GetPointerType(UINT32 id, POINTER_INPUT_TYPE *type) +{ + FIXME("(%d %p): stub\n", id, type); + + if(!id || !type) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + *type = PT_MOUSE; + return TRUE; +} + +BOOL WINAPI GetPointerInfo(UINT32 id, POINTER_INFO *info) +{ + FIXME("(%d %p): stub\n", id, info); + + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; +} + +LRESULT WINAPI ImeWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + if (!imm_ime_wnd_proc) return DefWindowProcA(hwnd, msg, wParam, lParam); + return imm_ime_wnd_proc( hwnd, msg, wParam, lParam, TRUE ); +} + +LRESULT WINAPI ImeWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + if (!imm_ime_wnd_proc) return DefWindowProcW(hwnd, msg, wParam, lParam); + return imm_ime_wnd_proc( hwnd, msg, wParam, lParam, FALSE ); +} diff --git a/win32ss/user/user32_vista/wine/win.c b/win32ss/user/user32_vista/wine/win.c new file mode 100644 index 00000000000..99f681a3f9c --- /dev/null +++ b/win32ss/user/user32_vista/wine/win.c @@ -0,0 +1,1731 @@ +/* + * Window related functions + * + * Copyright 1993, 1994 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "user_private.h" +#include "controls.h" +#include "winver.h" +#include "wine/asm.h" +#include "wine/exception.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(win); + + +#ifdef __i386__ +/* Some apps pass a non-stdcall proc to EnumChildWindows, + * so we need a small assembly wrapper to call the proc. + */ +extern LRESULT enum_callback_wrapper( WNDENUMPROC proc, HWND hwnd, LPARAM lparam ); +__ASM_GLOBAL_FUNC( enum_callback_wrapper, + "pushl %ebp\n\t" + __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") + __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") + "movl %esp,%ebp\n\t" + __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") + "pushl 16(%ebp)\n\t" + "pushl 12(%ebp)\n\t" + "call *8(%ebp)\n\t" + "leave\n\t" + __ASM_CFI(".cfi_def_cfa %esp,4\n\t") + __ASM_CFI(".cfi_same_value %ebp\n\t") + "ret" ) +#else +static inline LRESULT enum_callback_wrapper( WNDENUMPROC proc, HWND hwnd, LPARAM lparam ) +{ + return proc( hwnd, lparam ); +} +#endif /* __i386__ */ + +/******************************************************************* + * enum_windows + */ +static BOOL enum_windows( HDESK desktop, HWND hwnd, DWORD tid, BOOL children, + WNDENUMPROC proc, LPARAM param ) +{ + HWND *list; + ULONG i, size = 128; + BOOL ret = !children; /* EnumChildWindows returns FALSE on empty list, the others TRUE */ + NTSTATUS status; + + for (;;) + { + if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return FALSE; + status = NtUserBuildHwndList( desktop, hwnd, children, TRUE, tid, size, list, &size ); + if (!status) break; + HeapFree( GetProcessHeap(), 0, list ); + if (status != STATUS_BUFFER_TOO_SMALL) return FALSE; + } + for (i = 0; i < size && list[i] != HWND_BOTTOM; i++) + { + if (!IsWindow( list[i] )) continue; + if (!(ret = enum_callback_wrapper( proc, list[i], param ))) break; + } + HeapFree( GetProcessHeap(), 0, list ); + return ret; +} + + +/******************************************************************* + * is_desktop_window + * + * Check if window is the desktop or the HWND_MESSAGE top parent. + */ +BOOL is_desktop_window( HWND hwnd ) +{ + struct ntuser_thread_info *thread_info = NtUserGetThreadInfo(); + + if (!hwnd) return FALSE; + if (hwnd == UlongToHandle( thread_info->top_window )) return TRUE; + if (hwnd == UlongToHandle( thread_info->msg_window )) return TRUE; + + if (!HIWORD(hwnd) || HIWORD(hwnd) == 0xffff) + { + if (LOWORD(thread_info->top_window) == LOWORD(hwnd)) return TRUE; + if (LOWORD(thread_info->msg_window) == LOWORD(hwnd)) return TRUE; + } + return FALSE; +} + + +/* check if hwnd is a broadcast magic handle */ +static inline BOOL is_broadcast( HWND hwnd ) +{ + return hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST; +} + + +/*********************************************************************** + * WIN_IsCurrentProcess + * + * Check whether a given window belongs to the current process (and return the full handle). + */ +HWND WIN_IsCurrentProcess( HWND hwnd ) +{ + return UlongToHandle( NtUserCallHwnd( hwnd, NtUserIsCurrentProcessWindow )); +} + + +/*********************************************************************** + * WIN_IsCurrentThread + * + * Check whether a given window belongs to the current thread (and return the full handle). + */ +HWND WIN_IsCurrentThread( HWND hwnd ) +{ + return UlongToHandle( NtUserCallHwnd( hwnd, NtUserIsCurrentThreadWindow )); +} + + +/*********************************************************************** + * WIN_GetFullHandle + * + * Convert a possibly truncated window handle to a full 32-bit handle. + */ +HWND WIN_GetFullHandle( HWND hwnd ) +{ + return UlongToHandle( NtUserCallHwnd( hwnd, NtUserGetFullWindowHandle )); +} + + +/*********************************************************************** + * WIN_SetStyle + * + * Change the style of a window. + */ +ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits ) +{ + /* FIXME: Use SetWindowLong or move callers to win32u instead. + * We use STYLESTRUCT to pass params, but meaning of its field does not match our usage. */ + STYLESTRUCT style = { .styleNew = set_bits, .styleOld = clear_bits }; + return NtUserCallHwndParam( hwnd, (UINT_PTR)&style, NtUserSetWindowStyle ); +} + + +/*********************************************************************** + * dump_window_styles + */ +static void dump_window_styles( DWORD style, DWORD exstyle ) +{ + TRACE( "style:" ); + if(style & WS_POPUP) TRACE(" WS_POPUP"); + if(style & WS_CHILD) TRACE(" WS_CHILD"); + if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE"); + if(style & WS_VISIBLE) TRACE(" WS_VISIBLE"); + if(style & WS_DISABLED) TRACE(" WS_DISABLED"); + if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS"); + if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN"); + if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE"); + if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION"); + else + { + if(style & WS_BORDER) TRACE(" WS_BORDER"); + if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME"); + } + if(style & WS_VSCROLL) TRACE(" WS_VSCROLL"); + if(style & WS_HSCROLL) TRACE(" WS_HSCROLL"); + if(style & WS_SYSMENU) TRACE(" WS_SYSMENU"); + if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME"); + if (style & WS_CHILD) + { + if(style & WS_GROUP) TRACE(" WS_GROUP"); + if(style & WS_TABSTOP) TRACE(" WS_TABSTOP"); + } + else + { + if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX"); + if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX"); + } + + /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */ +#define DUMPED_STYLES \ + ((DWORD)(WS_POPUP | \ + WS_CHILD | \ + WS_MINIMIZE | \ + WS_VISIBLE | \ + WS_DISABLED | \ + WS_CLIPSIBLINGS | \ + WS_CLIPCHILDREN | \ + WS_MAXIMIZE | \ + WS_BORDER | \ + WS_DLGFRAME | \ + WS_VSCROLL | \ + WS_HSCROLL | \ + WS_SYSMENU | \ + WS_THICKFRAME | \ + WS_GROUP | \ + WS_TABSTOP | \ + WS_MINIMIZEBOX | \ + WS_MAXIMIZEBOX)) + + if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES); + TRACE("\n"); +#undef DUMPED_STYLES + + TRACE( "exstyle:" ); + if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME"); + if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT"); + if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY"); + if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST"); + if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES"); + if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT"); + if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD"); + if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW"); + if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE"); + if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE"); + if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP"); + if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT"); + if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING"); + if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR"); + if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT"); + if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE"); + if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW"); + if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED"); + if(exstyle & WS_EX_NOINHERITLAYOUT) TRACE(" WS_EX_NOINHERITLAYOUT"); + if(exstyle & WS_EX_LAYOUTRTL) TRACE(" WS_EX_LAYOUTRTL"); + if(exstyle & WS_EX_COMPOSITED) TRACE(" WS_EX_COMPOSITED"); + if(exstyle & WS_EX_NOACTIVATE) TRACE(" WS_EX_NOACTIVATE"); + +#define DUMPED_EX_STYLES \ + ((DWORD)(WS_EX_DLGMODALFRAME | \ + WS_EX_DRAGDETECT | \ + WS_EX_NOPARENTNOTIFY | \ + WS_EX_TOPMOST | \ + WS_EX_ACCEPTFILES | \ + WS_EX_TRANSPARENT | \ + WS_EX_MDICHILD | \ + WS_EX_TOOLWINDOW | \ + WS_EX_WINDOWEDGE | \ + WS_EX_CLIENTEDGE | \ + WS_EX_CONTEXTHELP | \ + WS_EX_RIGHT | \ + WS_EX_RTLREADING | \ + WS_EX_LEFTSCROLLBAR | \ + WS_EX_CONTROLPARENT | \ + WS_EX_STATICEDGE | \ + WS_EX_APPWINDOW | \ + WS_EX_LAYERED | \ + WS_EX_NOINHERITLAYOUT | \ + WS_EX_LAYOUTRTL | \ + WS_EX_COMPOSITED |\ + WS_EX_NOACTIVATE)) + + if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES); + TRACE("\n"); +#undef DUMPED_EX_STYLES +} + +static BOOL is_default_coord( int x ) +{ + return x == CW_USEDEFAULT || x == 0x8000; +} + +/*********************************************************************** + * WIN_CreateWindowEx + * + * Implementation of CreateWindowEx(). + */ +HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode ) +{ + UNICODE_STRING class, window_name = {0}; + HWND hwnd, top_child = 0; + MDICREATESTRUCTW mdi_cs; + WNDCLASSEXW info; + WCHAR name_buf[8]; + HMENU menu; + + if (!get_class_info( module, className, &info, &class, FALSE )) return FALSE; + + TRACE("%s %s%s%s ex=%08lx style=%08lx %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n", + unicode ? debugstr_w(cs->lpszName) : debugstr_a((LPCSTR)cs->lpszName), + debugstr_w(className), class.Buffer != className ? "->" : "", + class.Buffer != className ? debugstr_wn(class.Buffer, class.Length / sizeof(WCHAR)) : "", + cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy, + cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams ); + if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle ); + + /* Fix the styles for MDI children */ + if (cs->dwExStyle & WS_EX_MDICHILD) + { + POINT pos[2]; + UINT id = 0; + + if (!NtUserGetMDIClientInfo( cs->hwndParent )) + { + WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent); + return 0; + } + + /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children. + * MDICREATESTRUCT members have the originally passed values. + * + * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW + * have the same layout. + */ + mdi_cs.szClass = cs->lpszClass; + mdi_cs.szTitle = cs->lpszName; + mdi_cs.hOwner = cs->hInstance; + mdi_cs.x = cs->x; + mdi_cs.y = cs->y; + mdi_cs.cx = cs->cx; + mdi_cs.cy = cs->cy; + mdi_cs.style = cs->style; + mdi_cs.lParam = (LPARAM)cs->lpCreateParams; + + cs->lpCreateParams = &mdi_cs; + + if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES) + { + if (cs->style & WS_POPUP) + { + TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n"); + return 0; + } + cs->style |= WS_CHILD | WS_CLIPSIBLINGS; + } + else + { + cs->style &= ~WS_POPUP; + cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION | + WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; + } + + top_child = GetWindow(cs->hwndParent, GW_CHILD); + + if (top_child) + { + /* Restore current maximized child */ + if((cs->style & WS_VISIBLE) && IsZoomed(top_child)) + { + TRACE("Restoring current maximized child %p\n", top_child); + if (cs->style & WS_MAXIMIZE) + { + /* if the new window is maximized don't bother repainting */ + SendMessageW( top_child, WM_SETREDRAW, FALSE, 0 ); + NtUserShowWindow( top_child, SW_SHOWNORMAL ); + SendMessageW( top_child, WM_SETREDRAW, TRUE, 0 ); + } + else NtUserShowWindow( top_child, SW_SHOWNORMAL ); + } + } + + MDI_CalcDefaultChildPos( cs->hwndParent, -1, pos, 0, &id ); + if (!(cs->style & WS_POPUP)) cs->hMenu = ULongToHandle(id); + + TRACE( "MDI child id %04x\n", id ); + + if (cs->style & (WS_CHILD | WS_POPUP)) + { + if (is_default_coord( cs->x )) + { + cs->x = pos[0].x; + cs->y = pos[0].y; + } + if (is_default_coord( cs->cx ) || !cs->cx) cs->cx = pos[1].x; + if (is_default_coord( cs->cy ) || !cs->cy) cs->cy = pos[1].y; + } + } + + if (!unicode && cs->lpszName) + { + const char *nameA = (const char *)cs->lpszName; + /* resource ID string is a special case */ + if (nameA[0] == '\xff') + { + name_buf[0] = 0xffff; + name_buf[1] = MAKEWORD( nameA[1], nameA[2] ); + name_buf[2] = 0; + RtlInitUnicodeString( &window_name, name_buf ); + } + else if (!RtlCreateUnicodeStringFromAsciiz( &window_name, (const char *)cs->lpszName )) + return 0; + } + else RtlInitUnicodeString( &window_name, cs->lpszName ); + + menu = cs->hMenu; + if (!menu && info.lpszMenuName && (cs->style & (WS_CHILD | WS_POPUP)) != WS_CHILD) + menu = LoadMenuW( cs->hInstance, info.lpszMenuName ); + + hwnd = NtUserCreateWindowEx( cs->dwExStyle, &class, NULL, &window_name, cs->style, + cs->x, cs->y, cs->cx, cs->cy, cs->hwndParent, menu, module, + cs->lpCreateParams, 0, cs->hInstance, 0, !unicode ); + if (!hwnd && menu && menu != cs->hMenu) NtUserDestroyMenu( menu ); + if (!unicode && window_name.Buffer != name_buf) RtlFreeUnicodeString( &window_name ); + return hwnd; +} + + +/*********************************************************************** + * CreateWindowExA (USER32.@) + */ +HWND WINAPI DECLSPEC_HOTPATCH CreateWindowExA( DWORD exStyle, LPCSTR className, + LPCSTR windowName, DWORD style, INT x, + INT y, INT width, INT height, + HWND parent, HMENU menu, + HINSTANCE instance, LPVOID data ) +{ + CREATESTRUCTA cs; + + cs.lpCreateParams = data; + cs.hInstance = instance; + cs.hMenu = menu; + cs.hwndParent = parent; + cs.x = x; + cs.y = y; + cs.cx = width; + cs.cy = height; + cs.style = style; + cs.lpszName = windowName; + cs.lpszClass = className; + cs.dwExStyle = exStyle; + + if (!IS_INTRESOURCE(className)) + { + WCHAR bufferW[256]; + if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, ARRAY_SIZE( bufferW ))) + return 0; + return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE ); + } + /* Note: we rely on the fact that CREATESTRUCTA and */ + /* CREATESTRUCTW have the same layout. */ + return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE ); +} + + +/*********************************************************************** + * CreateWindowExW (USER32.@) + */ +HWND WINAPI DECLSPEC_HOTPATCH CreateWindowExW( DWORD exStyle, LPCWSTR className, + LPCWSTR windowName, DWORD style, INT x, + INT y, INT width, INT height, + HWND parent, HMENU menu, + HINSTANCE instance, LPVOID data ) +{ + CREATESTRUCTW cs; + + cs.lpCreateParams = data; + cs.hInstance = instance; + cs.hMenu = menu; + cs.hwndParent = parent; + cs.x = x; + cs.y = y; + cs.cx = width; + cs.cy = height; + cs.style = style; + cs.lpszName = windowName; + cs.lpszClass = className; + cs.dwExStyle = exStyle; + + return wow_handlers.create_window( &cs, className, instance, TRUE ); +} + + +/*********************************************************************** + * CloseWindow (USER32.@) + */ +BOOL WINAPI CloseWindow( HWND hwnd ) +{ + if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE; + NtUserShowWindow( hwnd, SW_MINIMIZE ); + return TRUE; +} + + +/*********************************************************************** + * OpenIcon (USER32.@) + */ +BOOL WINAPI OpenIcon( HWND hwnd ) +{ + if (!IsIconic( hwnd )) return FALSE; + NtUserShowWindow( hwnd, SW_SHOWNORMAL ); + return TRUE; +} + + +/*********************************************************************** + * FindWindowExW (USER32.@) + */ +HWND WINAPI FindWindowExW( HWND parent, HWND child, const WCHAR *class, const WCHAR *title ) +{ + UNICODE_STRING class_str, title_str; + + if (title) RtlInitUnicodeString( &title_str, title ); + + if (class) + { + if (IS_INTRESOURCE(class)) + { + class_str.Buffer = (WCHAR *)class; + class_str.Length = class_str.MaximumLength = 0; + } + else RtlInitUnicodeString( &class_str, class ); + } + + return NtUserFindWindowEx( parent, child, class ? &class_str : NULL, + title ? &title_str : NULL, 0 ); +} + + + +/*********************************************************************** + * FindWindowA (USER32.@) + */ +HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title ) +{ + HWND ret = FindWindowExA( 0, 0, className, title ); + if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS); + return ret; +} + + +/*********************************************************************** + * FindWindowExA (USER32.@) + */ +HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title ) +{ + LPWSTR titleW = NULL; + HWND hwnd = 0; + + if (title) + { + DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 ); + if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0; + MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len ); + } + + if (!IS_INTRESOURCE(className)) + { + WCHAR classW[256]; + if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, ARRAY_SIZE( classW ))) + hwnd = FindWindowExW( parent, child, classW, titleW ); + } + else + { + hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW ); + } + + HeapFree( GetProcessHeap(), 0, titleW ); + return hwnd; +} + + +/*********************************************************************** + * FindWindowW (USER32.@) + */ +HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title ) +{ + return FindWindowExW( 0, 0, className, title ); +} + + +/********************************************************************** + * GetDesktopWindow (USER32.@) + */ +HWND WINAPI GetDesktopWindow(void) +{ + struct ntuser_thread_info *thread_info = NtUserGetThreadInfo(); + + if (thread_info->top_window) return UlongToHandle( thread_info->top_window ); + return NtUserGetDesktopWindow(); +} + + +/******************************************************************* + * EnableWindow (USER32.@) + */ +BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable ) +{ + return NtUserEnableWindow( hwnd, enable ); +} + + +/*********************************************************************** + * IsWindowEnabled (USER32.@) + */ +BOOL WINAPI IsWindowEnabled( HWND hwnd ) +{ + return NtUserIsWindowEnabled( hwnd ); +} + +/*********************************************************************** + * IsWindowUnicode (USER32.@) + */ +BOOL WINAPI IsWindowUnicode( HWND hwnd ) +{ + return NtUserIsWindowUnicode( hwnd ); +} + + +/*********************************************************************** + * GetWindowDpiAwarenessContext (USER32.@) + */ +DPI_AWARENESS_CONTEXT WINAPI GetWindowDpiAwarenessContext( HWND hwnd ) +{ + return LongToHandle( NtUserGetWindowDpiAwarenessContext( hwnd ) ); +} + +/*********************************************************************** + * GetDpiAwarenessContextForProcess (USER32.@) + */ +DPI_AWARENESS_CONTEXT WINAPI GetDpiAwarenessContextForProcess(HANDLE process) +{ + return LongToHandle( NtUserGetProcessDpiAwarenessContext( process ) ); +} + +/*********************************************************************** + * GetWindowDpiHostingBehavior (USER32.@) + */ +DPI_HOSTING_BEHAVIOR WINAPI GetWindowDpiHostingBehavior( HWND hwnd ) +{ + FIXME("(%p): stub\n", hwnd); + return DPI_HOSTING_BEHAVIOR_DEFAULT; +} + + +static LONG_PTR get_window_long_ptr( HWND hwnd, int offset, LONG_PTR ret, BOOL ansi ) +{ + if (offset == DWLP_DLGPROC && NtUserGetDialogInfo( hwnd )) + { + DLGPROC proc = NtUserGetDialogProc( (DLGPROC)ret, ansi ); + if (proc && proc != WINPROC_PROC16) return (LONG_PTR)proc; + } + return ret; +} + + +static LONG_PTR set_dialog_proc( HWND hwnd, LONG_PTR newval, BOOL ansi ) +{ + DLGPROC proc; + LONG_PTR ret; + newval = NtUserCallTwoParam( newval, ansi, NtUserAllocWinProc ); + ret = NtUserSetWindowLongPtr( hwnd, DWLP_DLGPROC, newval, ansi ); + proc = NtUserGetDialogProc( (DLGPROC)ret, ansi ); + if (proc) ret = (UINT_PTR)proc; + return ret; +} + + +/*********************************************************************** + * GetDpiForWindow (USER32.@) + */ +UINT WINAPI GetDpiForWindow( HWND hwnd ) +{ + return NtUserGetDpiForWindow( hwnd ); +} + + +/*********************************************************************** + * SwitchToThisWindow (USER32.@) + */ +void WINAPI SwitchToThisWindow( HWND hwnd, BOOL alt_tab ) +{ + if (IsIconic( hwnd )) NtUserShowWindow( hwnd, SW_RESTORE ); + else BringWindowToTop( hwnd ); +} + + +/*********************************************************************** + * GetWindowRect (USER32.@) + */ +BOOL WINAPI GetWindowRect( HWND hwnd, RECT *rect ) +{ + UINT dpi = NTUSER_DPI_CONTEXT_GET_DPI( (UINT_PTR)GetThreadDpiAwarenessContext() ); + BOOL ret = NtUserGetWindowRect( hwnd, rect, dpi ); + if (ret) TRACE( "hwnd %p %s\n", hwnd, wine_dbgstr_rect(rect) ); + return ret; +} + + +/*********************************************************************** + * GetWindowRgn (USER32.@) + */ +int WINAPI GetWindowRgn( HWND hwnd, HRGN hrgn ) +{ + return NtUserGetWindowRgnEx( hwnd, hrgn, 0 ); +} + + +/*********************************************************************** + * GetWindowRgnBox (USER32.@) + */ +int WINAPI GetWindowRgnBox( HWND hwnd, RECT *rect ) +{ + int ret = ERROR; + HRGN hrgn; + + if (!rect) + return ERROR; + + if ((hrgn = CreateRectRgn( 0, 0, 0, 0 ))) + { + if ((ret = GetWindowRgn( hwnd, hrgn )) != ERROR ) + ret = GetRgnBox( hrgn, rect ); + DeleteObject( hrgn ); + } + + return ret; +} + + +/*********************************************************************** + * GetClientRect (USER32.@) + */ +BOOL WINAPI GetClientRect( HWND hwnd, RECT *rect ) +{ + UINT dpi = NTUSER_DPI_CONTEXT_GET_DPI( (UINT_PTR)GetThreadDpiAwarenessContext() ); + return NtUserGetClientRect( hwnd, rect, dpi ); +} + + +/******************************************************************* + * WindowFromPoint (USER32.@) + */ +HWND WINAPI WindowFromPoint( POINT pt ) +{ + return NtUserWindowFromPoint( pt.x, pt.y ); +} + + +/******************************************************************* + * ChildWindowFromPoint (USER32.@) + */ +HWND WINAPI ChildWindowFromPoint( HWND parent, POINT pt ) +{ + return NtUserChildWindowFromPointEx( parent, pt.x, pt.y, CWP_ALL ); +} + +/******************************************************************* + * RealChildWindowFromPoint (USER32.@) + */ +HWND WINAPI RealChildWindowFromPoint( HWND parent, POINT pt ) +{ + return NtUserRealChildWindowFromPoint( parent, pt.x, pt.y ); +} + +/******************************************************************* + * ChildWindowFromPointEx (USER32.@) + */ +HWND WINAPI ChildWindowFromPointEx( HWND parent, POINT pt, UINT flags ) +{ + return NtUserChildWindowFromPointEx( parent, pt.x, pt.y, flags ); +} + + +/******************************************************************* + * MapWindowPoints (USER32.@) + */ +INT WINAPI MapWindowPoints( HWND hwnd_from, HWND hwnd_to, POINT *points, UINT count ) +{ + UINT dpi = NTUSER_DPI_CONTEXT_GET_DPI( (UINT_PTR)GetThreadDpiAwarenessContext() ); + return NtUserMapWindowPoints( hwnd_from, hwnd_to, points, count, dpi ); +} + + +/******************************************************************* + * ClientToScreen (USER32.@) + */ +BOOL WINAPI ClientToScreen( HWND hwnd, POINT *pt ) +{ + return NtUserClientToScreen( hwnd, pt ); +} + + +/******************************************************************* + * ScreenToClient (USER32.@) + */ +BOOL WINAPI ScreenToClient( HWND hwnd, POINT *pt ) +{ + return NtUserScreenToClient( hwnd, pt ); +} + + +/*********************************************************************** + * IsIconic (USER32.@) + */ +BOOL WINAPI IsIconic( HWND hwnd ) +{ + return (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE) != 0; +} + + +/*********************************************************************** + * IsZoomed (USER32.@) + */ +BOOL WINAPI IsZoomed( HWND hwnd ) +{ + return (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE) != 0; +} + + +/******************************************************************* + * AllowSetForegroundWindow (USER32.@) + */ +BOOL WINAPI AllowSetForegroundWindow( DWORD procid ) +{ + /* FIXME: If Win98/2000 style SetForegroundWindow behavior is + * implemented, then fix this function. */ + return TRUE; +} + + +/******************************************************************* + * LockSetForegroundWindow (USER32.@) + */ +BOOL WINAPI LockSetForegroundWindow( UINT lockcode ) +{ + /* FIXME: If Win98/2000 style SetForegroundWindow behavior is + * implemented, then fix this function. */ + return TRUE; +} + + +/*********************************************************************** + * BringWindowToTop (USER32.@) + */ +BOOL WINAPI BringWindowToTop( HWND hwnd ) +{ + return NtUserSetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE ); +} + + +/*********************************************************************** + * AnimateWindow (USER32.@) + */ +BOOL WINAPI AnimateWindow( HWND hwnd, DWORD time, DWORD flags ) +{ + FIXME( "partial stub\n" ); + + /* If trying to show/hide and it's already shown/hidden or invalid window, + * fail with invalid parameter. */ + if (!IsWindow( hwnd ) || (!(flags & AW_HIDE)) == IsWindowVisible( hwnd )) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + NtUserShowWindow( hwnd, (flags & AW_HIDE) ? SW_HIDE : ((flags & AW_ACTIVATE) ? SW_SHOW : SW_SHOWNA) ); + return TRUE; +} + + +/*********************************************************************** + * BeginDeferWindowPos (USER32.@) + */ +HDWP WINAPI BeginDeferWindowPos( INT count ) +{ + return NtUserBeginDeferWindowPos( count ); +} + + +/*********************************************************************** + * DeferWindowPos (USER32.@) + */ +HDWP WINAPI DeferWindowPos( HDWP hdwp, HWND hwnd, HWND after, INT x, INT y, + INT cx, INT cy, UINT flags ) +{ + return NtUserDeferWindowPosAndBand( hdwp, hwnd, after, x, y, cx, cy, flags, 0, 0 ); +} + + +/*********************************************************************** + * EndDeferWindowPos (USER32.@) + */ +BOOL WINAPI EndDeferWindowPos( HDWP hdwp ) +{ + return NtUserEndDeferWindowPosEx( hdwp, FALSE ); +} + + +/*********************************************************************** + * ArrangeIconicWindows (USER32.@) + */ +UINT WINAPI ArrangeIconicWindows( HWND parent ) +{ + return NtUserArrangeIconicWindows( parent ); +} + + +/********************************************************************** + * GetWindowWord (USER32.@) + */ +WORD WINAPI GetWindowWord( HWND hwnd, INT offset ) +{ + return NtUserGetWindowWord( hwnd, offset ); +} + + +/********************************************************************** + * GetWindowLongA (USER32.@) + */ + +#ifdef __i386__ + +/* This wrapper is here to workaround a ntlea quirk. First of all, ntlea + * checks whether GetWindowLongA starts with the Win32 hotpatchable prologue, + * if it can find that, it will use a hooking strategy more difficult for us + * to deal with. Secondly, it assumes what follows the prologue is a `pushl $-2`, + * and will try to skip over this instruction when calling `GetWindowLongA`, + * (i.e. it tries to jump to `GetWindowLongA + 7`, 5 bytes for the prologue, 2 + * bytes for the `pushl`.). We have to anticipate that and make sure the result + * of doing this won't be a messed up stack, or a desynced PC. + */ +__ASM_STDCALL_FUNC( GetWindowLongA, 8, + ".byte 0x8b, 0xff, 0x55, 0x8b, 0xec\n" /* Win32 hotpatchable prologue. */ + "pushl $-2\n" + "addl $4, %esp\n" + "popl %ebp\n" + "jmp " __ASM_STDCALL("get_window_longA", 8) ) +LONG WINAPI get_window_longA( HWND hwnd, INT offset ) +#else +LONG WINAPI DECLSPEC_HOTPATCH GetWindowLongA( HWND hwnd, INT offset ) +#endif +{ + switch (offset) + { +#ifdef _WIN64 + case GWLP_WNDPROC: + case GWLP_HINSTANCE: + case GWLP_HWNDPARENT: + WARN( "Invalid offset %d\n", offset ); + SetLastError( ERROR_INVALID_INDEX ); + return 0; +#endif + default: + if (sizeof(void *) == sizeof(LONG)) + { + LONG_PTR ret = NtUserGetWindowLongA( hwnd, offset ); + return get_window_long_ptr( hwnd, offset, ret, TRUE ); + } + return NtUserGetWindowLongA( hwnd, offset ); + } +} + + +/********************************************************************** + * GetWindowLongW (USER32.@) + */ +LONG WINAPI GetWindowLongW( HWND hwnd, INT offset ) +{ + switch (offset) + { +#ifdef _WIN64 + case GWLP_WNDPROC: + case GWLP_HINSTANCE: + case GWLP_HWNDPARENT: + WARN( "Invalid offset %d\n", offset ); + SetLastError( ERROR_INVALID_INDEX ); + return 0; +#endif + default: + if (sizeof(void *) == sizeof(LONG)) + { + LONG_PTR ret = NtUserGetWindowLongW( hwnd, offset ); + return get_window_long_ptr( hwnd, offset, ret, FALSE ); + } + return NtUserGetWindowLongW( hwnd, offset ); + } +} + + +/********************************************************************** + * SetWindowLongA (USER32.@) + * + * See SetWindowLongW. + */ +LONG WINAPI DECLSPEC_HOTPATCH SetWindowLongA( HWND hwnd, INT offset, LONG newval ) +{ + switch (offset) + { +#ifdef _WIN64 + case GWLP_WNDPROC: + case GWLP_HINSTANCE: + case GWLP_HWNDPARENT: + WARN( "Invalid offset %d\n", offset ); + SetLastError( ERROR_INVALID_INDEX ); + return 0; +#else + case DWLP_DLGPROC: + if (NtUserGetDialogInfo( hwnd )) return set_dialog_proc( hwnd, newval, TRUE ); + /* fall through */ +#endif + default: + return NtUserSetWindowLong( hwnd, offset, newval, TRUE ); + } +} + + +/********************************************************************** + * SetWindowLongW (USER32.@) Set window attribute + * + * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long) + * value in a window's extra memory. + * + * The _hwnd_ parameter specifies the handle to a window that + * has extra memory. The _newval_ parameter contains the new + * attribute or extra memory value. If positive, the _offset_ + * parameter is the byte-addressed location in the window's extra + * memory to set. If negative, _offset_ specifies the window + * attribute to set, and should be one of the following values: + * + * GWL_EXSTYLE The window's extended window style + * + * GWL_STYLE The window's window style. + * + * GWLP_WNDPROC Pointer to the window's window procedure. + * + * GWLP_HINSTANCE The window's application instance handle. + * + * GWLP_ID The window's identifier. + * + * GWLP_USERDATA The window's user-specified data. + * + * If the window is a dialog box, the _offset_ parameter can be one of + * the following values: + * + * DWLP_DLGPROC The address of the window's dialog box procedure. + * + * DWLP_MSGRESULT The return value of a message + * that the dialog box procedure processed. + * + * DWLP_USER Application specific information. + * + * RETURNS + * + * If successful, returns the previous value located at _offset_. Otherwise, + * returns 0. + * + * NOTES + * + * Extra memory for a window class is specified by a nonzero cbWndExtra + * parameter of the WNDCLASS structure passed to RegisterClass() at the + * time of class creation. + * + * Using GWL_WNDPROC to set a new window procedure effectively creates + * a window subclass. Use CallWindowProc() in the new windows procedure + * to pass messages to the superclass's window procedure. + * + * The user data is reserved for use by the application which created + * the window. + * + * Do not use GWL_STYLE to change the window's WS_DISABLED style; + * instead, call the EnableWindow() function to change the window's + * disabled state. + * + * Do not use GWL_HWNDPARENT to reset the window's parent, use + * SetParent() instead. + * + * Win95: + * When offset is GWL_STYLE and the calling app's ver is 4.0, + * it sends WM_STYLECHANGING before changing the settings + * and WM_STYLECHANGED afterwards. + * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST. + */ +LONG WINAPI DECLSPEC_HOTPATCH SetWindowLongW( + HWND hwnd, /* [in] window to alter */ + INT offset, /* [in] offset, in bytes, of location to alter */ + LONG newval /* [in] new value of location */ +) +{ + switch (offset) + { +#ifdef _WIN64 + case GWLP_WNDPROC: + case GWLP_HINSTANCE: + case GWLP_HWNDPARENT: + WARN("Invalid offset %d\n", offset ); + SetLastError( ERROR_INVALID_INDEX ); + return 0; +#else + case DWLP_DLGPROC: + if (NtUserGetDialogInfo( hwnd )) return set_dialog_proc( hwnd, newval, FALSE ); + /* fall through */ +#endif + default: + return NtUserSetWindowLong( hwnd, offset, newval, FALSE ); + } +} + + +/******************************************************************* + * GetWindowTextA (USER32.@) + */ +INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount ) +{ + WCHAR *buffer; + int ret = 0; + + if (!lpString || nMaxCount <= 0) return 0; + + __TRY + { + lpString[0] = 0; + + if (WIN_IsCurrentProcess( hwnd )) + { + ret = (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString ); + } + else if ((buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) + { + /* when window belongs to other process, don't send a message */ + NtUserInternalGetWindowText( hwnd, buffer, nMaxCount ); + if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL )) + lpString[nMaxCount-1] = 0; + HeapFree( GetProcessHeap(), 0, buffer ); + ret = strlen(lpString); + } + } + __EXCEPT_PAGE_FAULT + { + ret = 0; + } + __ENDTRY + + return ret; +} + + +/******************************************************************* + * GetWindowTextW (USER32.@) + */ +INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount ) +{ + int ret; + + if (!lpString || nMaxCount <= 0) return 0; + + __TRY + { + lpString[0] = 0; + + if (WIN_IsCurrentProcess( hwnd )) + { + ret = (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString ); + } + else + { + /* when window belongs to other process, don't send a message */ + ret = NtUserInternalGetWindowText( hwnd, lpString, nMaxCount ); + } + } + __EXCEPT_PAGE_FAULT + { + ret = 0; + } + __ENDTRY + + return ret; +} + + +/******************************************************************* + * SetWindowTextA (USER32.@) + * SetWindowText (USER32.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH SetWindowTextA( HWND hwnd, LPCSTR lpString ) +{ + if (is_broadcast(hwnd)) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + if (!WIN_IsCurrentProcess( hwnd )) + WARN( "setting text %s of other process window %p should not use SendMessage\n", + debugstr_a(lpString), hwnd ); + return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString ); +} + + +/******************************************************************* + * SetWindowTextW (USER32.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH SetWindowTextW( HWND hwnd, LPCWSTR lpString ) +{ + if (is_broadcast(hwnd)) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + if (!WIN_IsCurrentProcess( hwnd )) + WARN( "setting text %s of other process window %p should not use SendMessage\n", + debugstr_w(lpString), hwnd ); + return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString ); +} + + +/******************************************************************* + * GetWindowTextLengthA (USER32.@) + */ +INT WINAPI GetWindowTextLengthA( HWND hwnd ) +{ + CPINFO info; + + if (WIN_IsCurrentProcess( hwnd )) return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 ); + + /* when window belongs to other process, don't send a message */ + GetCPInfo( CP_ACP, &info ); + return NtUserGetWindowTextLength( hwnd ) * info.MaxCharSize; +} + +/******************************************************************* + * GetWindowTextLengthW (USER32.@) + */ +INT WINAPI GetWindowTextLengthW( HWND hwnd ) +{ + if (WIN_IsCurrentProcess( hwnd )) return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 ); + + /* when window belongs to other process, don't send a message */ + return NtUserGetWindowTextLength( hwnd ); +} + + +/******************************************************************* + * IsWindow (USER32.@) + */ +BOOL WINAPI IsWindow( HWND hwnd ) +{ + return NtUserIsWindow( hwnd ); +} + + +/*********************************************************************** + * GetWindowThreadProcessId (USER32.@) + */ +DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process ) +{ + return NtUserGetWindowThread( hwnd, process ); +} + + +/***************************************************************** + * GetParent (USER32.@) + */ +HWND WINAPI GetParent( HWND hwnd ) +{ + return NtUserGetParent( hwnd ); +} + + +/******************************************************************* + * IsChild (USER32.@) + */ +BOOL WINAPI IsChild( HWND parent, HWND child ) +{ + return NtUserIsChild( parent, child ); +} + + +/*********************************************************************** + * IsWindowVisible (USER32.@) + */ +BOOL WINAPI IsWindowVisible( HWND hwnd ) +{ + return NtUserIsWindowVisible( hwnd ); +} + + +/******************************************************************* + * GetTopWindow (USER32.@) + */ +HWND WINAPI GetTopWindow( HWND hwnd ) +{ + if (!hwnd) hwnd = GetDesktopWindow(); + return GetWindow( hwnd, GW_CHILD ); +} + + +/******************************************************************* + * GetWindow (USER32.@) + */ +HWND WINAPI GetWindow( HWND hwnd, UINT rel ) +{ + return NtUserGetWindowRelative( hwnd, rel ); +} + + +/******************************************************************* + * ShowOwnedPopups (USER32.@) + */ +BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL show ) +{ + return NtUserShowOwnedPopups( owner, show ); +} + + +/******************************************************************* + * GetLastActivePopup (USER32.@) + */ +HWND WINAPI GetLastActivePopup( HWND hwnd ) +{ + return NtUserGetLastActivePopup( hwnd ); +} + + +/******************************************************************* + * WIN_ListChildren + * + * Build an array of the children of a given window. The array must be + * freed with HeapFree. Returns NULL when no windows are found. + */ +HWND *WIN_ListChildren( HWND hwnd ) +{ + HWND *list; + ULONG size = 128; + NTSTATUS status; + + if (!(hwnd = GetWindow( hwnd, GW_CHILD ))) return NULL; + + for (;;) + { + if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL; + status = NtUserBuildHwndList( 0, hwnd, FALSE, TRUE, 0, size, list, &size ); + if (!status && size > 1) break; + HeapFree( GetProcessHeap(), 0, list ); + if (status != STATUS_BUFFER_TOO_SMALL) return NULL; + } + list[size - 1] = 0; + return list; +} + + +/******************************************************************* + * EnumWindows (USER32.@) + */ +BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam ) +{ + return enum_windows( 0, 0, 0, FALSE, lpEnumFunc, lParam ); +} + + +/********************************************************************** + * EnumThreadWindows (USER32.@) + */ +BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam ) +{ + return enum_windows( 0, 0, id, FALSE, func, lParam ); +} + + +/*********************************************************************** + * EnumDesktopWindows (USER32.@) + */ +BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam ) +{ + return enum_windows( desktop, 0, 0, FALSE, func, lparam ); +} + + +/********************************************************************** + * EnumChildWindows (USER32.@) + */ +BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam ) +{ + return enum_windows( 0, parent, 0, TRUE, func, lParam ); +} + + +/******************************************************************* + * AnyPopup (USER32.@) + */ +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; +} + + +/******************************************************************* + * FlashWindow (USER32.@) + */ +BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert ) +{ + FLASHWINFO finfo; + + finfo.cbSize = sizeof(FLASHWINFO); + finfo.dwFlags = bInvert ? FLASHW_ALL : FLASHW_STOP; + finfo.uCount = 1; + finfo.dwTimeout = 0; + finfo.hwnd = hWnd; + return NtUserFlashWindowEx( &finfo ); +} + + +/******************************************************************* + * GetWindowContextHelpId (USER32.@) + */ +DWORD WINAPI GetWindowContextHelpId( HWND hwnd ) +{ + return NtUserGetWindowContextHelpId( hwnd ); +} + + +/******************************************************************* + * SetWindowContextHelpId (USER32.@) + */ +BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id ) +{ + return NtUserSetWindowContextHelpId( hwnd, id ); +} + + +/******************************************************************* + * DragDetect (USER32.@) + */ +BOOL WINAPI DragDetect( HWND hwnd, POINT pt ) +{ + return NtUserDragDetect( hwnd, pt.x, pt.y ); +} + +/****************************************************************************** + * GetWindowModuleFileNameA (USER32.@) + */ +UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size ) +{ + HINSTANCE hinst; + + TRACE( "%p, %p, %u\n", hwnd, module, size ); + + if (!WIN_IsCurrentProcess( hwnd )) + { + SetLastError( ERROR_INVALID_WINDOW_HANDLE ); + return 0; + } + + hinst = (HINSTANCE)GetWindowLongPtrA( hwnd, GWLP_HINSTANCE ); + return GetModuleFileNameA( hinst, module, size ); +} + +/****************************************************************************** + * GetWindowModuleFileNameW (USER32.@) + */ +UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size ) +{ + HINSTANCE hinst; + + TRACE( "%p, %p, %u\n", hwnd, module, size ); + + if (!WIN_IsCurrentProcess( hwnd )) + { + SetLastError( ERROR_INVALID_WINDOW_HANDLE ); + return 0; + } + + hinst = (HINSTANCE)GetWindowLongPtrW( hwnd, GWLP_HINSTANCE ); + return GetModuleFileNameW( hinst, module, size ); +} + +/****************************************************************************** + * GetWindowInfo (USER32.@) + * + * Note: tests show that Windows doesn't check cbSize of the structure. + */ +BOOL WINAPI DECLSPEC_HOTPATCH GetWindowInfo( HWND hwnd, WINDOWINFO *info ) +{ + return NtUserGetWindowInfo( hwnd, info ); +} + +/***************************************************************************** + * UpdateLayeredWindowIndirect (USER32.@) + */ +BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info ) +{ + if (!info || info->cbSize != sizeof(*info)) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + return NtUserUpdateLayeredWindow( hwnd, info->hdcDst, info->pptDst, info->psize, + info->hdcSrc, info->pptSrc, info->crKey, + info->pblend, info->dwFlags, info->prcDirty ); +} + + +/***************************************************************************** + * UpdateLayeredWindow (USER32.@) + */ +BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize, + HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend, + DWORD flags) +{ + UPDATELAYEREDWINDOWINFO info; + + if (flags & ULW_EX_NORESIZE) /* only valid for UpdateLayeredWindowIndirect */ + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + info.cbSize = sizeof(info); + info.hdcDst = hdcDst; + info.pptDst = pptDst; + info.psize = psize; + info.hdcSrc = hdcSrc; + info.pptSrc = pptSrc; + info.crKey = crKey; + info.pblend = pblend; + info.dwFlags = flags; + info.prcDirty = NULL; + return UpdateLayeredWindowIndirect( hwnd, &info ); +} + + +/****************************************************************************** + * GetProcessDefaultLayout [USER32.@] + * + * Gets the default layout for parentless windows. + */ +BOOL WINAPI GetProcessDefaultLayout( DWORD *layout ) +{ + if (!layout) + { + SetLastError( ERROR_NOACCESS ); + return FALSE; + } + *layout = NtUserGetProcessDefaultLayout(); + if (*layout == ~0u) + { + WCHAR *str, buffer[MAX_PATH]; + DWORD i, version_layout = 0; + UINT len; + DWORD user_lang = GetUserDefaultLangID(); + DWORD *languages; + void *data = NULL; + + GetModuleFileNameW( 0, buffer, MAX_PATH ); + if (!(len = GetFileVersionInfoSizeW( buffer, NULL ))) goto done; + if (!(data = HeapAlloc( GetProcessHeap(), 0, len ))) goto done; + if (!GetFileVersionInfoW( buffer, 0, len, data )) goto done; + if (!VerQueryValueW( data, L"\\VarFileInfo\\Translation", (void **)&languages, &len ) || !len) goto done; + + len /= sizeof(DWORD); + for (i = 0; i < len; i++) if (LOWORD(languages[i]) == user_lang) break; + if (i == len) /* try neutral language */ + for (i = 0; i < len; i++) + if (LOWORD(languages[i]) == MAKELANGID( PRIMARYLANGID(user_lang), SUBLANG_NEUTRAL )) break; + if (i == len) i = 0; /* default to the first one */ + + swprintf( buffer, ARRAY_SIZE(buffer), L"\\StringFileInfo\\%04x%04x\\FileDescription", + LOWORD(languages[i]), HIWORD(languages[i]) ); + if (!VerQueryValueW( data, buffer, (void **)&str, &len )) goto done; + TRACE( "found description %s\n", debugstr_w( str )); + if (str[0] == 0x200e && str[1] == 0x200e) version_layout = LAYOUT_RTL; + + done: + HeapFree( GetProcessHeap(), 0, data ); + NtUserSetProcessDefaultLayout( *layout = version_layout ); + } + return TRUE; +} + + +/****************************************************************************** + * SetProcessDefaultLayout [USER32.@] + * + * Sets the default layout for parentless windows. + */ +BOOL WINAPI SetProcessDefaultLayout( DWORD layout ) +{ + return NtUserSetProcessDefaultLayout( layout ); +} + + +/*********************************************************************** + * UpdateWindow (USER32.@) + */ +BOOL WINAPI UpdateWindow( HWND hwnd ) +{ + if (!hwnd) + { + SetLastError( ERROR_INVALID_WINDOW_HANDLE ); + return FALSE; + } + + return NtUserRedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN ); +} + + +/*********************************************************************** + * ValidateRgn (USER32.@) + */ +BOOL WINAPI ValidateRgn( HWND hwnd, HRGN hrgn ) +{ + if (!hwnd) + { + SetLastError( ERROR_INVALID_WINDOW_HANDLE ); + return FALSE; + } + + return NtUserRedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE ); +} + + +/************************************************************************* + * ScrollWindow (USER32.@) + */ +BOOL WINAPI ScrollWindow( HWND hwnd, INT dx, INT dy, const RECT *rect, const RECT *clip_rect ) +{ + UINT flags = SW_INVALIDATE | SW_ERASE | (rect ? 0 : SW_SCROLLCHILDREN) | SW_NODCCACHE; + return NtUserScrollWindowEx( hwnd, dx, dy, rect, clip_rect, 0, NULL, flags ); +} + +#ifdef _WIN64 + +/* 64bit versions */ + +#undef GetWindowLongPtrW +#undef GetWindowLongPtrA +#undef SetWindowLongPtrW +#undef SetWindowLongPtrA + +/***************************************************************************** + * GetWindowLongPtrW (USER32.@) + */ +LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset ) +{ + LONG_PTR ret = NtUserGetWindowLongPtrW( hwnd, offset ); + return get_window_long_ptr( hwnd, offset, ret, FALSE ); +} + +/***************************************************************************** + * GetWindowLongPtrA (USER32.@) + */ +LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset ) +{ + LONG_PTR ret = NtUserGetWindowLongPtrA( hwnd, offset ); + return get_window_long_ptr( hwnd, offset, ret, TRUE ); +} + +/***************************************************************************** + * SetWindowLongPtrW (USER32.@) + */ +LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval ) +{ + if (offset == DWLP_DLGPROC && NtUserGetDialogInfo( hwnd )) + return set_dialog_proc( hwnd, newval, FALSE ); + + return NtUserSetWindowLongPtr( hwnd, offset, newval, FALSE ); +} + +/***************************************************************************** + * SetWindowLongPtrA (USER32.@) + */ +LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval ) +{ + if (offset == DWLP_DLGPROC && NtUserGetDialogInfo( hwnd )) + return set_dialog_proc( hwnd, newval, TRUE ); + + return NtUserSetWindowLongPtr( hwnd, offset, newval, TRUE ); +} + +#endif /* _WIN64 */ + +/***************************************************************************** + * GetWindowDisplayAffinity (USER32.@) + */ +BOOL WINAPI GetWindowDisplayAffinity(HWND hwnd, DWORD *affinity) +{ + FIXME("(%p, %p): stub\n", hwnd, affinity); + + if (!hwnd || !affinity) + { + SetLastError(hwnd ? ERROR_NOACCESS : ERROR_INVALID_WINDOW_HANDLE); + return FALSE; + } + + *affinity = WDA_NONE; + return TRUE; +} + +/***************************************************************************** + * SetWindowDisplayAffinity (USER32.@) + */ +BOOL WINAPI SetWindowDisplayAffinity(HWND hwnd, DWORD affinity) +{ + FIXME("(%p, %lu): stub\n", hwnd, affinity); + + if (!hwnd) + { + SetLastError(ERROR_INVALID_WINDOW_HANDLE); + return FALSE; + } + + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; +} + +/********************************************************************** + * SetWindowCompositionAttribute (USER32.@) + */ +BOOL WINAPI SetWindowCompositionAttribute(HWND hwnd, void *data) +{ + FIXME("(%p, %p): stub\n", hwnd, data); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +}