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
14 * (except for WINELIB32 where it is a 32-bit handle). -- AJ
23 /* This should probably reside in USER heap */
24 static HANDLE HOOK_systemHooks[WH_NB_HOOKS] = { 0, };
27 /***********************************************************************
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 );
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 /***********************************************************************
46 * Get the first hook for a given type.
48 static HANDLE HOOK_GetHook( short id )
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];
60 /***********************************************************************
63 * Install a given hook.
65 HANDLE HOOK_SetHook( short id, HOOKPROC proc, HINSTANCE hInst, HTASK hTask )
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 );
97 data->ownerQueue = hQueue;
98 data->ownerModule = hInst;
100 dprintf_hook( stddeb, "Setting hook %d: ret=%04x\n", id, handle );
102 /* Insert it in the correct linked list */
106 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock( hQueue );
107 data->next = queue->hooks[id - WH_FIRST_HOOK];
108 queue->hooks[id - WH_FIRST_HOOK] = handle;
112 data->next = HOOK_systemHooks[id - WH_FIRST_HOOK];
113 HOOK_systemHooks[id - WH_FIRST_HOOK] = handle;
119 /***********************************************************************
122 * Remove a hook from the list.
124 static BOOL HOOK_RemoveHook( HANDLE hook )
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;
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 );
160 /***********************************************************************
163 * Call a hook procedure.
165 static DWORD HOOK_CallHook( HANDLE hook, short code,
166 WPARAM wParam, LPARAM lParam )
173 /* Find the first hook with a valid proc */
178 if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook))) return 0;
179 if (data->proc) break;
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 %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 );
202 /***********************************************************************
207 DWORD HOOK_CallHooks( short id, short code, WPARAM wParam, LPARAM lParam )
209 HANDLE hook = HOOK_GetHook( id );
211 return HOOK_CallHook( hook, code, wParam, lParam );
215 /***********************************************************************
216 * SetWindowsHook (USER.121)
218 FARPROC SetWindowsHook( short id, HOOKPROC proc )
223 HINSTANCE hInst = FarGetOwner( HIWORD(proc) );
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 (FARPROC)-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 */
234 return (FARPROC)handle;
236 return (FARPROC)MAKELONG( handle, HOOK_MAGIC );
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 );
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. */
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, INT 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 );
295 return (HHOOK)handle;
297 return MAKELONG( handle, HOOK_MAGIC );
302 /***********************************************************************
303 * UnhookWindowHookEx (USER.292)
305 BOOL UnhookWindowsHookEx( HHOOK hhook )
308 return HOOK_RemoveHook( (HANDLE)hhook );
310 if (HIWORD(hhook) != HOOK_MAGIC) return FALSE; /* Not a new format hook */
311 return HOOK_RemoveHook( LOWORD(hhook) );
316 /***********************************************************************
317 * CallNextHookEx (USER.293)
319 LRESULT CallNextHookEx( HHOOK hhook, INT code, WPARAM wParam, LPARAM lParam )
323 if (!(next = HOOK_GetNextHook( (HANDLE)hhook ))) return 0;
325 if (HIWORD(hhook) != HOOK_MAGIC) return 0; /* Not a new format hook */
326 if (!(next = HOOK_GetNextHook( LOWORD(hhook) ))) return 0;
328 return HOOK_CallHook( next, code, wParam, lParam );