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
)
82 HOOKDATA
*data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR( hhook
);
83 return data
? data
->proc
: NULL
;
87 /***********************************************************************
90 * Install a given hook.
92 static HANDLE16
HOOK_SetHook( INT16 id
, HOOKPROC16 proc
, HINSTANCE16 hInst
,
99 if ((id
< WH_MINHOOK
) || (id
> WH_MAXHOOK
)) return 0;
100 if (!(hInst
= GetExePtr( hInst
))) return 0;
102 dprintf_hook( stddeb
, "Setting hook %d: %08x %04x %04x\n",
103 id
, (UINT32
)proc
, hInst
, hTask
);
105 if (hTask
) /* Task-specific hook */
107 if ((id
== WH_JOURNALRECORD
) || (id
== WH_JOURNALPLAYBACK
) ||
108 (id
== WH_SYSMSGFILTER
)) return 0; /* System-only hooks */
109 if (!(hQueue
= GetTaskQueue( hTask
))) return 0;
114 fprintf( stdnimp
,"WH_DEBUG is broken in 16-bit Windows.\n");
117 else if (id
== WH_CBT
|| id
== WH_SHELL
)
119 fprintf( stdnimp
, "Half-implemented hook set: (%s,%08lx,%04x,%04x)!\n",
120 (id
==WH_CBT
)?"WH_CBT":"WH_SHELL", (DWORD
)proc
, hInst
, hTask
);
123 if (id
== WH_JOURNALPLAYBACK
) EnableHardwareInput(FALSE
);
125 /* Create the hook structure */
127 if (!(handle
= USER_HEAP_ALLOC( sizeof(HOOKDATA
) ))) return 0;
128 data
= (HOOKDATA
*) USER_HEAP_LIN_ADDR( handle
);
131 data
->ownerQueue
= hQueue
;
132 data
->ownerModule
= hInst
;
133 data
->inHookProc
= 0;
134 dprintf_hook( stddeb
, "Setting hook %d: ret=%04x\n", id
, handle
);
136 /* Insert it in the correct linked list */
140 MESSAGEQUEUE
*queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
);
141 data
->next
= queue
->hooks
[id
- WH_MINHOOK
];
142 queue
->hooks
[id
- WH_MINHOOK
] = handle
;
146 data
->next
= HOOK_systemHooks
[id
- WH_MINHOOK
];
147 HOOK_systemHooks
[id
- WH_MINHOOK
] = handle
;
153 /***********************************************************************
156 * Remove a hook from the list.
158 static BOOL32
HOOK_RemoveHook( HANDLE16 hook
)
163 dprintf_hook( stddeb
, "Removing hook %04x\n", hook
);
165 if (!(data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
))) return FALSE
;
166 if (data
->inHookProc
)
168 /* Mark it for deletion later on */
169 dprintf_hook( stddeb
, "Hook still running, deletion delayed\n" );
170 data
->proc
= (HOOKPROC16
)0;
174 if (data
->id
== WH_JOURNALPLAYBACK
) EnableHardwareInput(TRUE
);
176 /* Remove it from the linked list */
178 if (data
->ownerQueue
)
180 MESSAGEQUEUE
*queue
= (MESSAGEQUEUE
*)GlobalLock16( data
->ownerQueue
);
181 if (!queue
) return FALSE
;
182 prevHook
= &queue
->hooks
[data
->id
- WH_MINHOOK
];
184 else prevHook
= &HOOK_systemHooks
[data
->id
- WH_MINHOOK
];
186 while (*prevHook
&& *prevHook
!= hook
)
187 prevHook
= &((HOOKDATA
*)USER_HEAP_LIN_ADDR(*prevHook
))->next
;
189 if (!*prevHook
) return FALSE
;
190 *prevHook
= data
->next
;
191 USER_HEAP_FREE( hook
);
196 /***********************************************************************
199 * Call a hook procedure.
201 static LRESULT
HOOK_CallHook( HANDLE16 hook
, INT16 code
,
202 WPARAM16 wParam
, LPARAM lParam
)
209 /* Find the first hook with a valid proc */
214 if (!(data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
))) return 0;
215 if (data
->proc
) break;
221 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
222 prevHook
= queue
->hCurHook
;
223 queue
->hCurHook
= hook
;
224 data
->inHookProc
= 1;
226 dprintf_hook( stddeb
, "Calling hook %04x: proc=%p %d %04lx %08lx\n",
227 hook
, data
->proc
, code
, (DWORD
)wParam
, lParam
);
228 ret
= data
->proc( code
, wParam
, lParam
);
229 dprintf_hook( stddeb
, "Ret hook %04x = %08lx\n", hook
, ret
);
231 data
->inHookProc
= 0;
232 queue
->hCurHook
= prevHook
;
233 if (!data
->proc
) HOOK_RemoveHook( hook
);
238 /***********************************************************************
243 LRESULT
HOOK_CallHooks( INT16 id
, INT16 code
, WPARAM16 wParam
, LPARAM lParam
)
245 HANDLE16 hook
= HOOK_GetHook( id
, GetTaskQueue(0) );
247 return HOOK_CallHook( hook
, code
, wParam
, lParam
);
251 /***********************************************************************
252 * HOOK_FreeModuleHooks
254 void HOOK_FreeModuleHooks( HMODULE16 hModule
)
256 /* remove all system hooks registered by this module */
262 for( id
= WH_MINHOOK
; id
<= WH_MAXHOOK
; id
++ )
264 hook
= HOOK_systemHooks
[id
- WH_MINHOOK
];
266 if( (hptr
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
)) )
269 if( hptr
->ownerModule
== hModule
)
271 hptr
->inHookProc
= 0;
272 HOOK_RemoveHook(hook
);
280 /***********************************************************************
281 * HOOK_FreeQueueHooks
283 void HOOK_FreeQueueHooks( HQUEUE16 hQueue
)
285 /* remove all hooks registered by this queue */
287 HOOKDATA
* hptr
= NULL
;
291 for( id
= WH_MINHOOK
; id
<= WH_MAXHOOK
; id
++ )
293 hook
= HOOK_GetHook( id
, hQueue
);
296 next
= HOOK_GetNextHook(hook
);
298 hptr
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
);
299 if( hptr
&& hptr
->ownerQueue
== hQueue
)
301 hptr
->inHookProc
= 0;
302 HOOK_RemoveHook(hook
);
310 /***********************************************************************
311 * SetWindowsHook16 (USER.121)
313 FARPROC16
SetWindowsHook16( INT16 id
, HOOKPROC16 proc
)
315 HTASK16 hTask
= (id
== WH_MSGFILTER
) ? GetCurrentTask() : 0;
316 HANDLE16 handle
= HOOK_SetHook( id
, proc
, 0, hTask
);
318 return (handle
) ? (FARPROC16
)MAKELONG( handle
, HOOK_MAGIC
) : NULL
;
322 /***********************************************************************
323 * UnhookWindowsHook16 (USER.234)
325 BOOL16
UnhookWindowsHook16( INT16 id
, HOOKPROC16 proc
)
327 HANDLE16 hook
= HOOK_GetHook( id
, 0 );
329 dprintf_hook( stddeb
, "UnhookWindowsHook: %d %08lx\n", id
, (DWORD
)proc
);
333 HOOKDATA
*data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
);
334 if (data
->proc
== proc
) break;
335 hook
= HOOK_GetNextHook( hook
);
337 if (!hook
) return FALSE
;
338 return HOOK_RemoveHook( hook
);
342 /***********************************************************************
343 * DefHookProc (USER.235)
345 LRESULT
DefHookProc( INT16 code
, WPARAM16 wParam
, LPARAM lParam
, HHOOK
*hhook
)
347 /* Note: the *hhook parameter is never used, since we rely on the
348 * current hook value from the task queue to find the next hook. */
352 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
353 if (!(next
= HOOK_GetNextHook( queue
->hCurHook
))) return 0;
354 return HOOK_CallHook( next
, code
, wParam
, lParam
);
358 /***********************************************************************
359 * CallMsgFilter (USER.123)
361 BOOL16
CallMsgFilter( SEGPTR msg
, INT16 code
)
363 if (GetSysModalWindow16()) return FALSE
;
364 if (HOOK_CallHooks( WH_SYSMSGFILTER
, code
, 0, (LPARAM
)msg
)) return TRUE
;
365 return HOOK_CallHooks( WH_MSGFILTER
, code
, 0, (LPARAM
)msg
);
369 /***********************************************************************
370 * SetWindowsHookEx16 (USER.291)
372 HHOOK
SetWindowsHookEx16( INT16 id
, HOOKPROC16 proc
, HINSTANCE16 hInst
,
375 HANDLE16 handle
= HOOK_SetHook( id
, proc
, hInst
, hTask
);
376 return (handle
) ? MAKELONG( handle
, HOOK_MAGIC
) : NULL
;
380 /***********************************************************************
381 * UnhookWindowHookEx16 (USER.292)
383 BOOL16
UnhookWindowsHookEx16( HHOOK hhook
)
385 if (HIWORD(hhook
) != HOOK_MAGIC
) return FALSE
; /* Not a new format hook */
386 return HOOK_RemoveHook( LOWORD(hhook
) );
390 /***********************************************************************
391 * CallNextHookEx (USER.293)
393 LRESULT
CallNextHookEx(HHOOK hhook
, INT16 code
, WPARAM16 wParam
, LPARAM lParam
)
396 if (HIWORD(hhook
) != HOOK_MAGIC
) return 0; /* Not a new format hook */
397 if (!(next
= HOOK_GetNextHook( LOWORD(hhook
) ))) return 0;
398 return HOOK_CallHook( next
, code
, wParam
, lParam
);