Run WH_KEYBOARD_LL and WH_MOUSE_LL hooks in the context of the thread
that set the hook.
diff --git a/server/hook.c b/server/hook.c
index 65bd3ba..fa42d8d 100644
--- a/server/hook.c
+++ b/server/hook.c
@@ -28,6 +28,7 @@
#include "winuser.h"
#include "object.h"
+#include "process.h"
#include "request.h"
#include "user.h"
@@ -91,16 +92,16 @@
}
/* create a new hook and add it to the specified table */
-static struct hook *add_hook( struct thread *thread, int index )
+static struct hook *add_hook( struct thread *thread, int index, int global )
{
struct hook *hook;
- struct hook_table *table = thread ? get_queue_hooks(thread) : global_hooks;
+ struct hook_table *table = global ? global_hooks : get_queue_hooks(thread);
if (!table)
{
if (!(table = alloc_hook_table())) return NULL;
- if (thread) set_queue_hooks( thread, table );
- else global_hooks = table;
+ if (global) global_hooks = table;
+ else set_queue_hooks( thread, table );
}
if (!(hook = mem_alloc( sizeof(*hook) ))) return NULL;
@@ -145,7 +146,10 @@
/* get the hook table that a given hook belongs to */
inline static struct hook_table *get_table( struct hook *hook )
{
- return hook->thread ? get_queue_hooks(hook->thread) : global_hooks;
+ if (!hook->thread) return global_hooks;
+ if (hook->index + WH_MINHOOK == WH_KEYBOARD_LL) return global_hooks;
+ if (hook->index + WH_MINHOOK == WH_MOUSE_LL) return global_hooks;
+ return get_queue_hooks(hook->thread);
}
/* get the first hook in the chain */
@@ -236,6 +240,25 @@
}
}
+/* remove all global hooks owned by a given thread */
+void remove_thread_hooks( struct thread *thread )
+{
+ int index;
+
+ if (!global_hooks) return;
+
+ /* only low-level keyboard/mouse global hooks can be owned by a thread */
+ for (index = WH_KEYBOARD_LL - WH_MINHOOK; index <= WH_MOUSE_LL - WH_MINHOOK; index++)
+ {
+ struct hook *hook = get_first_hook( global_hooks, index );
+ while (hook)
+ {
+ struct hook *next = HOOK_ENTRY( list_next( &global_hooks->hooks[index], &hook->chain ) );
+ if (hook->thread == thread) remove_hook( hook );
+ hook = next;
+ }
+ }
+}
/* set a window hook */
DECL_HANDLER(set_hook)
@@ -243,6 +266,7 @@
struct thread *thread;
struct hook *hook;
WCHAR *module;
+ int global;
size_t module_size = get_req_data_size();
if (!req->proc || req->id < WH_MINHOOK || req->id > WH_MAXHOOK)
@@ -250,7 +274,14 @@
set_error( STATUS_INVALID_PARAMETER );
return;
}
- if (!req->tid)
+ if (req->id == WH_KEYBOARD_LL || req->id == WH_MOUSE_LL)
+ {
+ /* low-level hardware hooks are special: always global, but without a module */
+ thread = (struct thread *)grab_object( current );
+ module = NULL;
+ global = 1;
+ }
+ else if (!req->tid)
{
if (!module_size)
{
@@ -259,14 +290,16 @@
}
if (!(module = memdup( get_req_data(), module_size ))) return;
thread = NULL;
+ global = 1;
}
else
{
module = NULL;
+ global = 0;
if (!(thread = get_thread_from_id( req->tid ))) return;
}
- if ((hook = add_hook( thread, req->id - WH_MINHOOK )))
+ if ((hook = add_hook( thread, req->id - WH_MINHOOK, global )))
{
hook->proc = req->proc;
hook->unicode = req->unicode;
@@ -319,8 +352,20 @@
!(hook = get_first_valid_hook( global_hooks, req->id - WH_MINHOOK )))
return; /* no hook set */
}
+
+ if (hook->thread && hook->thread != current) /* must run in other thread */
+ {
+ reply->pid = get_process_id( hook->thread->process );
+ reply->tid = get_thread_id( hook->thread );
+ reply->proc = 0;
+ }
+ else
+ {
+ reply->pid = 0;
+ reply->tid = 0;
+ reply->proc = hook->proc;
+ }
reply->handle = hook->handle;
- reply->proc = hook->proc;
reply->unicode = hook->unicode;
table->counts[hook->index]++;
if (hook->module) set_reply_data( hook->module, hook->module_size );
@@ -358,9 +403,20 @@
{
reply->next = next->handle;
reply->id = next->index + WH_MINHOOK;
- reply->proc = next->proc;
reply->prev_unicode = hook->unicode;
reply->next_unicode = next->unicode;
if (next->module) set_reply_data( next->module, next->module_size );
+ if (next->thread && next->thread != current)
+ {
+ reply->pid = get_process_id( next->thread->process );
+ reply->tid = get_thread_id( next->thread );
+ reply->proc = 0;
+ }
+ else
+ {
+ reply->pid = 0;
+ reply->tid = 0;
+ reply->proc = next->proc;
+ }
}
}
diff --git a/server/protocol.def b/server/protocol.def
index 6a8c460..7020c9c 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2108,6 +2108,8 @@
int id; /* id of the hook */
@REPLY
user_handle_t handle; /* handle to 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; /* hook procedure */
int unicode; /* is it a unicode hook? */
VARARG(module,unicode_str); /* module name */
@@ -2126,6 +2128,8 @@
@REPLY
user_handle_t next; /* handle to the next hook */
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 prev_unicode; /* was the previous a unicode hook? */
int next_unicode; /* is the next a unicode hook? */
diff --git a/server/queue.c b/server/queue.c
index ce72462..eb2c11c 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -239,6 +239,7 @@
{
struct process *process = thread->process;
+ remove_thread_hooks( thread );
if (!thread->queue) return;
if (process->queue == thread->queue) /* is it the process main queue? */
{
diff --git a/server/trace.c b/server/trace.c
index 5c7970c..bfab082 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -2437,6 +2437,8 @@
static void dump_start_hook_chain_reply( const struct start_hook_chain_reply *req )
{
fprintf( stderr, " handle=%p,", req->handle );
+ fprintf( stderr, " pid=%04x,", req->pid );
+ fprintf( stderr, " tid=%04x,", req->tid );
fprintf( stderr, " proc=%p,", req->proc );
fprintf( stderr, " unicode=%d,", req->unicode );
fprintf( stderr, " module=" );
@@ -2457,6 +2459,8 @@
{
fprintf( stderr, " next=%p,", req->next );
fprintf( stderr, " id=%d,", req->id );
+ fprintf( stderr, " pid=%04x,", req->pid );
+ fprintf( stderr, " tid=%04x,", req->tid );
fprintf( stderr, " proc=%p,", req->proc );
fprintf( stderr, " prev_unicode=%d,", req->prev_unicode );
fprintf( stderr, " next_unicode=%d,", req->next_unicode );
diff --git a/server/user.h b/server/user.h
index e4229a0..a075dd7 100644
--- a/server/user.h
+++ b/server/user.h
@@ -50,6 +50,7 @@
/* hook functions */
extern void close_global_hooks(void);
+extern void remove_thread_hooks( struct thread *thread );
/* queue functions */