Release 960521
[wine/multimedia.git] / windows / hook.c
blob74c225928661adfb1b068d9d46d3c8349e9d47ec
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
14 * (except for WINELIB32 where it is a 32-bit handle). -- AJ
17 #include "hook.h"
18 #include "queue.h"
19 #include "user.h"
20 #include "stddebug.h"
21 #include "debug.h"
23 /* This should probably reside in USER heap */
24 static HANDLE HOOK_systemHooks[WH_NB_HOOKS] = { 0, };
27 /***********************************************************************
28 * HOOK_GetNextHook
30 * Get the next hook of a given hook.
32 static HANDLE HOOK_GetNextHook( HANDLE hook )
34 HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR( hook );
35 if (!data || !hook) return 0;
36 if (data->next) return data->next;
37 if (!data->ownerQueue) return 0; /* Already system hook */
38 /* Now start enumerating the system hooks */
39 return HOOK_systemHooks[data->id - WH_FIRST_HOOK];
43 /***********************************************************************
44 * HOOK_GetHook
46 * Get the first hook for a given type.
48 HANDLE HOOK_GetHook( short id , HQUEUE hQueue )
50 MESSAGEQUEUE *queue;
51 HANDLE hook = 0;
53 if ((queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(hQueue) )) != NULL)
54 hook = queue->hooks[id - WH_FIRST_HOOK];
55 if (!hook) hook = HOOK_systemHooks[id - WH_FIRST_HOOK];
56 return hook;
60 /***********************************************************************
61 * HOOK_SetHook
63 * Install a given hook.
65 HANDLE HOOK_SetHook( short id, HOOKPROC proc, HINSTANCE hInst, HTASK hTask )
67 HOOKDATA *data;
68 HANDLE handle;
69 HQUEUE hQueue = 0;
71 if ((id < WH_FIRST_HOOK) || (id > WH_LAST_HOOK)) return 0;
72 if (!(hInst = GetExePtr( hInst ))) return 0;
74 dprintf_hook( stddeb, "Setting hook %d: %08lx %04x %04x\n",
75 id, (DWORD)proc, hInst, hTask );
77 if (hTask) /* Task-specific hook */
79 if ((id == WH_JOURNALRECORD) || (id == WH_JOURNALPLAYBACK) ||
80 (id == WH_SYSMSGFILTER)) return 0; /* System-only hooks */
81 if (!(hQueue = GetTaskQueue( hTask ))) return 0;
84 if (id == WH_JOURNALPLAYBACK || id == WH_CBT ||
85 id == WH_DEBUG || id == WH_SHELL)
87 fprintf( stdnimp, "Unimplemented hook set: (%d,%08lx,%04x,%04x)!\n",
88 id, (DWORD)proc, hInst, hTask );
91 /* Create the hook structure */
93 if (!(handle = (HANDLE)USER_HEAP_ALLOC( sizeof(HOOKDATA) ))) return 0;
94 data = (HOOKDATA *) USER_HEAP_LIN_ADDR( handle );
95 data->proc = proc;
96 data->id = id;
97 data->ownerQueue = hQueue;
98 data->ownerModule = hInst;
99 data->inHookProc = 0;
100 dprintf_hook( stddeb, "Setting hook %d: ret=%04x\n", id, handle );
102 /* Insert it in the correct linked list */
104 if (hQueue)
106 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
107 data->next = queue->hooks[id - WH_FIRST_HOOK];
108 queue->hooks[id - WH_FIRST_HOOK] = handle;
110 else
112 data->next = HOOK_systemHooks[id - WH_FIRST_HOOK];
113 HOOK_systemHooks[id - WH_FIRST_HOOK] = handle;
115 return handle;
119 /***********************************************************************
120 * HOOK_RemoveHook
122 * Remove a hook from the list.
124 static BOOL HOOK_RemoveHook( HANDLE hook )
126 HOOKDATA *data;
127 HANDLE *prevHook;
129 dprintf_hook( stddeb, "Removing hook %04x\n", hook );
131 if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook))) return FALSE;
132 if (data->inHookProc)
134 /* Mark it for deletion later on */
135 dprintf_hook( stddeb, "Hook still running, deletion delayed\n" );
136 data->proc = (FARPROC)0;
137 return TRUE;
140 /* Remove it from the linked list */
142 if (data->ownerQueue)
144 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( data->ownerQueue );
145 if (!queue) return FALSE;
146 prevHook = &queue->hooks[data->id - WH_FIRST_HOOK];
148 else prevHook = &HOOK_systemHooks[data->id - WH_FIRST_HOOK];
150 while (*prevHook && *prevHook != hook)
151 prevHook = &((HOOKDATA *)USER_HEAP_LIN_ADDR(*prevHook))->next;
153 if (!*prevHook) return FALSE;
154 *prevHook = data->next;
155 USER_HEAP_FREE( hook );
156 return TRUE;
160 /***********************************************************************
161 * HOOK_CallHook
163 * Call a hook procedure.
165 static DWORD HOOK_CallHook( HANDLE hook, short code,
166 WPARAM wParam, LPARAM lParam )
168 HOOKDATA *data;
169 MESSAGEQUEUE *queue;
170 HANDLE prevHook;
171 DWORD ret;
173 /* Find the first hook with a valid proc */
175 for (;;)
177 if (!hook) return 0;
178 if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook))) return 0;
179 if (data->proc) break;
180 hook = data->next;
183 /* Now call it */
185 if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
186 prevHook = queue->hCurHook;
187 queue->hCurHook = hook;
188 data->inHookProc = 1;
190 dprintf_hook( stddeb, "Calling hook %04x: %d %04lx %08lx\n",
191 hook, code, (DWORD)wParam, lParam );
192 ret = CallHookProc( data->proc, code, wParam, lParam );
193 dprintf_hook( stddeb, "Ret hook %04x = %08lx\n", hook, ret );
195 data->inHookProc = 0;
196 queue->hCurHook = prevHook;
197 if (!data->proc) HOOK_RemoveHook( hook );
198 return ret;
202 /***********************************************************************
203 * HOOK_CallHooks
205 * Call a hook chain.
207 DWORD HOOK_CallHooks( short id, short code, WPARAM wParam, LPARAM lParam )
209 HANDLE hook = HOOK_GetHook( id , 0 );
210 if (!hook) return 0;
211 return HOOK_CallHook( hook, code, wParam, lParam );
215 /***********************************************************************
216 * HOOK_FreeModuleHooks
218 void HOOK_FreeModuleHooks( HMODULE hModule )
220 /* remove all system hooks registered by this module */
222 HOOKDATA* hptr;
223 HHOOK hook, next;
224 int id;
226 for( id = WH_FIRST_HOOK; id <= WH_LAST_HOOK; id++ )
228 hook = HOOK_systemHooks[id - WH_FIRST_HOOK];
229 while( hook )
230 if( (hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook)) )
232 next = hptr->next;
233 if( hptr->ownerModule == hModule )
235 hptr->inHookProc = 0;
236 HOOK_RemoveHook(hook);
238 hook = next;
240 else hook = 0;
244 /***********************************************************************
245 * HOOK_FreeQueueHooks
247 void HOOK_FreeQueueHooks( HQUEUE hQueue )
249 /* remove all hooks registered by this queue */
251 HOOKDATA* hptr = NULL;
252 HHOOK hook, next;
253 int id;
255 for( id = WH_FIRST_HOOK; id <= WH_LAST_HOOK; id++ )
257 hook = HOOK_GetHook( id, hQueue );
258 while( hook )
260 next = HOOK_GetNextHook(hook);
262 hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook);
263 if( hptr && hptr->ownerQueue == hQueue )
265 hptr->inHookProc = 0;
266 HOOK_RemoveHook(hook);
268 hook = next;
273 /***********************************************************************
274 * SetWindowsHook (USER.121)
276 FARPROC SetWindowsHook( short id, HOOKPROC proc )
278 #ifdef WINELIB
279 HINSTANCE hInst = 0;
280 #else
281 HINSTANCE hInst = FarGetOwner( HIWORD(proc) );
282 #endif
283 /* WH_MSGFILTER is the only task-specific hook for SetWindowsHook() */
284 HTASK hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0;
286 HANDLE handle = HOOK_SetHook( id, proc, hInst, hTask );
287 if (!handle) return (FARPROC)-1;
288 if (!((HOOKDATA *)USER_HEAP_LIN_ADDR( handle ))->next) return 0;
289 /* Not sure if the return value is correct; should not matter much
290 * since it's never used (see DefHookProc). -- AJ */
291 #ifdef WINELIB32
292 return (FARPROC)handle;
293 #else
294 return (FARPROC)MAKELONG( handle, HOOK_MAGIC );
295 #endif
299 /***********************************************************************
300 * UnhookWindowsHook (USER.234)
302 BOOL UnhookWindowsHook( short id, HOOKPROC proc )
304 HANDLE hook = HOOK_GetHook( id , 0 );
306 dprintf_hook( stddeb, "UnhookWindowsHook: %d %08lx\n", id, (DWORD)proc );
308 while (hook)
310 HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook);
311 if (data->proc == proc) break;
312 hook = HOOK_GetNextHook( hook );
314 if (!hook) return FALSE;
315 return HOOK_RemoveHook( hook );
319 /***********************************************************************
320 * DefHookProc (USER.235)
322 DWORD DefHookProc( short code, WORD wParam, DWORD lParam, HHOOK *hhook )
324 /* Note: the *hhook parameter is never used, since we rely on the
325 * current hook value from the task queue to find the next hook. */
326 MESSAGEQUEUE *queue;
327 HANDLE next;
329 if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
330 if (!(next = HOOK_GetNextHook( queue->hCurHook ))) return 0;
331 return HOOK_CallHook( next, code, wParam, lParam );
335 /***********************************************************************
336 * CallMsgFilter (USER.123)
338 BOOL CallMsgFilter( SEGPTR msg, INT code )
340 if (GetSysModalWindow()) return FALSE;
341 if (HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)msg )) return TRUE;
342 return HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)msg );
346 /***********************************************************************
347 * SetWindowsHookEx (USER.291)
349 HHOOK SetWindowsHookEx( short id, HOOKPROC proc, HINSTANCE hInst, HTASK hTask )
351 HANDLE handle = HOOK_SetHook( id, proc, hInst, hTask );
352 #ifdef WINELIB32
353 return (HHOOK)handle;
354 #else
355 return MAKELONG( handle, HOOK_MAGIC );
356 #endif
360 /***********************************************************************
361 * UnhookWindowHookEx (USER.292)
363 BOOL UnhookWindowsHookEx( HHOOK hhook )
365 #ifdef WINELIB32
366 return HOOK_RemoveHook( (HANDLE)hhook );
367 #else
368 if (HIWORD(hhook) != HOOK_MAGIC) return FALSE; /* Not a new format hook */
369 return HOOK_RemoveHook( LOWORD(hhook) );
370 #endif
374 /***********************************************************************
375 * CallNextHookEx (USER.293)
377 LRESULT CallNextHookEx( HHOOK hhook, INT code, WPARAM wParam, LPARAM lParam )
379 HANDLE next;
380 #ifdef WINELIB32
381 if (!(next = HOOK_GetNextHook( (HANDLE)hhook ))) return 0;
382 #else
383 if (HIWORD(hhook) != HOOK_MAGIC) return 0; /* Not a new format hook */
384 if (!(next = HOOK_GetNextHook( LOWORD(hhook) ))) return 0;
385 #endif
386 return HOOK_CallHook( next, code, wParam, lParam );