user: [2/2] Pass hook handle to the destination thread. [try3]

Vitaliy vitaliy at kievinfo.com
Tue Sep 5 00:38:51 CDT 2006


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

Changes since last try:
- Fixed message unpacking for inter-process messages.

------------------------------------------------------------------------------
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      |   20 ++++++++++++++------
 dlls/user/user_private.h |    7 +++++++
 server/hook.c            |   29 +++++++++++++++++++++++++++++
 server/protocol.def      |   13 +++++++++++++
 5 files changed, 100 insertions(+), 10 deletions(-)


-------------- next part --------------
1080acaaa582a55945da950d2416463b1eb68a0d
diff --git a/dlls/user/hook.c b/dlls/user/hook.c
index ad36ea3..d3b9e54 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..a35750e 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,11 +880,14 @@ static BOOL unpack_message( HWND hwnd, U
         minsize = sizeof(DEV_BROADCAST_HDR);
         break;
     case WM_WINE_KEYBOARD_LL_HOOK:
-        minsize = sizeof(KBDLLHOOKSTRUCT);
-        break;
     case WM_WINE_MOUSE_LL_HOOK:
-        minsize = sizeof(MSLLHOOKSTRUCT);
-        break;
+        minsize = sizeof(struct hook_extra_info) +
+                  (message == WM_WINE_KEYBOARD_LL_HOOK ? sizeof(KBDLLHOOKSTRUCT)
+                                                       : sizeof(MSLLHOOKSTRUCT));
+        if (size < minsize) return FALSE;
+        *wparam = (WPARAM)(*buffer);
+        *lparam = (LPARAM)((char*)*buffer + sizeof(struct hook_extra_info));
+        return TRUE;
     case WM_NCPAINT:
         if (*wparam <= 1) return TRUE;
         FIXME( "WM_NCPAINT hdc unpacking not supported\n" );
@@ -1191,9 +1196,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