user: Pass all required information with internal message when chaining hooks

Vitaliy Margolen wine-patch at kievinfo.com
Fri Aug 11 22:28:29 CDT 2006


ChangeLog:
user: Pass all required information with internal message when chaining hooks
between threads, instead of restating the chain.

Currently Wine has a major problem with LL hooks (low level hooks) when second
hook is installed in a separate thread - the second hook callback is never called.
And while attempting to call it Wine almost locks up in never ending loop.
This happening because instead of calling current thread's hook callback Wine restarts
the whole hook chain from the start.

This patch deals with two sides of this problem. And actually saves some time by not calling
server one extra time.

Fixes Bug [5803], [5712] and possibly others.

 dlls/user/hook.c         |   98 +++++++++++++++++++++++-----------------------
 dlls/user/message.c      |   10 +++--
 dlls/user/user_private.h |   11 +++++
 3 files changed, 66 insertions(+), 53 deletions(-)
-------------- next part --------------
f56a91b4f4bcb85d9f19fe0aac69307e3c71ab3f
diff --git a/dlls/user/hook.c b/dlls/user/hook.c
index 0d36a6f..985a7fe 100644
--- a/dlls/user/hook.c
+++ b/dlls/user/hook.c
@@ -316,17 +316,35 @@ static void *get_hook_proc( void *proc, 
 }
 
 
