Release 961023
[wine/multimedia.git] / windows / hook.c
blobbf32483450c54aa3579563d84b7625c4b7fda1e1
1 /*
2 * Windows hook functions
4 * Copyright 1994, 1995 Alexandre Julliard
6 * Based on investigations by Alex Korobka
7 */
9 /*
10 * Warning!
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 */
17 #include "hook.h"
18 #include "queue.h"
19 #include "user.h"
20 #include "stddebug.h"
21 #include "debug.h"
23 #pragma pack(1)
25 /* Hook data (pointed to by a HHOOK) */
26 typedef struct
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 */
34 } HOOKDATA;
36 #pragma pack(4)
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 /***********************************************************************
45 * HOOK_GetNextHook
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 /***********************************************************************
61 * HOOK_GetHook
63 * Get the first hook for a given type.
65 HANDLE16 HOOK_GetHook( INT16 id , HQUEUE16 hQueue )
67 MESSAGEQUEUE *queue;
68 HANDLE16 hook = 0;
70 if ((queue = (MESSAGEQUEUE *)GlobalLock16( hQueue )) != NULL)
71 hook = queue->hooks[id - WH_MINHOOK];
72 if (!hook) hook = HOOK_systemHooks[id - WH_MINHOOK];
73 return hook;
77 /***********************************************************************
78 * HOOK_GetProc16
80 HOOKPROC16 HOOK_GetProc16( HHOOK hhook )
82 HOOKDATA *data;
83 if (HIWORD(hhook) != HOOK_MAGIC) return NULL;
84 if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR( LOWORD(hhook) ))) return NULL;
85 return data->proc;
89 /***********************************************************************
90 * HOOK_SetHook
92 * Install a given hook.
94 static HANDLE16 HOOK_SetHook( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst,
95 HTASK16 hTask )
97 HOOKDATA *data;
98 HANDLE16 handle;
99 HQUEUE16 hQueue = 0;
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;
114 if (id == WH_DEBUG)
116 fprintf( stdnimp,"WH_DEBUG is broken in 16-bit Windows.\n");
117 return 0;
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 );
131 data->proc = proc;
132 data->id = id;
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 */
140 if (hQueue)
142 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
143 data->next = queue->hooks[id - WH_MINHOOK];
144 queue->hooks[id - WH_MINHOOK] = handle;
146 else
148 data->next = HOOK_systemHooks[id - WH_MINHOOK];
149 HOOK_systemHooks[id - WH_MINHOOK] = handle;
151 return handle;
155 /***********************************************************************
156 * HOOK_RemoveHook
158 * Remove a hook from the list.
160 static BOOL32 HOOK_RemoveHook( HANDLE16 hook )
162 HOOKDATA *data;
163 HANDLE16 *prevHook;
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;
173 return TRUE;
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 );
194 return TRUE;
198 /***********************************************************************
199 * HOOK_CallHook
201 * Call a hook procedure.
203 static LRESULT HOOK_CallHook( HANDLE16 hook, INT16 code,
204 WPARAM16 wParam, LPARAM lParam )
206 HOOKDATA *data;
207 MESSAGEQUEUE *queue;
208 HANDLE16 prevHook;
209 LRESULT ret;
211 /* Find the first hook with a valid proc */
213 for (;;)
215 if (!hook) return 0;
216 if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook))) return 0;
217 if (data->proc) break;
218 hook = data->next;
221 /* Now call it */
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 );
236 return ret;
240 /***********************************************************************
241 * HOOK_CallHooks
243 * Call a hook chain.
245 LRESULT HOOK_CallHooks( INT16 id, INT16 code, WPARAM16 wParam, LPARAM lParam )
247 HANDLE16 hook = HOOK_GetHook( id , GetTaskQueue(0) );
248 if (!hook) return 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 */
260 HOOKDATA* hptr;
261 HHOOK hook, next;
262 int id;
264 for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ )
266 hook = HOOK_systemHooks[id - WH_MINHOOK];
267 while( hook )
268 if( (hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook)) )
270 next = hptr->next;
271 if( hptr->ownerModule == hModule )
273 hptr->inHookProc = 0;
274 HOOK_RemoveHook(hook);
276 hook = next;
278 else hook = 0;
282 /***********************************************************************
283 * HOOK_FreeQueueHooks
285 void HOOK_FreeQueueHooks( HQUEUE16 hQueue )
287 /* remove all hooks registered by this queue */
289 HOOKDATA* hptr = NULL;
290 HHOOK hook, next;
291 int id;
293 for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ )
295 hook = HOOK_GetHook( id, hQueue );
296 while( hook )
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);
306 hook = next;
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 );
333 while (hook)
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. */
351 MESSAGEQUEUE *queue;
352 HANDLE16 next;
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,
375 HTASK16 hTask )
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)
397 HANDLE16 next;
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 );