Release 951124
[wine/multimedia.git] / windows / hook.c
blob2460cad52fd2d432e59c41208ecb43ff008bd9d6
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 "message.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) 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 static HANDLE HOOK_GetHook( short id )
50 MESSAGEQUEUE *queue;
51 HANDLE hook = 0;
53 if ((queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) )) != 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 "NPFMT" "NPFMT"\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,"NPFMT","NPFMT")!\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="NPFMT"\n", id, handle );
102 /* Insert it in the correct linked list */
104 if (hQueue)
106 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock( 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 "NPFMT"\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 *)GlobalLock( 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 *)GlobalLock( GetTaskQueue(0) ))) return 0;
186 prevHook = queue->hCurHook;
187 queue->hCurHook = hook;
188 data->inHookProc = 1;
190 dprintf_hook( stddeb, "Calling hook "NPFMT": %d %04lx %08lx\n",
191 hook, code, (DWORD)wParam, lParam );
192 ret = CallHookProc( data->proc, code, wParam, lParam );
193 dprintf_hook( stddeb, "Ret hook "NPFMT" = %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 );
210 if (!hook) return 0;
211 return HOOK_CallHook( hook, code, wParam, lParam );
215 /***********************************************************************
216 * SetWindowsHook (USER.121)
218 FARPROC SetWindowsHook( short id, HOOKPROC proc )
220 #ifdef WINELIB
221 HINSTANCE hInst = 0;
222 #else
223 HINSTANCE hInst = FarGetOwner( HIWORD(proc) );
224 #endif
225 /* WH_MSGFILTER is the only task-specific hook for SetWindowsHook() */
226 HTASK hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0;
228 HANDLE handle = HOOK_SetHook( id, proc, hInst, hTask );
229 if (!handle) return -1;
230 if (!((HOOKDATA *)USER_HEAP_LIN_ADDR( handle ))->next) return 0;
231 /* Not sure if the return value is correct; should not matter much
232 * since it's never used (see DefHookProc). -- AJ */
233 #ifdef WINELIB32
234 return (FARPROC)handle;
235 #else
236 return (FARPROC)MAKELONG( handle, HOOK_MAGIC );
237 #endif
241 /***********************************************************************
242 * UnhookWindowsHook (USER.234)
244 BOOL UnhookWindowsHook( short id, HOOKPROC proc )
246 HANDLE hook = HOOK_GetHook( id );
248 dprintf_hook( stddeb, "UnhookWindowsHook: %d %08lx\n", id, (DWORD)proc );
250 while (hook)
252 HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook);
253 if (data->proc == proc) break;
254 hook = HOOK_GetNextHook( hook );
256 if (!hook) return FALSE;
257 return HOOK_RemoveHook( hook );
261 /***********************************************************************
262 * DefHookProc (USER.235)
264 DWORD DefHookProc( short code, WORD wParam, DWORD lParam, HHOOK *hhook )
266 /* Note: the *hhook parameter is never used, since we rely on the
267 * current hook value from the task queue to find the next hook. */
268 MESSAGEQUEUE *queue;
269 HANDLE next;
271 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return 0;
272 if (!(next = HOOK_GetNextHook( queue->hCurHook ))) return 0;
273 return HOOK_CallHook( next, code, wParam, lParam );
277 /***********************************************************************
278 * CallMsgFilter (USER.123)
280 BOOL CallMsgFilter( SEGPTR msg, short code )
282 if (GetSysModalWindow()) return FALSE;
283 if (HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)msg )) return TRUE;
284 return HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)msg );
288 /***********************************************************************
289 * SetWindowsHookEx (USER.291)
291 HHOOK SetWindowsHookEx( short id, HOOKPROC proc, HINSTANCE hInst, HTASK hTask )
293 HANDLE handle = HOOK_SetHook( id, proc, hInst, hTask );
294 #ifdef WINELIB32
295 return (HHOOK)handle;
296 #else
297 return MAKELONG( handle, HOOK_MAGIC );
298 #endif
302 /***********************************************************************
303 * UnhookWindowHookEx (USER.292)
305 BOOL UnhookWindowsHookEx( HHOOK hhook )
307 #ifdef WINELIB32
308 return HOOK_RemoveHook( (HANDLE)hhook );
309 #else
310 if (HIWORD(hhook) != HOOK_MAGIC) return FALSE; /* Not a new format hook */
311 return HOOK_RemoveHook( LOWORD(hhook) );
312 #endif
316 /***********************************************************************
317 * CallNextHookEx (USER.293)
319 DWORD CallNextHookEx( HHOOK hhook, short code, WPARAM wParam, LPARAM lParam )
321 HANDLE next;
322 if (HIWORD(hhook) != HOOK_MAGIC) return 0; /* Not a new format hook */
323 if (!(next = HOOK_GetNextHook( LOWORD(hhook) ))) return 0;
324 return HOOK_CallHook( next, code, wParam, lParam );