+LRESULT call_thread_hook( INT id, INT code, struct hook_extra_info *h_extra, LPARAM lparam )
+{
+    struct user_thread_info *thread_info = get_user_thread_info();
+    LRESULT ret = 0;
+
+    TRACE( "calling hook %p %s code %x wp %x lp %lx module %s\n",
+           h_extra->proc, hook_names[id-WH_MINHOOK], code, h_extra->wparam, lparam,
+           debugstr_w(h_extra->module) );
+
+    if (!h_extra->module[0] || (h_extra->proc = get_hook_proc( h_extra->proc, h_extra->module )))
+    {
+        HHOOK prev = thread_info->hook;
+        thread_info->hook = h_extra->handle;
+        ret = call_hook( h_extra->proc, id, code, h_extra->wparam, lparam,
+                         h_extra->prev_unicode, h_extra->next_unicode );
+        thread_info->hook = prev;
+    }
+    return ret;
+}
+
+
 /***********************************************************************
  *		HOOK_CallHooks
  */
 LRESULT HOOK_CallHooks( INT id, INT code, WPARAM wparam, LPARAM lparam, BOOL unicode )
 {
     struct user_thread_info *thread_info = get_user_thread_info();
-    HOOKPROC proc = NULL;
-    HHOOK handle = 0;
+    struct hook_extra_info h_extra;
     DWORD pid = 0, tid = 0;
-    WCHAR module[MAX_PATH];
-    BOOL unicode_hook = FALSE;
     DWORD_PTR ret = 0;
 
     USER_CheckNotLock();
@@ -337,19 +355,22 @@ LRESULT HOOK_CallHooks( INT id, INT code
         return 0;
     }
 
+    h_extra.proc = 0;
+    h_extra.prev_unicode = unicode;
+    h_extra.wparam = wparam;
     SERVER_START_REQ( start_hook_chain )
     {
         req->id = id;
         req->event = EVENT_MIN;
-        wine_server_set_reply( req, module, sizeof(module)-sizeof(WCHAR) );
+        wine_server_set_reply( req, h_extra.module, sizeof(h_extra.module)-sizeof(WCHAR) );
         if (!wine_server_call( req ))
         {
-            module[wine_server_reply_size(req) / sizeof(WCHAR)] = 0;
-            handle       = reply->handle;
-            proc         = reply->proc;
+            h_extra.module[wine_server_reply_size(req) / sizeof(WCHAR)] = 0;
+            h_extra.handle = reply->handle;
+            h_extra.proc = reply->proc;
             pid          = reply->pid;
             tid          = reply->tid;
-            unicode_hook = reply->unicode;
+            h_extra.next_unicode = reply->unicode;
             thread_info->active_hooks = reply->active_hooks;
         }
     }
@@ -363,11 +384,11 @@ LRESULT HOOK_CallHooks( INT id, INT code
         switch(id)
         {
         case WH_KEYBOARD_LL:
-            MSG_SendInternalMessageTimeout( pid, tid, WM_WINE_KEYBOARD_LL_HOOK, wparam, lparam,
+            MSG_SendInternalMessageTimeout( pid, tid, WM_WINE_KEYBOARD_LL_HOOK, (WPARAM)&h_extra, lparam,
                                             SMTO_ABORTIFHUNG, get_ll_hook_timeout(), &ret );
             break;
         case WH_MOUSE_LL:
-            MSG_SendInternalMessageTimeout( pid, tid, WM_WINE_MOUSE_LL_HOOK, wparam, lparam,
+            MSG_SendInternalMessageTimeout( pid, tid, WM_WINE_MOUSE_LL_HOOK, (WPARAM)&h_extra, lparam,
                                             SMTO_ABORTIFHUNG, get_ll_hook_timeout(), &ret );
             break;
         default:
@@ -376,20 +397,8 @@ LRESULT HOOK_CallHooks( INT id, INT code
             break;
         }
     }
-    else if (proc)
-    {
-        TRACE( "calling hook %p %s code %x wp %x lp %lx module %s\n",
-               proc, hook_names[id-WH_MINHOOK], code, wparam, lparam, debugstr_w(module) );
-
-        if (!module[0] || (proc = get_hook_proc( proc, module )) != NULL)
-        {
-            HHOOK prev = thread_info->hook;
-            thread_info->hook = handle;
-            ret = call_hook( proc, id, code, wparam, lparam, unicode, unicode_hook );
-            thread_info->hook = prev;
-        }
-
-    }
+    else if (h_extra.proc)
+        ret = call_thread_hook( id, code, &h_extra, lparam);
     else return 0;
 
     SERVER_START_REQ( finish_hook_chain )
@@ -501,29 +510,30 @@ BOOL WINAPI UnhookWindowsHookEx( HHOOK h
 LRESULT WINAPI CallNextHookEx( HHOOK hhook, INT code, WPARAM wparam, LPARAM lparam )
 {
     struct user_thread_info *thread_info = get_user_thread_info();
-    HOOKPROC proc = NULL;
-    WCHAR module[MAX_PATH];
-    HHOOK handle = 0;
+    struct hook_extra_info h_extra;
     DWORD pid = 0, tid = 0;
     INT id = 0;
-    BOOL prev_unicode = FALSE, next_unicode = FALSE;
     DWORD_PTR ret = 0;
 
+    h_extra.proc = NULL;
+    h_extra.prev_unicode = h_extra.next_unicode = FALSE;
+    h_extra.wparam = wparam;
+
     SERVER_START_REQ( get_next_hook )
     {
         req->handle = thread_info->hook;
         req->event = EVENT_MIN;
-        wine_server_set_reply( req, module, sizeof(module)-sizeof(WCHAR) );
+        wine_server_set_reply( req, h_extra.module, sizeof(h_extra.module)-sizeof(WCHAR) );
         if (!wine_server_call_err( req ))
         {
-            module[wine_server_reply_size(req) / sizeof(WCHAR)] = 0;
-            handle       = reply->next;
+            h_extra.module[wine_server_reply_size(req) / sizeof(WCHAR)] = 0;
+            h_extra.handle = reply->next;
             id           = reply->id;
             pid          = reply->pid;
             tid          = reply->tid;
-            proc         = reply->proc;
-            prev_unicode = reply->prev_unicode;
-            next_unicode = reply->next_unicode;
+            h_extra.proc = reply->proc;
+            h_extra.prev_unicode = reply->prev_unicode;
+            h_extra.next_unicode = reply->next_unicode;
         }
     }
     SERVER_END_REQ;
@@ -536,11 +546,11 @@ LRESULT WINAPI CallNextHookEx( HHOOK hho
         switch(id)
         {
         case WH_KEYBOARD_LL:
-            MSG_SendInternalMessageTimeout( pid, tid, WM_WINE_KEYBOARD_LL_HOOK, wparam, lparam,
+            MSG_SendInternalMessageTimeout( pid, tid, WM_WINE_KEYBOARD_LL_HOOK, (WPARAM)&h_extra, lparam,
                                             SMTO_ABORTIFHUNG, get_ll_hook_timeout(), &ret );
             break;
         case WH_MOUSE_LL:
-            MSG_SendInternalMessageTimeout( pid, tid, WM_WINE_MOUSE_LL_HOOK, wparam, lparam,
+            MSG_SendInternalMessageTimeout( pid, tid, WM_WINE_MOUSE_LL_HOOK, (WPARAM)&h_extra, lparam,
                                             SMTO_ABORTIFHUNG, get_ll_hook_timeout(), &ret );
             break;
         default:
@@ -549,19 +559,9 @@ LRESULT WINAPI CallNextHookEx( HHOOK hho
             break;
         }
     }
-    else if (proc)
-    {
-        TRACE( "calling hook %p %s code %x wp %x lp %lx module %s\n",
-               proc, hook_names[id-WH_MINHOOK], code, wparam, lparam, debugstr_w(module) );
+    else if (h_extra.proc)
+        ret = call_thread_hook( id, code, &h_extra, lparam);
 
-        if (!module[0] || (proc = get_hook_proc( proc, module )) != NULL)
-        {
-            HHOOK prev = thread_info->hook;
-            thread_info->hook = handle;
-            ret = call_hook( proc, id, code, wparam, lparam, prev_unicode, next_unicode );
-            thread_info->hook = prev;
-        }
-    }
     return ret;
 }
 
diff --git a/dlls/user/message.c b/dlls/user/message.c
index 2561bcf..f2e4ab9 100644
--- a/dlls/user/message.c
+++ b/dlls/user/message.c
@@ -614,9 +614,11 @@ static size_t pack_message( HWND hwnd, U
         push_data( data, (WINDOWPOS *)lparam, sizeof(WINDOWPOS) );
         return 0;
     case WM_WINE_KEYBOARD_LL_HOOK:
+        push_data( data, (struct hook_extra_info *)wparam, sizeof(struct hook_extra_info) );
         push_data( data, (KBDLLHOOKSTRUCT *)lparam, sizeof(KBDLLHOOKSTRUCT) );
         return 0;
     case WM_WINE_MOUSE_LL_HOOK:
+        push_data( data, (struct hook_extra_info *)wparam, sizeof(struct hook_extra_info) );
         push_data( data, (MSLLHOOKSTRUCT *)lparam, sizeof(MSLLHOOKSTRUCT) );
         return 0;
     case WM_NCPAINT:
@@ -878,10 +880,10 @@ static BOOL unpack_message( HWND hwnd, U
         minsize = sizeof(DEV_BROADCAST_HDR);
         break;
     case WM_WINE_KEYBOARD_LL_HOOK:
-        minsize = sizeof(KBDLLHOOKSTRUCT);
+        minsize = sizeof(KBDLLHOOKSTRUCT) + sizeof(struct hook_extra_info);
         break;
     case WM_WINE_MOUSE_LL_HOOK:
-        minsize = sizeof(MSLLHOOKSTRUCT);
+        minsize = sizeof(MSLLHOOKSTRUCT) + sizeof(struct hook_extra_info);
         break;
     case WM_NCPAINT:
         if (*wparam <= 1) return TRUE;
@@ -1191,9 +1193,9 @@ static LRESULT handle_internal_message( 
         if (hwnd == GetDesktopWindow()) return 0;
         return (LRESULT)SetActiveWindow( (HWND)wparam );
     case WM_WINE_KEYBOARD_LL_HOOK:
-        return HOOK_CallHooks( WH_KEYBOARD_LL, HC_ACTION, wparam, lparam, TRUE );
+        return call_thread_hook( WH_KEYBOARD_LL, HC_ACTION, (struct hook_extra_info *)wparam, lparam );
     case WM_WINE_MOUSE_LL_HOOK:
-        return HOOK_CallHooks( WH_MOUSE_LL, HC_ACTION, wparam, lparam, TRUE );
+        return call_thread_hook( WH_MOUSE_LL, HC_ACTION, (struct hook_extra_info *)wparam, lparam );
     default:
         if (msg >= WM_WINE_FIRST_DRIVER_MSG && msg <= WM_WINE_LAST_DRIVER_MSG)
             return USER_Driver->pWindowMessage( hwnd, msg, wparam, lparam );
diff --git a/dlls/user/user_private.h b/dlls/user/user_private.h
index 00e9b45..368276b 100644
--- a/dlls/user/user_private.h
+++ b/dlls/user/user_private.h
@@ -97,6 +97,17 @@ enum wine_internal_message
     WM_WINE_LAST_DRIVER_MSG = 0x80001fff
 };
 
+struct hook_extra_info
+{
+    HHOOK handle;
+    HOOKPROC proc;
+    WPARAM wparam;
+    BOOL prev_unicode, next_unicode;
+    WCHAR module[MAX_PATH];
+};
+
+extern LRESULT call_thread_hook( INT id, INT code, struct hook_extra_info *h_extra, LPARAM lparam );
+
 struct tagCURSORICONINFO;
 
 typedef struct tagUSER_DRIVER {


More information about the wine-patches mailing list