Release 961013
[wine/multimedia.git] / windows / hook.c
blob4deddf791dbe0fd1f19e873d90bf9d1d2118b8c3
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 = (HOOKDATA *)USER_HEAP_LIN_ADDR( hhook );
83 return data ? data->proc : NULL;
87 /***********************************************************************
88 * HOOK_SetHook
90 * Install a given hook.
92 static HANDLE16 HOOK_SetHook( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst,
93 HTASK16 hTask )
95 HOOKDATA *data;
96 HANDLE16 handle;
97 HQUEUE16 hQueue = 0;
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;
112 if (id == WH_DEBUG)
114 fprintf( stdnimp,"WH_DEBUG is broken in 16-bit Windows.\n");
115 return 0;
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 );
129 data->proc = proc;
130 data->id = id;
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 */
138 if (hQueue)
140 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
141 data->next = queue->hooks[id - WH_MINHOOK];
142 queue->hooks[id - WH_MINHOOK] = handle;
144 else
146 data->next = HOOK_systemHooks[id - WH_MINHOOK];
147 HOOK_systemHooks[id - WH_MINHOOK] = handle;
149 return handle;
153 /***********************************************************************
154 * HOOK_RemoveHook
156 * Remove a hook from the list.
158 static BOOL32 HOOK_RemoveHook( HANDLE16 hook )
160 HOOKDATA *data;
161 HANDLE16 *prevHook;
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;
171 return TRUE;
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 );
192 return TRUE;
196 /***********************************************************************
197 * HOOK_CallHook
199 * Call a hook procedure.
201 static LRESULT HOOK_CallHook( HANDLE16 hook, INT16 code,
202 WPARAM16 wParam, LPARAM lParam )
204 HOOKDATA *data;
205 MESSAGEQUEUE *queue;
206 HANDLE16 prevHook;
207 LRESULT ret;
209 /* Find the first hook with a valid proc */
211 for (;;)
213 if (!hook) return 0;
214 if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook))) return 0;
215 if (data->proc) break;
216 hook = data->next;
219 /* Now call it */
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 );
234 return ret;
238 /***********************************************************************
239 * HOOK_CallHooks
241 * Call a hook chain.
243 LRESULT HOOK_CallHooks( INT16 id, INT16 code, WPARAM16 wParam, LPARAM lParam )
245 HANDLE16 hook = HOOK_GetHook( id , GetTaskQueue(0) );
246 if (!hook) return 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 */
258 HOOKDATA* hptr;
259 HHOOK hook, next;
260 int id;
262 for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ )
264 hook = HOOK_systemHooks[id - WH_MINHOOK];
265 while( hook )
266 if( (hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook)) )
268 next = hptr->next;
269 if( hptr->ownerModule == hModule )
271 hptr->inHookProc = 0;
272 HOOK_RemoveHook(hook);
274 hook = next;
276 else hook = 0;
280 /***********************************************************************
281 * HOOK_FreeQueueHooks
283 void HOOK_FreeQueueHooks( HQUEUE16 hQueue )
285 /* remove all hooks registered by this queue */
287 HOOKDATA* hptr = NULL;
288 HHOOK hook, next;
289 int id;
291 for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ )
293 hook = HOOK_GetHook( id, hQueue );
294 while( hook )
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);
304 hook = next;
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 );
331 while (hook)
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. */
349 MESSAGEQUEUE *queue;
350 HANDLE16 next;
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,
373 HTASK16 hTask )
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)
395 HANDLE16 next;
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 );