Release 960928
[wine/multimedia.git] / windows / hook.c
blobce581078bf89f598a458c795dca0051eb6ff0657
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 "callback.h"
19 #include "queue.h"
20 #include "user.h"
21 #include "stddebug.h"
22 #include "debug.h"
24 /* This should probably reside in USER heap */
25 static HANDLE16 HOOK_systemHooks[WH_NB_HOOKS] = { 0, };
28 /***********************************************************************
29 * HOOK_GetNextHook
31 * Get the next hook of a given hook.
33 static HANDLE16 HOOK_GetNextHook( HANDLE16 hook )
35 HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR( hook );
36 if (!data || !hook) return 0;
37 if (data->next) return data->next;
38 if (!data->ownerQueue) return 0; /* Already system hook */
39 /* Now start enumerating the system hooks */
40 return HOOK_systemHooks[data->id - WH_MINHOOK];
44 /***********************************************************************
45 * HOOK_GetHook
47 * Get the first hook for a given type.
49 HANDLE16 HOOK_GetHook( INT16 id , HQUEUE16 hQueue )
51 MESSAGEQUEUE *queue;
52 HANDLE16 hook = 0;
54 if ((queue = (MESSAGEQUEUE *)GlobalLock16( hQueue )) != NULL)
55 hook = queue->hooks[id - WH_MINHOOK];
56 if (!hook) hook = HOOK_systemHooks[id - WH_MINHOOK];
57 return hook;
61 /***********************************************************************
62 * HOOK_SetHook
64 * Install a given hook.
66 static HANDLE16 HOOK_SetHook( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst,
67 HTASK16 hTask )
69 HOOKDATA *data;
70 HANDLE16 handle;
71 HQUEUE16 hQueue = 0;
73 if ((id < WH_MINHOOK) || (id > WH_MAXHOOK)) return 0;
74 if (!(hInst = GetExePtr( hInst ))) return 0;
76 dprintf_hook( stddeb, "Setting hook %d: %08x %04x %04x\n",
77 id, (UINT32)proc, hInst, hTask );
79 if (hTask) /* Task-specific hook */
81 if ((id == WH_JOURNALRECORD) || (id == WH_JOURNALPLAYBACK) ||
82 (id == WH_SYSMSGFILTER)) return 0; /* System-only hooks */
83 if (!(hQueue = GetTaskQueue( hTask ))) return 0;
86 if (id == WH_DEBUG)
88 fprintf( stdnimp,"WH_DEBUG is broken in 16-bit Windows.\n");
89 return 0;
91 else if (id == WH_CBT || id == WH_SHELL)
93 fprintf( stdnimp, "Half-implemented hook set: (%s,%08lx,%04x,%04x)!\n",
94 (id==WH_CBT)?"WH_CBT":"WH_SHELL", (DWORD)proc, hInst, hTask );
97 if (id == WH_JOURNALPLAYBACK) EnableHardwareInput(FALSE);
99 /* Create the hook structure */
101 if (!(handle = USER_HEAP_ALLOC( sizeof(HOOKDATA) ))) return 0;
102 data = (HOOKDATA *) USER_HEAP_LIN_ADDR( handle );
103 data->proc = proc;
104 data->id = id;
105 data->ownerQueue = hQueue;
106 data->ownerModule = hInst;
107 data->inHookProc = 0;
108 dprintf_hook( stddeb, "Setting hook %d: ret=%04x\n", id, handle );
110 /* Insert it in the correct linked list */
112 if (hQueue)
114 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
115 data->next = queue->hooks[id - WH_MINHOOK];
116 queue->hooks[id - WH_MINHOOK] = handle;
118 else
120 data->next = HOOK_systemHooks[id - WH_MINHOOK];
121 HOOK_systemHooks[id - WH_MINHOOK] = handle;
123 return handle;
127 /***********************************************************************
128 * HOOK_RemoveHook
130 * Remove a hook from the list.
132 static BOOL32 HOOK_RemoveHook( HANDLE16 hook )
134 HOOKDATA *data;
135 HANDLE16 *prevHook;
137 dprintf_hook( stddeb, "Removing hook %04x\n", hook );
139 if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook))) return FALSE;
140 if (data->inHookProc)
142 /* Mark it for deletion later on */
143 dprintf_hook( stddeb, "Hook still running, deletion delayed\n" );
144 data->proc = (HOOKPROC16)0;
145 return TRUE;
148 if (data->id == WH_JOURNALPLAYBACK) EnableHardwareInput(TRUE);
150 /* Remove it from the linked list */
152 if (data->ownerQueue)
154 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( data->ownerQueue );
155 if (!queue) return FALSE;
156 prevHook = &queue->hooks[data->id - WH_MINHOOK];
158 else prevHook = &HOOK_systemHooks[data->id - WH_MINHOOK];
160 while (*prevHook && *prevHook != hook)
161 prevHook = &((HOOKDATA *)USER_HEAP_LIN_ADDR(*prevHook))->next;
163 if (!*prevHook) return FALSE;
164 *prevHook = data->next;
165 USER_HEAP_FREE( hook );
166 return TRUE;
170 /***********************************************************************
171 * HOOK_CallHook
173 * Call a hook procedure.
175 static LRESULT HOOK_CallHook( HANDLE16 hook, INT16 code,
176 WPARAM16 wParam, LPARAM lParam )
178 HOOKDATA *data;
179 MESSAGEQUEUE *queue;
180 HANDLE16 prevHook;
181 LRESULT ret;
183 /* Find the first hook with a valid proc */
185 for (;;)
187 if (!hook) return 0;
188 if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook))) return 0;
189 if (data->proc) break;
190 hook = data->next;
193 /* Now call it */
195 if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
196 prevHook = queue->hCurHook;
197 queue->hCurHook = hook;
198 data->inHookProc = 1;
200 dprintf_hook( stddeb, "Calling hook %04x: %d %04lx %08lx\n",
201 hook, code, (DWORD)wParam, lParam );
202 ret = CallHookProc( data->proc, code, wParam, lParam );
203 dprintf_hook( stddeb, "Ret hook %04x = %08lx\n", hook, ret );
205 data->inHookProc = 0;
206 queue->hCurHook = prevHook;
207 if (!data->proc) HOOK_RemoveHook( hook );
208 return ret;
212 /***********************************************************************
213 * HOOK_CallHooks
215 * Call a hook chain.
217 LRESULT HOOK_CallHooks( INT16 id, INT16 code, WPARAM16 wParam, LPARAM lParam )
219 HANDLE16 hook = HOOK_GetHook( id , GetTaskQueue(0) );
220 if (!hook) return 0;
221 return HOOK_CallHook( hook, code, wParam, lParam );
225 /***********************************************************************
226 * HOOK_FreeModuleHooks
228 void HOOK_FreeModuleHooks( HMODULE16 hModule )
230 /* remove all system hooks registered by this module */
232 HOOKDATA* hptr;
233 HHOOK hook, next;
234 int id;
236 for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ )
238 hook = HOOK_systemHooks[id - WH_MINHOOK];
239 while( hook )
240 if( (hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook)) )
242 next = hptr->next;
243 if( hptr->ownerModule == hModule )
245 hptr->inHookProc = 0;
246 HOOK_RemoveHook(hook);
248 hook = next;
250 else hook = 0;
254 /***********************************************************************
255 * HOOK_FreeQueueHooks
257 void HOOK_FreeQueueHooks( HQUEUE16 hQueue )
259 /* remove all hooks registered by this queue */
261 HOOKDATA* hptr = NULL;
262 HHOOK hook, next;
263 int id;
265 for( id = WH_MINHOOK; id <= WH_MAXHOOK; id++ )
267 hook = HOOK_GetHook( id, hQueue );
268 while( hook )
270 next = HOOK_GetNextHook(hook);
272 hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook);
273 if( hptr && hptr->ownerQueue == hQueue )
275 hptr->inHookProc = 0;
276 HOOK_RemoveHook(hook);
278 hook = next;
283 /***********************************************************************
284 * SetWindowsHook (USER.121)
286 FARPROC16 SetWindowsHook( INT16 id, HOOKPROC16 proc )
288 HINSTANCE16 hInst = __winelib ? 0 : FarGetOwner( HIWORD(proc) );
289 HTASK16 hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0;
290 HANDLE16 handle = HOOK_SetHook( id, proc, hInst, hTask );
292 return (handle) ? (FARPROC16)MAKELONG( handle, HOOK_MAGIC ) : NULL;
296 /***********************************************************************
297 * UnhookWindowsHook (USER.234)
299 BOOL16 UnhookWindowsHook( INT16 id, HOOKPROC16 proc )
301 HANDLE16 hook = HOOK_GetHook( id , 0 );
303 dprintf_hook( stddeb, "UnhookWindowsHook: %d %08lx\n", id, (DWORD)proc );
305 while (hook)
307 HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook);
308 if (data->proc == proc) break;
309 hook = HOOK_GetNextHook( hook );
311 if (!hook) return FALSE;
312 return HOOK_RemoveHook( hook );
316 /***********************************************************************
317 * DefHookProc (USER.235)
319 LRESULT DefHookProc( INT16 code, WPARAM16 wParam, LPARAM lParam, HHOOK *hhook )
321 /* Note: the *hhook parameter is never used, since we rely on the
322 * current hook value from the task queue to find the next hook. */
323 MESSAGEQUEUE *queue;
324 HANDLE16 next;
326 if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
327 if (!(next = HOOK_GetNextHook( queue->hCurHook ))) return 0;
328 return HOOK_CallHook( next, code, wParam, lParam );
332 /***********************************************************************
333 * CallMsgFilter (USER.123)
335 BOOL16 CallMsgFilter( SEGPTR msg, INT16 code )
337 if (GetSysModalWindow16()) return FALSE;
338 if (HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)msg )) return TRUE;
339 return HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)msg );
343 /***********************************************************************
344 * SetWindowsHookEx (USER.291)
346 HHOOK SetWindowsHookEx( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst,
347 HTASK16 hTask )
349 HANDLE16 handle = HOOK_SetHook( id, proc, hInst, hTask );
350 return (handle) ? MAKELONG( handle, HOOK_MAGIC ) : NULL;
354 /***********************************************************************
355 * UnhookWindowHookEx (USER.292)
357 BOOL16 UnhookWindowsHookEx( HHOOK hhook )
359 if (HIWORD(hhook) != HOOK_MAGIC) return FALSE; /* Not a new format hook */
360 return HOOK_RemoveHook( LOWORD(hhook) );
364 /***********************************************************************
365 * CallNextHookEx (USER.293)
367 LRESULT CallNextHookEx(HHOOK hhook, INT16 code, WPARAM16 wParam, LPARAM lParam)
369 HANDLE16 next;
370 if (HIWORD(hhook) != HOOK_MAGIC) return 0; /* Not a new format hook */
371 if (!(next = HOOK_GetNextHook( LOWORD(hhook) ))) return 0;
372 return HOOK_CallHook( next, code, wParam, lParam );