From 63342353bcbb64cdaf61a554433be40b27a7d14f Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 11 May 2005 13:03:15 +0000 Subject: [PATCH] Store a bitmap of active hooks on the client side to try to avoid server calls for hooks that are not set. --- dlls/user/hook.c | 35 +++++++++++-- dlls/user/message.c | 1 + dlls/user/user_private.h | 3 +- include/wine/server_protocol.h | 6 ++- server/hook.c | 94 ++++++++++++++++++++++++---------- server/protocol.def | 5 ++ server/queue.c | 2 + server/trace.c | 12 ++++- server/user.h | 1 + 9 files changed, 124 insertions(+), 35 deletions(-) diff --git a/dlls/user/hook.c b/dlls/user/hook.c index 7590247b34e..37e53b3fee1 100644 --- a/dlls/user/hook.c +++ b/dlls/user/hook.c @@ -189,7 +189,11 @@ static HHOOK set_windows_hook( INT id, HOOKPROC proc, HINSTANCE inst, DWORD tid, } else req->proc = proc; - if (!wine_server_call_err( req )) handle = reply->handle; + if (!wine_server_call_err( req )) + { + handle = reply->handle; + get_user_thread_info()->active_hooks = reply->active_hooks; + } } SERVER_END_REQ; @@ -333,6 +337,12 @@ LRESULT HOOK_CallHooks( INT id, INT code, WPARAM wparam, LPARAM lparam, BOOL uni USER_CheckNotLock(); + if (!HOOK_IsHooked( id )) + { + TRACE( "skipping hook %s mask %x\n", hook_names[id-WH_MINHOOK], thread_info->active_hooks ); + return 0; + } + SERVER_START_REQ( start_hook_chain ) { req->id = id; @@ -346,6 +356,7 @@ LRESULT HOOK_CallHooks( INT id, INT code, WPARAM wparam, LPARAM lparam, BOOL uni pid = reply->pid; tid = reply->tid; unicode_hook = reply->unicode; + thread_info->active_hooks = reply->active_hooks; } } SERVER_END_REQ; @@ -402,7 +413,10 @@ LRESULT HOOK_CallHooks( INT id, INT code, WPARAM wparam, LPARAM lparam, BOOL uni */ BOOL HOOK_IsHooked( INT id ) { - return TRUE; /* FIXME */ + 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; } @@ -456,6 +470,7 @@ BOOL WINAPI UnhookWindowsHook( INT id, HOOKPROC proc ) req->id = id; req->proc = proc; ret = !wine_server_call_err( req ); + if (ret) get_user_thread_info()->active_hooks = reply->active_hooks; } SERVER_END_REQ; if (!ret && GetLastError() == ERROR_INVALID_HANDLE) SetLastError( ERROR_INVALID_HOOK_HANDLE ); @@ -478,6 +493,7 @@ BOOL WINAPI UnhookWindowsHookEx( HHOOK hhook ) req->handle = hhook; req->id = 0; ret = !wine_server_call_err( req ); + if (ret) get_user_thread_info()->active_hooks = reply->active_hooks; } SERVER_END_REQ; if (!ret && GetLastError() == ERROR_INVALID_HANDLE) SetLastError( ERROR_INVALID_HOOK_HANDLE ); @@ -643,7 +659,11 @@ HWINEVENTHOOK WINAPI SetWinEventHook(DWORD event_min, DWORD event_max, } else req->proc = proc; - if (!wine_server_call_err( req )) handle = reply->handle; + if (!wine_server_call_err( req )) + { + handle = reply->handle; + get_user_thread_info()->active_hooks = reply->active_hooks; + } } SERVER_END_REQ; @@ -675,6 +695,7 @@ BOOL WINAPI UnhookWinEvent(HWINEVENTHOOK hEventHook) req->handle = hEventHook; req->id = WH_WINEVENT; ret = !wine_server_call_err( req ); + if (ret) get_user_thread_info()->active_hooks = reply->active_hooks; } SERVER_END_REQ; return ret; @@ -683,8 +704,15 @@ BOOL WINAPI UnhookWinEvent(HWINEVENTHOOK hEventHook) inline static BOOL find_first_hook(DWORD id, DWORD event, HWND hwnd, LONG object_id, LONG child_id, struct hook_info *info) { + struct user_thread_info *thread_info = get_user_thread_info(); BOOL ret; + if (!HOOK_IsHooked( id )) + { + TRACE( "skipping hook %s mask %x\n", hook_names[id-WH_MINHOOK], thread_info->active_hooks ); + return FALSE; + } + SERVER_START_REQ( start_hook_chain ) { req->id = id; @@ -700,6 +728,7 @@ inline static BOOL find_first_hook(DWORD id, DWORD event, HWND hwnd, LONG object info->handle = reply->handle; info->proc = reply->proc; info->tid = reply->tid; + thread_info->active_hooks = reply->active_hooks; } } SERVER_END_REQ; diff --git a/dlls/user/message.c b/dlls/user/message.c index 86103ddd659..33aa87cf04f 100644 --- a/dlls/user/message.c +++ b/dlls/user/message.c @@ -1942,6 +1942,7 @@ static BOOL peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, int flags info.hook_proc = reply->hook_proc; hw_id = reply->hw_id; extra_info = reply->info; + thread_info->active_hooks = reply->active_hooks; } else { diff --git a/dlls/user/user_private.h b/dlls/user/user_private.h index 874b03ee933..c31d1788555 100644 --- a/dlls/user/user_private.h +++ b/dlls/user/user_private.h @@ -138,7 +138,8 @@ struct user_thread_info DWORD GetMessageExtraInfoVal; /* 1c Value for GetMessageExtraInfo */ HCURSOR cursor; /* 20 Current cursor */ INT cursor_count; /* 24 Cursor show count */ - /* 28-7c Available for more data */ + UINT active_hooks; /* 28 Bitmap of active hooks */ + /* 2c-7c Available for more data */ }; static inline struct user_thread_info *get_user_thread_info(void) diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index b30816a73b6..04457fd22dc 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2203,6 +2203,7 @@ struct get_message_reply unsigned int time; unsigned int info; unsigned int hw_id; + unsigned int active_hooks; size_t total; /* VARARG(data,bytes); */ }; @@ -3044,6 +3045,7 @@ struct set_hook_reply { struct reply_header __header; user_handle_t handle; + unsigned int active_hooks; }; @@ -3058,6 +3060,7 @@ struct remove_hook_request struct remove_hook_reply { struct reply_header __header; + unsigned int active_hooks; }; @@ -3079,6 +3082,7 @@ struct start_hook_chain_reply thread_id_t tid; void* proc; int unicode; + unsigned int active_hooks; /* VARARG(module,unicode_str); */ }; @@ -3954,6 +3958,6 @@ union generic_reply struct set_mailslot_info_reply set_mailslot_info_reply; }; -#define SERVER_PROTOCOL_VERSION 173 +#define SERVER_PROTOCOL_VERSION 174 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/hook.c b/server/hook.c index c228f987deb..125f3467ed5 100644 --- a/server/hook.c +++ b/server/hook.c @@ -172,6 +172,19 @@ inline static struct hook *get_first_hook( struct hook_table *table, int index ) return elem ? HOOK_ENTRY( elem ) : NULL; } +/* check if a given hook should run in the current thread */ +inline static int run_hook_in_current_thread( struct hook *hook ) +{ + if ((!hook->process || hook->process == current->process) && + (!(hook->flags & WINEVENT_SKIPOWNPROCESS) || hook->process != current->process)) + { + if ((!hook->thread || hook->thread == current) && + (!(hook->flags & WINEVENT_SKIPOWNTHREAD) || hook->thread != current)) + return 1; + } + return 0; +} + /* find the first non-deleted hook in the chain */ inline static struct hook *get_first_valid_hook( struct hook_table *table, int index, int event, user_handle_t win, @@ -181,22 +194,17 @@ inline static struct hook *get_first_valid_hook( struct hook_table *table, int i while (hook) { - if ((!hook->process || hook->process == current->process) && - (!(hook->flags & WINEVENT_SKIPOWNPROCESS) || hook->process != current->process)) + if (hook->proc && run_hook_in_current_thread( hook )) { - if ((!hook->thread || hook->thread == current) && - (!(hook->flags & WINEVENT_SKIPOWNTHREAD) || hook->thread != current)) + if (event >= hook->event_min && event <= hook->event_max) { - if (hook->proc && event >= hook->event_min && event <= hook->event_max) - { - if (hook->flags & WINEVENT_INCONTEXT) return hook; + if (hook->flags & WINEVENT_INCONTEXT) return hook; - /* only winevent hooks may be out of context */ - assert(hook->index + WH_MINHOOK == WH_WINEVENT); - post_win_event( hook->owner, event, win, object_id, child_id, - hook->proc, hook->module, hook->module_size, - hook->handle ); - } + /* only winevent hooks may be out of context */ + assert(hook->index + WH_MINHOOK == WH_WINEVENT); + post_win_event( hook->owner, event, win, object_id, child_id, + hook->proc, hook->module, hook->module_size, + hook->handle ); } } hook = HOOK_ENTRY( list_next( &table->hooks[index], &hook->chain ) ); @@ -213,22 +221,17 @@ static struct hook *get_next_hook( struct hook *hook, int event, user_handle_t w while ((hook = HOOK_ENTRY( list_next( &table->hooks[index], &hook->chain ) ))) { - if ((!hook->process || hook->process == current->process) && - (!(hook->flags & WINEVENT_SKIPOWNPROCESS) || hook->process != current->process)) + if (hook->proc && run_hook_in_current_thread( hook )) { - if ((!hook->thread || hook->thread == current) && - (!(hook->flags & WINEVENT_SKIPOWNTHREAD) || hook->thread != current)) + if (event >= hook->event_min && event <= hook->event_max) { - if (hook->proc && event >= hook->event_min && event <= hook->event_max) - { - if (hook->flags & WINEVENT_INCONTEXT) return hook; + if (hook->flags & WINEVENT_INCONTEXT) return hook; - /* only winevent hooks may be out of context */ - assert(hook->index + WH_MINHOOK == WH_WINEVENT); - post_win_event( hook->owner, event, win, object_id, child_id, - hook->proc, hook->module, hook->module_size, - hook->handle ); - } + /* only winevent hooks may be out of context */ + assert(hook->index + WH_MINHOOK == WH_WINEVENT); + post_win_event( hook->owner, event, win, object_id, child_id, + hook->proc, hook->module, hook->module_size, + hook->handle ); } } } @@ -314,6 +317,35 @@ void remove_thread_hooks( struct thread *thread ) } } +/* get a bitmap of active hooks in a hook table */ +static int is_hook_active( struct hook_table *table, int index ) +{ + struct hook *hook = get_first_hook( table, index ); + + while (hook) + { + if (hook->proc && run_hook_in_current_thread( hook )) return 1; + hook = HOOK_ENTRY( list_next( &table->hooks[index], &hook->chain ) ); + } + return 0; +} + +/* get a bitmap of all active hooks for the current thread */ +unsigned int get_active_hooks(void) +{ + struct hook_table *table = get_queue_hooks( current ); + unsigned int ret = 1 << 31; /* set high bit to indicate that the bitmap is valid */ + int id; + + for (id = WH_MINHOOK; id <= WH_WINEVENT; id++) + { + if ((table && is_hook_active( table, id - WH_MINHOOK )) || + (global_hooks && is_hook_active( global_hooks, id - WH_MINHOOK ))) + ret |= 1 << (id - WH_MINHOOK); + } + return ret; +} + /* set a window hook */ DECL_HANDLER(set_hook) { @@ -388,6 +420,7 @@ DECL_HANDLER(set_hook) hook->module = module; hook->module_size = module_size; reply->handle = hook->handle; + reply->active_hooks = get_active_hooks(); } else if (module) free( module ); @@ -423,6 +456,7 @@ DECL_HANDLER(remove_hook) } } remove_hook( hook ); + reply->active_hooks = get_active_hooks(); } @@ -438,11 +472,15 @@ DECL_HANDLER(start_hook_chain) return; } - if (!table || !(hook = get_first_valid_hook( table, req->id - WH_MINHOOK, req->event, req->window, req->object_id, req->child_id ))) + reply->active_hooks = get_active_hooks(); + + if (!table || !(hook = get_first_valid_hook( table, req->id - WH_MINHOOK, req->event, + req->window, req->object_id, req->child_id ))) { /* try global table */ if (!(table = global_hooks) || - !(hook = get_first_valid_hook( global_hooks, req->id - WH_MINHOOK, req->event, req->window, req->object_id, req->child_id ))) + !(hook = get_first_valid_hook( global_hooks, req->id - WH_MINHOOK, req->event, + req->window, req->object_id, req->child_id ))) return; /* no hook set */ } diff --git a/server/protocol.def b/server/protocol.def index c21c8f572ab..6b0787422c0 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1564,6 +1564,7 @@ enum message_type unsigned int time; /* message time */ unsigned int info; /* extra info (callback argument for MSG_CALLBACK_RESULT) */ unsigned int hw_id; /* id if hardware message */ + unsigned int active_hooks; /* active hooks bitmap */ size_t total; /* total size of extra data */ VARARG(data,bytes); /* message data for sent messages */ @END @@ -2129,6 +2130,7 @@ enum message_type VARARG(module,unicode_str); /* module name */ @REPLY user_handle_t handle; /* handle to the hook */ + unsigned int active_hooks; /* active hooks bitmap */ @END @@ -2137,6 +2139,8 @@ enum message_type user_handle_t handle; /* handle to the hook */ int id; /* id of the hook if handle is 0 */ void* proc; /* hook procedure if handle is 0 */ +@REPLY + unsigned int active_hooks; /* active hooks bitmap */ @END @@ -2153,6 +2157,7 @@ enum message_type thread_id_t tid; /* thread id for low-level keyboard/mouse hooks */ void* proc; /* hook procedure */ int unicode; /* is it a unicode hook? */ + unsigned int active_hooks; /* active hooks bitmap */ VARARG(module,unicode_str); /* module name */ @END diff --git a/server/queue.c b/server/queue.c index a0617a1402f..bdce76a505d 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1572,6 +1572,8 @@ DECL_HANDLER(get_message) struct msg_queue *queue = get_current_queue(); user_handle_t get_win = get_user_full_handle( req->get_win ); + reply->active_hooks = get_active_hooks(); + if (!queue) return; gettimeofday( &queue->last_get_msg, NULL ); diff --git a/server/trace.c b/server/trace.c index 65ee3e9bd89..cd056686322 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1909,6 +1909,7 @@ static void dump_get_message_reply( const struct get_message_reply *req ) fprintf( stderr, " time=%08x,", req->time ); fprintf( stderr, " info=%08x,", req->info ); fprintf( stderr, " hw_id=%08x,", req->hw_id ); + fprintf( stderr, " active_hooks=%08x,", req->active_hooks ); fprintf( stderr, " total=%d,", req->total ); fprintf( stderr, " data=" ); dump_varargs_bytes( cur_size ); @@ -2542,7 +2543,8 @@ static void dump_set_hook_request( const struct set_hook_request *req ) static void dump_set_hook_reply( const struct set_hook_reply *req ) { - fprintf( stderr, " handle=%p", req->handle ); + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " active_hooks=%08x", req->active_hooks ); } static void dump_remove_hook_request( const struct remove_hook_request *req ) @@ -2552,6 +2554,11 @@ static void dump_remove_hook_request( const struct remove_hook_request *req ) fprintf( stderr, " proc=%p", req->proc ); } +static void dump_remove_hook_reply( const struct remove_hook_reply *req ) +{ + fprintf( stderr, " active_hooks=%08x", req->active_hooks ); +} + static void dump_start_hook_chain_request( const struct start_hook_chain_request *req ) { fprintf( stderr, " id=%d,", req->id ); @@ -2568,6 +2575,7 @@ static void dump_start_hook_chain_reply( const struct start_hook_chain_reply *re fprintf( stderr, " tid=%04x,", req->tid ); fprintf( stderr, " proc=%p,", req->proc ); fprintf( stderr, " unicode=%d,", req->unicode ); + fprintf( stderr, " active_hooks=%08x,", req->active_hooks ); fprintf( stderr, " module=" ); dump_varargs_unicode_str( cur_size ); } @@ -3161,7 +3169,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_set_caret_window_reply, (dump_func)dump_set_caret_info_reply, (dump_func)dump_set_hook_reply, - (dump_func)0, + (dump_func)dump_remove_hook_reply, (dump_func)dump_start_hook_chain_reply, (dump_func)0, (dump_func)dump_get_next_hook_reply, diff --git a/server/user.h b/server/user.h index 36fd880de12..0f66a4d76ca 100644 --- a/server/user.h +++ b/server/user.h @@ -53,6 +53,7 @@ extern void cleanup_clipboard_thread( struct thread *thread ); extern void close_global_hooks(void); extern void remove_thread_hooks( struct thread *thread ); +extern unsigned int get_active_hooks(void); /* queue functions */