user: [2/2] Pass hook handle to the destination thread. Call server to get hook information

Vitaliy Margolen wine-patch at kievinfo.com
Thu Aug 17 09:46:12 CDT 2006


ChangeLog:
user: Pass hook handle to the destination thread. Call server to get hook
information for inter-thread hooks.

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 both sides of this problem.

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

 dlls/user/hook.c         |   41 +++++++++++++++++++++++++++++++++++++----
 dlls/user/message.c      |   13 +++++++++----
 dlls/user/user_private.h |    7 +++++++
 server/hook.c            |   29 +++++++++++++++++++++++++++++
 server/protocol.def      |   13 +++++++++++++
 5 files changed, 95 insertions(+), 8 deletions(-)
-------------- next part --------------
4996abec8ab41504e16ea3cd3c676910e3f4dd1b
diff --git a/dlls/user/hook.c b/dlls/user/hook.c
index 49b4c11..6b1f857 100644
--- a/dlls/user/hook.c
+++ b/dlls/user/hook.c
@@ -330,18 +330,24 @@ static LRESULT call_hook_interthread( st
 
     if (info->tid)
     {
+        struct hook_extra_info h_extra;
+        h_extra.handle = info->handle;
+        h_extra.wparam = wparam;
+
         TRACE( "calling hook in thread %04lx %s code %x wp %x lp %lx\n",
                info->tid, hook_names[info->id-WH_MINHOOK], code, wparam, lparam );
 
         switch(info->id)
         {
         case WH_KEYBOARD_LL:
-            MSG_SendInternalMessageTimeout( info->pid, info->tid, WM_WINE_KEYBOARD_LL_HOOK, wparam, lparam,
-                                            SMTO_ABORTIFHUNG, get_ll_hook_timeout(), &ret );
+            MSG_SendInternalMessageTimeout( info->pid, info->tid, WM_WINE_KEYBOARD_LL_HOOK,
+                                            (WPARAM)&h_extra, lparam, SMTO_ABORTIFHUNG,
+                                            get_ll_hook_timeout(), &ret );
             break;
         case WH_MOUSE_LL:
-            MSG_SendInternalMessageTimeout( info->pid, info->tid, WM_WINE_MOUSE_LL_HOOK, wparam, lparam,
-                                            SMTO_ABORTIFHUNG, get_ll_hook_timeout(), &ret );
+            MSG_SendInternalMessageTimeout( info->pid, info->tid, WM_WINE_MOUSE_LL_HOOK,
+                                            (WPARAM)&h_extra, lparam, SMTO_ABORTIFHUNG,
+                                            get_ll_hook_timeout(), &ret );
             break;
         default:
             ERR("Unknown hook id %d\n", info->id);
@@ -548,6 +554,33 @@ LRESULT WINAPI CallNextHookEx( HHOOK hho
 }
 
 
+LRESULT call_current_hook( HHOOK hhook, INT code, WPARAM wparam, LPARAM lparam )
+{
+    struct hook_info info;
+
+    ZeroMemory( &info, sizeof(info) - sizeof(info.module) );
+
+    SERVER_START_REQ( get_hook_info )
+    {
+        req->handle = hhook;
+        wine_server_set_reply( req, info.module, sizeof(info.module)-sizeof(WCHAR) );
+        if (!wine_server_call_err( req ))
+        {
+            info.module[wine_server_reply_size(req) / sizeof(WCHAR)] = 0;
+            info.handle       = hhook;
+            info.id           = reply->id;
+            info.pid          = reply->pid;
+            info.tid          = reply->tid;
+            info.proc         = reply->proc;
+            info.prev_unicode = reply->unicode;
+            info.next_unicode = reply->unicode;
+        }
+    }
+    SERVER_END_REQ;
+
+    return call_hook_interthread( &info, code, wparam, lparam );
+}
+
 /***********************************************************************
  *		CallMsgFilterA (USER32.@)
  */
diff --git a/dlls/user/message.c b/dlls/user/message.c
index 2561bcf..1d782d8 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(struct hook_extra_info) + sizeof(KBDLLHOOKSTRUCT);
         break;
     case WM_WINE_MOUSE_LL_HOOK:
-        minsize = sizeof(MSLLHOOKSTRUCT);
+        minsize = sizeof(struct hook_extra_info) + sizeof(MSLLHOOKSTRUCT);
         break;
     case WM_NCPAINT:
         if (*wparam <= 1) return TRUE;
@@ -1191,9 +1193,12 @@ 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 );
     case WM_WINE_MOUSE_LL_HOOK:
-        return HOOK_CallHooks( WH_MOUSE_LL, HC_ACTION, wparam, lparam, TRUE );
+    {
+        struct hook_extra_info *h_extra = (struct hook_extra_info *)wparam;
+
+        return call_current_hook( h_extra->handle, HC_ACTION, h_extra->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..7ae3cb0 100644
--- a/dlls/user/user_private.h
+++ b/dlls/user/user_private.h
@@ -182,6 +182,12 @@ struct user_thread_info
                                                           /* 30-7c Available for more data */
 };
 
+struct hook_extra_info
+{
+    HHOOK handle;
+    WPARAM wparam;
+};
+
 static inline struct user_thread_info *get_user_thread_info(void)
 {
     return (struct user_thread_info *)NtCurrentTeb()->Win32ClientInfo;
@@ -200,6 +206,7 @@ extern HBRUSH SYSCOLOR_55AABrush;
 extern BOOL CLIPBOARD_ReleaseOwner(void);
 extern BOOL FOCUS_MouseActivate( HWND hwnd );
 extern BOOL HOOK_IsHooked( INT id );
+extern LRESULT call_current_hook( HHOOK hhook, INT code, WPARAM wparam, LPARAM lparam );
 extern LRESULT MSG_SendInternalMessageTimeout( DWORD dest_pid, DWORD dest_tid,
                                                UINT msg, WPARAM wparam, LPARAM lparam,
                                                UINT flags, UINT timeout, PDWORD_PTR res_ptr );
diff --git a/server/hook.c b/server/hook.c
index b2cb0b8..21ae119 100644
--- a/server/hook.c
+++ b/server/hook.c
@@ -567,3 +567,32 @@ DECL_HANDLER(get_next_hook)
         reply->proc = next->proc;
     }
 }
+
+
+/* get the hook's information */
+DECL_HANDLER(get_hook_info)
+{
+    struct hook *hook;
+
+    if (!(hook = get_user_object( req->handle, USER_HOOK ))) return;
+    if (hook->thread && (hook->thread != current))
+    {
+        set_error( STATUS_INVALID_HANDLE );
+        return;
+    }
+    reply->id      = hook->index + WH_MINHOOK;
+    reply->unicode = hook->unicode;
+    if (hook->module) set_reply_data( hook->module, hook->module_size );
+
+    if (run_hook_in_owner_thread( hook ))
+    {
+        reply->pid = get_process_id( hook->owner->process );
+        reply->tid = get_thread_id( hook->owner );
+    }
+    else
+    {
+        reply->pid = 0;
+        reply->tid = 0;
+    }
+    reply->proc = hook->proc;
+}
diff --git a/server/protocol.def b/server/protocol.def
index 2794dc3..784ad5f 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2367,6 +2367,19 @@ #define SET_CARET_STATE      0x04  /* se
 @END
 
 
+/* Get the hook's information */
+ at REQ(get_hook_info)
+    user_handle_t  handle;         /* handle to the current hook */
+ at REPLY
+    int            id;             /* id of the next hook */
+    process_id_t   pid;            /* process id for low-level keyboard/mouse hooks */
+    thread_id_t    tid;            /* thread id for low-level keyboard/mouse hooks */
+    void*          proc;           /* next hook procedure */
+    int            unicode;        /* is hook unicode hook? */
+    VARARG(module,unicode_str);    /* module name */
+ at END
+
+
 /* Create a window class */
 @REQ(create_class)
     int            local;          /* is it a local class? */


More information about the wine-patches mailing list