2 * Windows hook functions
4 * Copyright 1994, 1995 Alexandre Julliard
6 * Based on investigations by Alex Korobka
11 * A HHOOK is a 32-bit handle for compatibility with Windows 3.0 where it was
12 * a pointer to the next function. Now it is in fact composed of a USER heap
13 * handle in the low 16 bits and of a HOOK_MAGIC value in the high 16 bits.
16 #define NO_TRANSITION_TYPES /* This file is Win32-clean */
25 /* Hook data (pointed to by a HHOOK) */
28 HANDLE16 next
; /* 00 Next hook in chain */
29 HOOKPROC16 proc WINE_PACKED
; /* 02 Hook procedure */
30 INT16 id
; /* 06 Hook id (WH_xxx) */
31 HQUEUE16 ownerQueue
; /* 08 Owner queue (0 for system hook) */
32 HMODULE16 ownerModule
; /* 0a Owner module */
33 WORD inHookProc
; /* 0c TRUE if in this->proc */
38 #define HOOK_MAGIC ((int)'H' | (int)'K' << 8) /* 'HK' */
40 /* This should probably reside in USER heap */
41 static HANDLE16 HOOK_systemHooks
[WH_NB_HOOKS
] = { 0, };
44 /***********************************************************************
47 * Get the next hook of a given hook.
49 static HANDLE16
HOOK_GetNextHook( HANDLE16 hook
)
51 HOOKDATA
*data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR( hook
);
52 if (!data
|| !hook
) return 0;
53 if (data
->next
) return data
->next
;
54 if (!data
->ownerQueue
) return 0; /* Already system hook */
55 /* Now start enumerating the system hooks */
56 return HOOK_systemHooks
[data
->id
- WH_MINHOOK
];
60 /***********************************************************************
63 * Get the first hook for a given type.
65 HANDLE16
HOOK_GetHook( INT16 id
, HQUEUE16 hQueue
)
70 if ((queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
)) != NULL
)
71 hook
= queue
->hooks
[id
- WH_MINHOOK
];
72 if (!hook
) hook
= HOOK_systemHooks
[id
- WH_MINHOOK
];
77 /***********************************************************************
80 HOOKPROC16
HOOK_GetProc16( HHOOK hhook
)
83 if (HIWORD(hhook
) != HOOK_MAGIC
) return NULL
;
84 if (!(data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR( LOWORD(hhook
) ))) return NULL
;
89 /***********************************************************************
92 * Install a given hook.
94 static HANDLE16
HOOK_SetHook( INT16 id
, HOOKPROC16 proc
, HINSTANCE16 hInst
,
101 if ((id
< WH_MINHOOK
) || (id
> WH_MAXHOOK
)) return 0;
102 if (!(hInst
= GetExePtr( hInst
))) return 0;
104 dprintf_hook( stddeb
, "Setting hook %d: %08x %04x %04x\n",
105 id
, (UINT32
)proc
, hInst
, hTask
);
107 if (hTask
) /* Task-specific hook */
109 if ((id
== WH_JOURNALRECORD
) || (id
== WH_JOURNALPLAYBACK
) ||
110 (id
== WH_SYSMSGFILTER
)) return 0; /* System-only hooks */
111 if (!(hQueue
= GetTaskQueue( hTask
))) return 0;
116 fprintf( stdnimp
,"WH_DEBUG is broken in 16-bit Windows.\n");
119 else if (id
== WH_CBT
|| id
== WH_SHELL
)
121 fprintf( stdnimp
, "Half-implemented hook set: (%s,%08lx,%04x,%04x)!\n",
122 (id
==WH_CBT
)?"WH_CBT":"WH_SHELL", (DWORD
)proc
, hInst
, hTask
);
125 if (id
== WH_JOURNALPLAYBACK
) EnableHardwareInput(FALSE
);
127 /* Create the hook structure */
129 if (!(handle
= USER_HEAP_ALLOC( sizeof(HOOKDATA
) ))) return 0;
130 data
= (HOOKDATA
*) USER_HEAP_LIN_ADDR( handle
);
133 data
->ownerQueue
= hQueue
;
134 data
->ownerModule
= hInst
;
135 data
->inHookProc
= 0;
136 dprintf_hook( stddeb
, "Setting hook %d: ret=%04x\n", id
, handle
);
138 /* Insert it in the correct linked list */
142 MESSAGEQUEUE
*queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
);
143 data
->next
= queue
->hooks
[id
- WH_MINHOOK
];
144 queue
->hooks
[id
- WH_MINHOOK
] = handle
;
148 data
->next
= HOOK_systemHooks
[id
- WH_MINHOOK
];
149 HOOK_systemHooks
[id
- WH_MINHOOK
] = handle
;
155 /***********************************************************************
158 * Remove a hook from the list.
160 static BOOL32
HOOK_RemoveHook( HANDLE16 hook
)
165 dprintf_hook( stddeb
, "Removing hook %04x\n", hook
);
167 if (!(data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
))) return FALSE
;
168 if (data
->inHookProc
)
170 /* Mark it for deletion later on */
171 dprintf_hook( stddeb
, "Hook still running, deletion delayed\n" );
172 data
->proc
= (HOOKPROC16
)0;
176 if (data
->id
== WH_JOURNALPLAYBACK
) EnableHardwareInput(TRUE
);
178 /* Remove it from the linked list */
180 if (data
->ownerQueue
)
182 MESSAGEQUEUE
*queue
= (MESSAGEQUEUE
*)GlobalLock16( data
->ownerQueue
);
183 if (!queue
) return FALSE
;
184 prevHook
= &queue
->hooks
[data
->id
- WH_MINHOOK
];
186 else prevHook
= &HOOK_systemHooks
[data
->id
- WH_MINHOOK
];
188 while (*prevHook
&& *prevHook
!= hook
)
189 prevHook
= &((HOOKDATA
*)USER_HEAP_LIN_ADDR(*prevHook
))->next
;
191 if (!*prevHook
) return FALSE
;
192 *prevHook
= data
->next
;
193 USER_HEAP_FREE( hook
);
198 /***********************************************************************
201 * Call a hook procedure.
203 static LRESULT
HOOK_CallHook( HANDLE16 hook
, INT16 code
,
204 WPARAM16 wParam
, LPARAM lParam
)
211 /* Find the first hook with a valid proc */
216 if (!(data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
))) return 0;
217 if (data
->proc
) break;
223 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
224 prevHook
= queue
->hCurHook
;
225 queue
->hCurHook
= hook
;
226 data
->inHookProc
= 1;
228 dprintf_hook( stddeb
, "Calling hook %04x: proc=%p %d %04lx %08lx\n",
229 hook
, data
->proc
, code
, (DWORD
)wParam
, lParam
);
230 ret
= data
->proc( code
, wParam
, lParam
);
231 dprintf_hook( stddeb
, "Ret hook %04x = %08lx\n", hook
, ret
);
233 data
->inHookProc
= 0;
234 queue
->hCurHook
= prevHook
;
235 if (!data
->proc
) HOOK_RemoveHook( hook
);
240 /***********************************************************************
245 LRESULT
HOOK_CallHooks( INT16 id
, INT16 code
, WPARAM16 wParam
, LPARAM lParam
)
247 HANDLE16 hook
= HOOK_GetHook( id
, GetTaskQueue(0) );
249 return HOOK_CallHook( hook
, code
, wParam
, lParam
);
253 /***********************************************************************
254 * HOOK_FreeModuleHooks
256 void HOOK_FreeModuleHooks( HMODULE16 hModule
)
258 /* remove all system hooks registered by this module */
264 for( id
= WH_MINHOOK
; id
<= WH_MAXHOOK
; id
++ )
266 hook
= HOOK_systemHooks
[id
- WH_MINHOOK
];
268 if( (hptr
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
)) )
271 if( hptr
->ownerModule
== hModule
)
273 hptr
->inHookProc
= 0;
274 HOOK_RemoveHook(hook
);
282 /***********************************************************************
283 * HOOK_FreeQueueHooks
285 void HOOK_FreeQueueHooks( HQUEUE16 hQueue
)
287 /* remove all hooks registered by this queue */
289 HOOKDATA
* hptr
= NULL
;
293 for( id
= WH_MINHOOK
; id
<= WH_MAXHOOK
; id
++ )
295 hook
= HOOK_GetHook( id
, hQueue
);
298 next
= HOOK_GetNextHook(hook
);
300 hptr
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
);
301 if( hptr
&& hptr
->ownerQueue
== hQueue
)
303 hptr
->inHookProc
= 0;
304 HOOK_RemoveHook(hook
);
312 /***********************************************************************
313 * SetWindowsHook16 (USER.121)
315 FARPROC16
SetWindowsHook16( INT16 id
, HOOKPROC16 proc
)
317 HTASK16 hTask
= (id
== WH_MSGFILTER
) ? GetCurrentTask() : 0;
318 HANDLE16 handle
= HOOK_SetHook( id
, proc
, 0, hTask
);
320 return (handle
) ? (FARPROC16
)MAKELONG( handle
, HOOK_MAGIC
) : NULL
;
324 /***********************************************************************
325 * UnhookWindowsHook16 (USER.234)
327 BOOL16
UnhookWindowsHook16( INT16 id
, HOOKPROC16 proc
)
329 HANDLE16 hook
= HOOK_GetHook( id
, 0 );
331 dprintf_hook( stddeb
, "UnhookWindowsHook: %d %08lx\n", id
, (DWORD
)proc
);
335 HOOKDATA
*data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
);
336 if (data
->proc
== proc
) break;
337 hook
= HOOK_GetNextHook( hook
);
339 if (!hook
) return FALSE
;
340 return HOOK_RemoveHook( hook
);
344 /***********************************************************************
345 * DefHookProc (USER.235)
347 LRESULT
DefHookProc( INT16 code
, WPARAM16 wParam
, LPARAM lParam
, HHOOK
*hhook
)
349 /* Note: the *hhook parameter is never used, since we rely on the
350 * current hook value from the task queue to find the next hook. */
354 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
355 if (!(next
= HOOK_GetNextHook( queue
->hCurHook
))) return 0;
356 return HOOK_CallHook( next
, code
, wParam
, lParam
);
360 /***********************************************************************
361 * CallMsgFilter (USER.123)
363 BOOL16
CallMsgFilter( SEGPTR msg
, INT16 code
)
365 if (GetSysModalWindow16()) return FALSE
;
366 if (HOOK_CallHooks( WH_SYSMSGFILTER
, code
, 0, (LPARAM
)msg
)) return TRUE
;
367 return HOOK_CallHooks( WH_MSGFILTER
, code
, 0, (LPARAM
)msg
);
371 /***********************************************************************
372 * SetWindowsHookEx16 (USER.291)
374 HHOOK
SetWindowsHookEx16( INT16 id
, HOOKPROC16 proc
, HINSTANCE16 hInst
,
377 HANDLE16 handle
= HOOK_SetHook( id
, proc
, hInst
, hTask
);
378 return (handle
) ? MAKELONG( handle
, HOOK_MAGIC
) : NULL
;
382 /***********************************************************************
383 * UnhookWindowHookEx16 (USER.292)
385 BOOL16
UnhookWindowsHookEx16( HHOOK hhook
)
387 if (HIWORD(hhook
) != HOOK_MAGIC
) return FALSE
; /* Not a new format hook */
388 return HOOK_RemoveHook( LOWORD(hhook
) );
392 /***********************************************************************
393 * CallNextHookEx (USER.293)
395 LRESULT
CallNextHookEx(HHOOK hhook
, INT16 code
, WPARAM16 wParam
, LPARAM lParam
)
398 if (HIWORD(hhook
) != HOOK_MAGIC
) return 0; /* Not a new format hook */
399 if (!(next
= HOOK_GetNextHook( LOWORD(hhook
) ))) return 0;
400 return HOOK_CallHook( next
, code
, wParam
, lParam
);