2 * Windows hook functions
4 * Copyright 1994, 1995 Alexandre Julliard
6 * Based on investigations by Alex Korobka
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 */
24 /* This should probably reside in USER heap */
25 static HANDLE16 HOOK_systemHooks[WH_NB_HOOKS] = { 0, };
28 /***********************************************************************
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_FIRST_HOOK];
44 /***********************************************************************
47 * Get the first hook for a given type.
49 HANDLE16 HOOK_GetHook( INT16 id , HQUEUE16 hQueue )
54 if ((queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(hQueue) )) != NULL)
55 hook = queue->hooks[id - WH_FIRST_HOOK];
56 if (!hook) hook = HOOK_systemHooks[id - WH_FIRST_HOOK];
61 /***********************************************************************
64 * Install a given hook.
66 static HANDLE16 HOOK_SetHook( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst,
73 if ((id < WH_FIRST_HOOK) || (id > WH_LAST_HOOK)) 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_JOURNALPLAYBACK || id == WH_CBT ||
87 id == WH_DEBUG || id == WH_SHELL)
89 fprintf( stdnimp, "Unimplemented hook set: (%d,%08lx,%04x,%04x)!\n",
90 id, (DWORD)proc, hInst, hTask );
93 /* Create the hook structure */
95 if (!(handle = USER_HEAP_ALLOC( sizeof(HOOKDATA) ))) return 0;
96 data = (HOOKDATA *) USER_HEAP_LIN_ADDR( handle );
99 data->ownerQueue = hQueue;
100 data->ownerModule = hInst;
101 data->inHookProc = 0;
102 dprintf_hook( stddeb, "Setting hook %d: ret=%04x\n", id, handle );
104 /* Insert it in the correct linked list */
108 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
109 data->next = queue->hooks[id - WH_FIRST_HOOK];
110 queue->hooks[id - WH_FIRST_HOOK] = handle;
114 data->next = HOOK_systemHooks[id - WH_FIRST_HOOK];
115 HOOK_systemHooks[id - WH_FIRST_HOOK] = handle;
121 /***********************************************************************
124 * Remove a hook from the list.
126 static BOOL32 HOOK_RemoveHook( HANDLE16 hook )
131 dprintf_hook( stddeb, "Removing hook %04x\n", hook );
133 if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook))) return FALSE;
134 if (data->inHookProc)
136 /* Mark it for deletion later on */
137 dprintf_hook( stddeb, "Hook still running, deletion delayed\n" );
138 data->proc = (HOOKPROC16)0;
142 /* Remove it from the linked list */
144 if (data->ownerQueue)
146 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( data->ownerQueue );
147 if (!queue) return FALSE;
148 prevHook = &queue->hooks[data->id - WH_FIRST_HOOK];
150 else prevHook = &HOOK_systemHooks[data->id - WH_FIRST_HOOK];
152 while (*prevHook && *prevHook != hook)
153 prevHook = &((HOOKDATA *)USER_HEAP_LIN_ADDR(*prevHook))->next;
155 if (!*prevHook) return FALSE;
156 *prevHook = data->next;
157 USER_HEAP_FREE( hook );
162 /***********************************************************************
165 * Call a hook procedure.
167 static LRESULT HOOK_CallHook( HANDLE16 hook, INT16 code,
168 WPARAM16 wParam, LPARAM lParam )
175 /* Find the first hook with a valid proc */
180 if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook))) return 0;
181 if (data->proc) break;
187 if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
188 prevHook = queue->hCurHook;
189 queue->hCurHook = hook;
190 data->inHookProc = 1;
192 dprintf_hook( stddeb, "Calling hook %04x: %d %04lx %08lx\n",
193 hook, code, (DWORD)wParam, lParam );
194 ret = CallHookProc( data->proc, code, wParam, lParam );
195 dprintf_hook( stddeb, "Ret hook %04x = %08lx\n", hook, ret );
197 data->inHookProc = 0;
198 queue->hCurHook = prevHook;
199 if (!data->proc) HOOK_RemoveHook( hook );
204 /***********************************************************************
209 LRESULT HOOK_CallHooks( INT16 id, INT16 code, WPARAM16 wParam, LPARAM lParam )
211 HANDLE16 hook = HOOK_GetHook( id , 0 );
213 return HOOK_CallHook( hook, code, wParam, lParam );
217 /***********************************************************************
218 * HOOK_FreeModuleHooks
220 void HOOK_FreeModuleHooks( HMODULE16 hModule )
222 /* remove all system hooks registered by this module */
228 for( id = WH_FIRST_HOOK; id <= WH_LAST_HOOK; id++ )
230 hook = HOOK_systemHooks[id - WH_FIRST_HOOK];
232 if( (hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook)) )
235 if( hptr->ownerModule == hModule )
237 hptr->inHookProc = 0;
238 HOOK_RemoveHook(hook);
246 /***********************************************************************
247 * HOOK_FreeQueueHooks
249 void HOOK_FreeQueueHooks( HQUEUE16 hQueue )
251 /* remove all hooks registered by this queue */
253 HOOKDATA* hptr = NULL;
257 for( id = WH_FIRST_HOOK; id <= WH_LAST_HOOK; id++ )
259 hook = HOOK_GetHook( id, hQueue );
262 next = HOOK_GetNextHook(hook);
264 hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook);
265 if( hptr && hptr->ownerQueue == hQueue )
267 hptr->inHookProc = 0;
268 HOOK_RemoveHook(hook);
275 /***********************************************************************
276 * SetWindowsHook (USER.121)
278 FARPROC16 SetWindowsHook( INT16 id, HOOKPROC16 proc )
280 HINSTANCE16 hInst = __winelib ? 0 : FarGetOwner( HIWORD(proc) );
281 /* WH_MSGFILTER is the only task-specific hook for SetWindowsHook() */
282 HTASK16 hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0;
284 HANDLE16 handle = HOOK_SetHook( id, proc, hInst, hTask );
285 if (!handle) return (FARPROC16)-1;
286 if (!((HOOKDATA *)USER_HEAP_LIN_ADDR( handle ))->next) return 0;
287 /* Not sure if the return value is correct; should not matter much
288 * since it's never used (see DefHookProc). -- AJ */
289 return (FARPROC16)MAKELONG( handle, HOOK_MAGIC );
293 /***********************************************************************
294 * UnhookWindowsHook (USER.234)
296 BOOL16 UnhookWindowsHook( INT16 id, HOOKPROC16 proc )
298 HANDLE16 hook = HOOK_GetHook( id , 0 );
300 dprintf_hook( stddeb, "UnhookWindowsHook: %d %08lx\n", id, (DWORD)proc );
304 HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook);
305 if (data->proc == proc) break;
306 hook = HOOK_GetNextHook( hook );
308 if (!hook) return FALSE;
309 return HOOK_RemoveHook( hook );
313 /***********************************************************************
314 * DefHookProc (USER.235)
316 LRESULT DefHookProc( INT16 code, WPARAM16 wParam, LPARAM lParam, HHOOK *hhook )
318 /* Note: the *hhook parameter is never used, since we rely on the
319 * current hook value from the task queue to find the next hook. */
323 if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
324 if (!(next = HOOK_GetNextHook( queue->hCurHook ))) return 0;
325 return HOOK_CallHook( next, code, wParam, lParam );
329 /***********************************************************************
330 * CallMsgFilter (USER.123)
332 BOOL16 CallMsgFilter( SEGPTR msg, INT16 code )
334 if (GetSysModalWindow16()) return FALSE;
335 if (HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)msg )) return TRUE;
336 return HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)msg );
340 /***********************************************************************
341 * SetWindowsHookEx (USER.291)
343 HHOOK SetWindowsHookEx( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst,
346 HANDLE16 handle = HOOK_SetHook( id, proc, hInst, hTask );
347 return MAKELONG( handle, HOOK_MAGIC );
351 /***********************************************************************
352 * UnhookWindowHookEx (USER.292)
354 BOOL16 UnhookWindowsHookEx( HHOOK hhook )
356 if (HIWORD(hhook) != HOOK_MAGIC) return FALSE; /* Not a new format hook */
357 return HOOK_RemoveHook( LOWORD(hhook) );
361 /***********************************************************************
362 * CallNextHookEx (USER.293)
364 LRESULT CallNextHookEx(HHOOK hhook, INT16 code, WPARAM16 wParam, LPARAM lParam)
367 if (HIWORD(hhook) != HOOK_MAGIC) return 0; /* Not a new format hook */
368 if (!(next = HOOK_GetNextHook( LOWORD(hhook) ))) return 0;
369 return HOOK_CallHook( next, code, wParam, lParam );