From 01b3674247b1956fb8d1d46cc725d687a63ed425 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Wed, 16 Feb 2022 12:30:12 +0100 Subject: [PATCH] win32u: Move NtUserNotifyWinEvent implementation from user32. Signed-off-by: Jacek Caban Signed-off-by: Huw Davies Signed-off-by: Alexandre Julliard --- dlls/user32/focus.c | 2 +- dlls/user32/hook.c | 169 +++++-------------------------------- dlls/user32/user32.spec | 2 +- dlls/user32/user_main.c | 1 + dlls/user32/user_private.h | 1 + dlls/user32/win.c | 2 +- dlls/win32u/hook.c | 96 +++++++++++++++++++++ dlls/win32u/syscall.c | 1 + dlls/win32u/win32u.spec | 2 +- dlls/wow64win/syscall.h | 1 + dlls/wow64win/user.c | 11 +++ include/ntuser.h | 14 +++ 12 files changed, 148 insertions(+), 154 deletions(-) diff --git a/dlls/user32/focus.c b/dlls/user32/focus.c index a20151ad5df..4ba2bfef193 100644 --- a/dlls/user32/focus.c +++ b/dlls/user32/focus.c @@ -74,7 +74,7 @@ static HWND set_focus_window( HWND hwnd ) SendMessageW( ime_default, WM_IME_INTERNAL, IME_INTERNAL_ACTIVATE, (LPARAM)hwnd ); if (previous) - NotifyWinEvent( EVENT_OBJECT_FOCUS, hwnd, OBJID_CLIENT, 0 ); + NtUserNotifyWinEvent( EVENT_OBJECT_FOCUS, hwnd, OBJID_CLIENT, 0 ); SendMessageW( hwnd, WM_SETFOCUS, (WPARAM)previous, 0 ); } diff --git a/dlls/user32/hook.c b/dlls/user32/hook.c index edcc3143ab4..3adfba43691 100644 --- a/dlls/user32/hook.c +++ b/dlls/user32/hook.c @@ -726,161 +726,30 @@ HWINEVENTHOOK WINAPI SetWinEventHook(DWORD event_min, DWORD event_max, return NtUserSetWinEventHook( event_min, event_max, inst, &str, proc, pid, tid, flags ); } -static inline BOOL find_first_hook(DWORD id, DWORD event, HWND hwnd, LONG object_id, - LONG child_id, struct hook_info *info) +BOOL WINAPI User32CallWinEventHook( const struct win_hook_proc_params *params, ULONG size ) { - struct user_thread_info *thread_info = get_user_thread_info(); - BOOL ret; + WINEVENTPROC proc = params->proc; + HMODULE free_module = 0; - if (!HOOK_IsHooked( id )) - { - TRACE( "skipping hook %s mask %x\n", hook_names[id-WH_MINHOOK], thread_info->active_hooks ); - return FALSE; - } + USER_CheckNotLock(); /* FIXME: move to NtUserNotifyWinEvent */ - SERVER_START_REQ( start_hook_chain ) - { - req->id = id; - req->event = event; - req->window = wine_server_user_handle( hwnd ); - req->object_id = object_id; - req->child_id = child_id; - wine_server_set_reply( req, info->module, sizeof(info->module)-sizeof(WCHAR) ); - ret = !wine_server_call( req ); - if (ret) - { - info->module[wine_server_reply_size(req) / sizeof(WCHAR)] = 0; - info->handle = wine_server_ptr_handle( reply->handle ); - info->proc = wine_server_get_ptr( reply->proc ); - info->tid = reply->tid; - thread_info->active_hooks = reply->active_hooks; - } - } - SERVER_END_REQ; - return ret && (info->tid || info->proc); + if (params->module[0] && !(proc = get_hook_proc( proc, params->module, &free_module ))) return FALSE; + + TRACE_(relay)( "\1Call winevent hook proc %p (hhook=%p,event=%x,hwnd=%p,object_id=%x,child_id=%x,tid=%04x,time=%x)\n", + proc, params->handle, params->event, params->hwnd, params->object_id, + params->child_id, GetCurrentThreadId(), GetCurrentTime() ); + + proc( params->handle, params->event, params->hwnd, params->object_id, params->child_id, + GetCurrentThreadId(), GetCurrentTime() ); + + TRACE_(relay)( "\1Ret winevent hook proc %p (hhook=%p,event=%x,hwnd=%p,object_id=%x,child_id=%x,tid=%04x,time=%x)\n", + proc, params->handle, params->event, params->hwnd, params->object_id, + params->child_id, GetCurrentThreadId(), GetCurrentTime() ); + + if (free_module) FreeLibrary( free_module ); + return TRUE; } -static inline BOOL find_next_hook(DWORD event, HWND hwnd, LONG object_id, - LONG child_id, struct hook_info *info) -{ - BOOL ret; - - SERVER_START_REQ( get_hook_info ) - { - req->handle = wine_server_user_handle( info->handle ); - req->get_next = 1; - req->event = event; - req->window = wine_server_user_handle( hwnd ); - req->object_id = object_id; - req->child_id = child_id; - wine_server_set_reply( req, info->module, sizeof(info->module)-sizeof(WCHAR) ); - ret = !wine_server_call( req ); - if (ret) - { - info->module[wine_server_reply_size(req) / sizeof(WCHAR)] = 0; - info->handle = wine_server_ptr_handle( reply->handle ); - info->proc = wine_server_get_ptr( reply->proc ); - info->tid = reply->tid; - } - } - SERVER_END_REQ; - return ret; -} - -static inline void find_hook_close(DWORD id) -{ - SERVER_START_REQ( finish_hook_chain ) - { - req->id = id; - wine_server_call( req ); - } - SERVER_END_REQ; -} - -/*********************************************************************** - * NotifyWinEvent [USER32.@] - * - * Inform the OS that an event has occurred. - * - * PARAMS - * event [I] Id of the event - * hwnd [I] Window holding the object that created the event - * object_id [I] Type of object that created the event - * child_id [I] Child object of nId, or CHILDID_SELF. - * - * RETURNS - * Nothing. - */ -void WINAPI NotifyWinEvent(DWORD event, HWND hwnd, LONG object_id, LONG child_id) -{ - struct hook_info info; - - TRACE("%04x,%p,%d,%d\n", event, hwnd, object_id, child_id); - - if (!hwnd) - { - SetLastError(ERROR_INVALID_WINDOW_HANDLE); - return; - } - - USER_CheckNotLock(); - -#if 0 - if (event & 0x80000000) - { - /* FIXME: on 64-bit platforms we need to invent some other way for - * passing parameters, nId and nChildId can't hold full [W|L]PARAM. - * struct call_hook *hook = (LRESULT *)hWnd; - * wparam = hook->wparam; - * lparam = hook->lparam; - */ - LRESULT *ret = (LRESULT *)hwnd; - INT id, code, unicode; - - id = (dwEvent & 0x7fff0000) >> 16; - code = event & 0x7fff; - unicode = event & 0x8000; - *ret = HOOK_CallHooks(id, code, object_id, child_id, unicode); - return; - } -#endif - - if (!find_first_hook(WH_WINEVENT, event, hwnd, object_id, child_id, &info)) return; - - do - { - WINEVENTPROC proc = info.proc; - if (proc) - { - HMODULE free_module = 0; - TRACE( "calling WH_WINEVENT hook %p event %x hwnd %p %x %x module %s\n", - proc, event, hwnd, object_id, child_id, debugstr_w(info.module) ); - - if (!info.module[0] || (proc = get_hook_proc( proc, info.module, &free_module )) != NULL) - { - TRACE_(relay)( "\1Call winevent hook proc %p (hhook=%p,event=%x,hwnd=%p,object_id=%x,child_id=%x,tid=%04x,time=%x)\n", - proc, info.handle, event, hwnd, object_id, - child_id, GetCurrentThreadId(), GetCurrentTime()); - - proc( info.handle, event, hwnd, object_id, child_id, - GetCurrentThreadId(), GetCurrentTime()); - - TRACE_(relay)( "\1Ret winevent hook proc %p (hhook=%p,event=%x,hwnd=%p,object_id=%x,child_id=%x,tid=%04x,time=%x)\n", - proc, info.handle, event, hwnd, object_id, - child_id, GetCurrentThreadId(), GetCurrentTime()); - - if (free_module) FreeLibrary(free_module); - } - } - else - break; - } - while (find_next_hook(event, hwnd, object_id, child_id, &info)); - - find_hook_close(WH_WINEVENT); -} - - /*********************************************************************** * IsWinEventHookInstalled [USER32.@] * diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 112b79049ce..16342d15ee7 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -545,7 +545,7 @@ @ stdcall MoveWindow(long long long long long long) @ stdcall MsgWaitForMultipleObjects(long ptr long long long) @ stdcall MsgWaitForMultipleObjectsEx(long ptr long long long) -@ stdcall NotifyWinEvent(long long long long) +@ stdcall NotifyWinEvent(long long long long) NtUserNotifyWinEvent @ stdcall OemKeyScan(long) @ stdcall OemToCharA(str ptr) @ stdcall OemToCharBuffA(ptr ptr long) diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c index 91c466aff11..c2ec561a800 100644 --- a/dlls/user32/user_main.c +++ b/dlls/user32/user_main.c @@ -212,6 +212,7 @@ static void dpiaware_init(void) static const void *kernel_callback_table[NtUserCallCount] = { User32CallEnumDisplayMonitor, + User32CallWinEventHook, }; diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 0858c630cea..17aa45f044c 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -194,6 +194,7 @@ extern const WCHAR *CLASS_GetVersionedName(const WCHAR *classname, UINT *basenam /* kernel callbacks */ BOOL WINAPI User32CallEnumDisplayMonitor( struct enum_display_monitor_params *params, ULONG size ); +BOOL WINAPI User32CallWinEventHook( const struct win_hook_proc_params *params, ULONG size ); /* message spy definitions */ diff --git a/dlls/user32/win.c b/dlls/user32/win.c index 8a0a91ff4fb..ee16144b179 100644 --- a/dlls/user32/win.c +++ b/dlls/user32/win.c @@ -1777,7 +1777,7 @@ HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, if (!USER_Driver->pCreateWindow( hwnd )) goto failed; - NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0); + NtUserNotifyWinEvent( EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0 ); /* send the size messages */ diff --git a/dlls/win32u/hook.c b/dlls/win32u/hook.c index 46f6efe1b1b..748ff3e9031 100644 --- a/dlls/win32u/hook.c +++ b/dlls/win32u/hook.c @@ -33,6 +33,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(hook); #define WH_WINEVENT (WH_MAXHOOK+1) +static BOOL is_hooked( INT id ) +{ + struct user_thread_info *thread_info = get_user_thread_info(); + + if (!thread_info->active_hooks) return TRUE; + return (thread_info->active_hooks & (1 << (id - WH_MINHOOK))) != 0; +} + /*********************************************************************** * NtUserSetWinEventHook (win32u.@) */ @@ -102,3 +110,91 @@ BOOL WINAPI NtUserUnhookWinEvent( HWINEVENTHOOK handle ) SERVER_END_REQ; return ret; } + +/*********************************************************************** + * NtUserNotifyWinEvent (win32u.@) + */ +void WINAPI NtUserNotifyWinEvent( DWORD event, HWND hwnd, LONG object_id, LONG child_id ) +{ + struct user_thread_info *thread_info = get_user_thread_info(); + struct win_hook_proc_params info; + void *ret_ptr; + ULONG ret_len; + BOOL ret; + + TRACE( "%04x, %p, %d, %d\n", event, hwnd, object_id, child_id ); + + if (!hwnd) + { + SetLastError( ERROR_INVALID_WINDOW_HANDLE ); + return; + } + + if (!is_hooked( WH_WINEVENT )) + { + TRACE( "skipping hook mask %x\n", thread_info->active_hooks ); + return; + } + + info.event = event; + info.hwnd = hwnd; + info.object_id = object_id; + info.child_id = child_id; + + SERVER_START_REQ( start_hook_chain ) + { + req->id = WH_WINEVENT; + req->event = event; + req->window = wine_server_user_handle( hwnd ); + req->object_id = object_id; + req->child_id = child_id; + wine_server_set_reply( req, info.module, sizeof(info.module) - sizeof(WCHAR) ); + ret = !wine_server_call( req ) && reply->proc; + if (ret) + { + info.module[wine_server_reply_size(req) / sizeof(WCHAR)] = 0; + info.handle = wine_server_ptr_handle( reply->handle ); + info.proc = wine_server_get_ptr( reply->proc ); + thread_info->active_hooks = reply->active_hooks; + } + } + SERVER_END_REQ; + if (!ret) return; + + do + { + TRACE( "calling WH_WINEVENT hook %p event %x hwnd %p %x %x module %s\n", + info.proc, event, hwnd, object_id, child_id, debugstr_w(info.module) ); + + KeUserModeCallback( NtUserCallWinEventHook, &info, + FIELD_OFFSET( struct win_hook_proc_params, module[lstrlenW(info.module) + 1] ), + &ret_ptr, &ret_len ); + + SERVER_START_REQ( get_hook_info ) + { + req->handle = wine_server_user_handle( info.handle ); + req->get_next = 1; + req->event = event; + req->window = wine_server_user_handle( hwnd ); + req->object_id = object_id; + req->child_id = child_id; + wine_server_set_reply( req, info.module, sizeof(info.module) - sizeof(WCHAR) ); + ret = !wine_server_call( req ) && reply->proc; + if (ret) + { + info.module[wine_server_reply_size(req) / sizeof(WCHAR)] = 0; + info.handle = wine_server_ptr_handle( reply->handle ); + info.proc = wine_server_get_ptr( reply->proc ); + } + } + SERVER_END_REQ; + } + while (ret); + + SERVER_START_REQ( finish_hook_chain ) + { + req->id = WH_WINEVENT; + wine_server_call( req ); + } + SERVER_END_REQ; +} diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c index e2b88dcc62e..3034a0377ff 100644 --- a/dlls/win32u/syscall.c +++ b/dlls/win32u/syscall.c @@ -128,6 +128,7 @@ static void * const syscalls[] = NtUserGetProp, NtUserGetSystemDpiForProcess, NtUserGetThreadDesktop, + NtUserNotifyWinEvent, NtUserOpenDesktop, NtUserOpenInputDesktop, NtUserOpenWindowStation, diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 7de0af5d959..5ddbf53af77 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -1089,7 +1089,7 @@ @ stub NtUserNavigateFocus @ stub NtUserNotifyIMEStatus @ stub NtUserNotifyProcessCreate -@ stub NtUserNotifyWinEvent +@ stdcall -syscall NtUserNotifyWinEvent(long long long long) @ stub NtUserOpenClipboard @ stdcall -syscall NtUserOpenDesktop(ptr long long) @ stdcall -syscall NtUserOpenInputDesktop(long long long) diff --git a/dlls/wow64win/syscall.h b/dlls/wow64win/syscall.h index a0292bb881f..50b442ecaea 100644 --- a/dlls/wow64win/syscall.h +++ b/dlls/wow64win/syscall.h @@ -115,6 +115,7 @@ SYSCALL_ENTRY( NtUserGetProp ) \ SYSCALL_ENTRY( NtUserGetSystemDpiForProcess ) \ SYSCALL_ENTRY( NtUserGetThreadDesktop ) \ + SYSCALL_ENTRY( NtUserNotifyWinEvent ) \ SYSCALL_ENTRY( NtUserOpenDesktop ) \ SYSCALL_ENTRY( NtUserOpenInputDesktop ) \ SYSCALL_ENTRY( NtUserOpenWindowStation ) \ diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index b610b510ebc..7a97cbed7f2 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -356,6 +356,17 @@ NTSTATUS WINAPI wow64_NtUserGetDoubleClickTime( UINT *args ) return NtUserGetDoubleClickTime(); } +NTSTATUS WINAPI wow64_NtUserNotifyWinEvent( UINT *args ) +{ + DWORD event = get_ulong( &args ); + HWND hwnd = get_handle( &args ); + LONG object_id = get_ulong( &args ); + LONG child_id = get_ulong( &args ); + + NtUserNotifyWinEvent( event, hwnd, object_id, child_id ); + return 0; +} + NTSTATUS WINAPI wow64_NtUserSetWinEventHook( UINT *args ) { DWORD event_min = get_ulong( &args ); diff --git a/include/ntuser.h b/include/ntuser.h index 65e9d20d90a..6f166f70d05 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -27,6 +27,7 @@ enum { NtUserCallEnumDisplayMonitor, + NtUserCallWinEventHook, NtUserCallVulkanDebugReportCallback, NtUserCallVulkanDebugUtilsCallback, NtUserCallCount @@ -42,6 +43,18 @@ struct enum_display_monitor_params LPARAM lparam; }; +/* NtUserCallWinEventHook params */ +struct win_hook_proc_params +{ + DWORD event; + HWND hwnd; + LONG object_id; + LONG child_id; + void *handle; + WINEVENTPROC proc; + WCHAR module[MAX_PATH]; +}; + /* process DPI awareness contexts */ #define NTUSER_DPI_UNAWARE 0x00006010 #define NTUSER_DPI_SYSTEM_AWARE 0x00006011 @@ -163,6 +176,7 @@ HDESK WINAPI NtUserGetThreadDesktop( DWORD thread ); BOOL WINAPI NtUserGetUpdatedClipboardFormats( UINT *formats, UINT size, UINT *out_size ); BOOL WINAPI NtUserIsClipboardFormatAvailable( UINT format ); UINT WINAPI NtUserMapVirtualKeyEx( UINT code, UINT type, HKL layout ); +void WINAPI NtUserNotifyWinEvent( DWORD event, HWND hwnd, LONG object_id, LONG child_id ); HWINSTA WINAPI NtUserOpenWindowStation( OBJECT_ATTRIBUTES *attr, ACCESS_MASK access ); BOOL WINAPI NtUserSetObjectInformation( HANDLE handle, INT index, void *info, DWORD len ); HDESK WINAPI NtUserOpenDesktop( OBJECT_ATTRIBUTES *attr, DWORD flags, ACCESS_MASK access );