From 58c4488626237bfddb2909983dee17348254061b Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Thu, 31 Mar 2022 15:36:51 +0200 Subject: [PATCH] win32u: Move NtUserPeekMessage implementation from user32. Signed-off-by: Jacek Caban Signed-off-by: Huw Davies Signed-off-by: Alexandre Julliard --- dlls/user.exe16/message.c | 16 ++++++++ dlls/user32/message.c | 31 +-------------- dlls/win32u/gdiobj.c | 1 + dlls/win32u/message.c | 73 ++++++++++++++++++++++++++++++++++++ dlls/win32u/sysparams.c | 5 +++ dlls/win32u/win32u.spec | 2 +- dlls/win32u/win32u_private.h | 2 + dlls/win32u/wrappers.c | 6 +++ include/ntuser.h | 3 ++ 9 files changed, 108 insertions(+), 31 deletions(-) diff --git a/dlls/user.exe16/message.c b/dlls/user.exe16/message.c index 915585267d6..05285d55eb5 100644 --- a/dlls/user.exe16/message.c +++ b/dlls/user.exe16/message.c @@ -2596,6 +2596,19 @@ static void WINAPI User16CallFreeIcon( ULONG *param, ULONG size ) } +static DWORD WINAPI User16ThunkLock( DWORD *param, ULONG size ) +{ + if (size != sizeof(DWORD)) + { + DWORD lock; + ReleaseThunkLock( &lock ); + return lock; + } + RestoreThunkLock( *param ); + return 0; +} + + void register_wow_handlers(void) { void **callback_table = NtCurrentTeb()->Peb->KernelCallbackTable; @@ -2615,6 +2628,9 @@ void register_wow_handlers(void) }; callback_table[NtUserCallFreeIcon] = User16CallFreeIcon; + callback_table[NtUserThunkLock] = User16ThunkLock; + + NtUserCallOneParam( TRUE, NtUserEnableThunkLock ); UserRegisterWowHandlers( &handlers16, &wow_handlers32 ); } diff --git a/dlls/user32/message.c b/dlls/user32/message.c index 95bc7c416ca..ddef9c25a0a 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -3208,36 +3208,7 @@ static inline void check_for_driver_events( UINT msg ) */ BOOL WINAPI DECLSPEC_HOTPATCH PeekMessageW( MSG *msg_out, HWND hwnd, UINT first, UINT last, UINT flags ) { - MSG msg; - int ret; - - USER_CheckNotLock(); - check_for_driver_events( 0 ); - - ret = peek_message( &msg, hwnd, first, last, flags, 0 ); - if (ret < 0) return FALSE; - - if (!ret) - { - flush_window_surfaces( TRUE ); - ret = wow_handlers.wait_message( 0, NULL, 0, QS_ALLINPUT, 0 ); - /* if we received driver events, check again for a pending message */ - if (ret == WAIT_TIMEOUT || peek_message( &msg, hwnd, first, last, flags, 0 ) <= 0) return FALSE; - } - - check_for_driver_events( msg.message ); - - /* copy back our internal safe copy of message data to msg_out. - * msg_out is a variable from the *program*, so it can't be used - * internally as it can get "corrupted" by our use of SendMessage() - * (back to the program) inside the message handling itself. */ - if (!msg_out) - { - SetLastError( ERROR_NOACCESS ); - return FALSE; - } - *msg_out = msg; - return TRUE; + return NtUserPeekMessage( msg_out, hwnd, first, last, flags ); } diff --git a/dlls/win32u/gdiobj.c b/dlls/win32u/gdiobj.c index b6c63d5d516..b75ae5aa8ab 100644 --- a/dlls/win32u/gdiobj.c +++ b/dlls/win32u/gdiobj.c @@ -1190,6 +1190,7 @@ static struct unix_funcs unix_funcs = NtUserMapVirtualKeyEx, NtUserMessageCall, NtUserMoveWindow, + NtUserPeekMessage, NtUserRedrawWindow, NtUserRegisterClassExWOW, NtUserRegisterHotKey, diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 76a7d4dd551..b74f5c75abd 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -856,6 +856,79 @@ void process_sent_messages(void) peek_message( &msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, 0 ); } +/* check for driver events if we detect that the app is not properly consuming messages */ +static inline void check_for_driver_events( UINT msg ) +{ + if (get_user_thread_info()->message_count > 200) + { + flush_window_surfaces( FALSE ); + user_driver->pMsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_ALLINPUT, 0 ); + } + else if (msg == WM_TIMER || msg == WM_SYSTIMER) + { + /* driver events should have priority over timers, so make sure we'll check for them soon */ + get_user_thread_info()->message_count += 100; + } + else get_user_thread_info()->message_count++; +} + +/* wait for message or signaled handle */ +static DWORD wait_message( DWORD count, const HANDLE *handles, DWORD timeout, DWORD mask, DWORD flags ) +{ + DWORD ret, lock; + void *ret_ptr; + ULONG ret_len; + + if (enable_thunk_lock) + lock = KeUserModeCallback( NtUserThunkLock, NULL, 0, &ret_ptr, &ret_len ); + + ret = user_driver->pMsgWaitForMultipleObjectsEx( count, handles, timeout, mask, flags ); + if (ret == WAIT_TIMEOUT && !count && !timeout) NtYieldExecution(); + if ((mask & QS_INPUT) == QS_INPUT) get_user_thread_info()->message_count = 0; + + if (enable_thunk_lock) + KeUserModeCallback( NtUserThunkLock, &lock, sizeof(lock), &ret_ptr, &ret_len ); + + return ret; +} + +/*********************************************************************** + * NtUserPeekMessage (win32u.@) + */ +BOOL WINAPI NtUserPeekMessage( MSG *msg_out, HWND hwnd, UINT first, UINT last, UINT flags ) +{ + MSG msg; + int ret; + + user_check_not_lock(); + check_for_driver_events( 0 ); + + ret = peek_message( &msg, hwnd, first, last, flags, 0 ); + if (ret < 0) return FALSE; + + if (!ret) + { + flush_window_surfaces( TRUE ); + ret = wait_message( 0, NULL, 0, QS_ALLINPUT, 0 ); + /* if we received driver events, check again for a pending message */ + if (ret == WAIT_TIMEOUT || peek_message( &msg, hwnd, first, last, flags, 0 ) <= 0) return FALSE; + } + + check_for_driver_events( msg.message ); + + /* copy back our internal safe copy of message data to msg_out. + * msg_out is a variable from the *program*, so it can't be used + * internally as it can get "corrupted" by our use of SendMessage() + * (back to the program) inside the message handling itself. */ + if (!msg_out) + { + SetLastError( ERROR_NOACCESS ); + return FALSE; + } + *msg_out = msg; + return TRUE; +} + /********************************************************************** * dispatch_message */ diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index e1c9a671007..d5666f3ae85 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -230,6 +230,8 @@ static struct list monitors = LIST_INIT(monitors); static INT64 last_query_display_time; static pthread_mutex_t display_lock = PTHREAD_MUTEX_INITIALIZER; +BOOL enable_thunk_lock = FALSE; + static struct monitor virtual_monitor = { .handle = NULLDRV_DEFAULT_HMONITOR, @@ -4669,6 +4671,9 @@ ULONG_PTR WINAPI NtUserCallOneParam( ULONG_PTR arg, ULONG code ) return dispatch_message( (const MSG *)arg, TRUE ); case NtUserEnableDC: return set_dce_flags( UlongToHandle(arg), DCHF_ENABLEDC ); + case NtUserEnableThunkLock: + enable_thunk_lock = arg; + return 0; case NtUserGetClipCursor: return get_clip_cursor( (RECT *)arg ); case NtUserGetCursorPos: diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 83901550f3b..70def5d2146 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -1098,7 +1098,7 @@ @ stub NtUserPaintDesktop @ stub NtUserPaintMenuBar @ stub NtUserPaintMonitor -@ stub NtUserPeekMessage +@ stdcall NtUserPeekMessage(ptr long long long long) @ stub NtUserPerMonitorDPIPhysicalToLogicalPoint @ stub NtUserPhysicalToLogicalDpiPointForWindow @ stub NtUserPhysicalToLogicalPoint diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 28545c16d15..ebd7e9e3a8d 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -238,6 +238,7 @@ struct unix_funcs BOOL (WINAPI *pNtUserMessageCall)( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, ULONG_PTR result_info, DWORD type, BOOL ansi ); BOOL (WINAPI *pNtUserMoveWindow)( HWND hwnd, INT x, INT y, INT cx, INT cy, BOOL repaint ); + BOOL (WINAPI *pNtUserPeekMessage)( MSG *msg_out, HWND hwnd, UINT first, UINT last, UINT flags ); BOOL (WINAPI *pNtUserRedrawWindow)( HWND hwnd, const RECT *rect, HRGN hrgn, UINT flags ); ATOM (WINAPI *pNtUserRegisterClassExWOW)( const WNDCLASSEXW *wc, UNICODE_STRING *name, UNICODE_STRING *version, @@ -349,6 +350,7 @@ extern BOOL reply_message_result( LRESULT result, MSG *msg ) DECLSPEC_HIDDEN; extern LRESULT send_message( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) DECLSPEC_HIDDEN; /* sysparams.c */ +extern BOOL enable_thunk_lock DECLSPEC_HIDDEN; extern RECT get_display_rect( const WCHAR *display ) DECLSPEC_HIDDEN; extern UINT get_monitor_dpi( HMONITOR monitor ) DECLSPEC_HIDDEN; extern BOOL get_monitor_info( HMONITOR handle, MONITORINFO *info ) DECLSPEC_HIDDEN; diff --git a/dlls/win32u/wrappers.c b/dlls/win32u/wrappers.c index e65557e13ee..823fbb41023 100644 --- a/dlls/win32u/wrappers.c +++ b/dlls/win32u/wrappers.c @@ -958,6 +958,12 @@ BOOL WINAPI NtUserMessageCall( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam return unix_funcs->pNtUserMessageCall( hwnd, msg, wparam, lparam, result_info, type, ansi ); } +BOOL WINAPI NtUserPeekMessage( MSG *msg_out, HWND hwnd, UINT first, UINT last, UINT flags ) +{ + if (!unix_funcs) return FALSE; + return unix_funcs->pNtUserPeekMessage( msg_out, hwnd, first, last, flags ); +} + BOOL WINAPI NtUserRedrawWindow( HWND hwnd, const RECT *rect, HRGN hrgn, UINT flags ) { if (!unix_funcs) return FALSE; diff --git a/include/ntuser.h b/include/ntuser.h index 536f246df42..df7828c9b42 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -35,6 +35,7 @@ enum NtUserLoadDriver, /* win16 hooks */ NtUserCallFreeIcon, + NtUserThunkLock, /* Vulkan support */ NtUserCallVulkanDebugReportCallback, NtUserCallVulkanDebugUtilsCallback, @@ -150,6 +151,7 @@ enum NtUserCreateCursorIcon, NtUserDispatchMessageA, NtUserEnableDC, + NtUserEnableThunkLock, NtUserGetClipCursor, NtUserGetCursorPos, NtUserGetIconParam, @@ -588,6 +590,7 @@ HWINSTA WINAPI NtUserOpenWindowStation( OBJECT_ATTRIBUTES *attr, ACCESS_MASK acc BOOL WINAPI NtUserSetObjectInformation( HANDLE handle, INT index, void *info, DWORD len ); HDESK WINAPI NtUserOpenDesktop( OBJECT_ATTRIBUTES *attr, DWORD flags, ACCESS_MASK access ); HDESK WINAPI NtUserOpenInputDesktop( DWORD flags, BOOL inherit, ACCESS_MASK access ); +BOOL WINAPI NtUserPeekMessage( MSG *msg_out, HWND hwnd, UINT first, UINT last, UINT flags ); BOOL WINAPI NtUserRedrawWindow( HWND hwnd, const RECT *rect, HRGN hrgn, UINT flags ); ATOM WINAPI NtUserRegisterClassExWOW( const WNDCLASSEXW *wc, UNICODE_STRING *name, UNICODE_STRING *version, struct client_menu_name *client_menu_name, DWORD fnid, DWORD flags,