Release 960913
[wine/testsucceed.git] / windows / hook.c
blob6f9f09a7f27904f7cd8a452fede52bb095f8782e
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_FIRST_HOOK];
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_FIRST_HOOK];
56 if (!hook) hook = HOOK_systemHooks[id - WH_FIRST_HOOK];
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_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_CBT || id == WH_DEBUG || id == WH_SHELL)
88 fprintf( stdnimp, "Unimplemented hook set: (%d,%08lx,%04x,%04x)!\n",
89 id, (DWORD)proc, hInst, hTask );
92 /* Create the hook structure */
94 if (!(handle = USER_HEAP_ALLOC( sizeof(HOOKDATA) ))) return 0;
95 data = (HOOKDATA *) USER_HEAP_LIN_ADDR( handle );
96 data->proc = proc;
97 data->id = id;
98 data->ownerQueue = hQueue;
99 data->ownerModule = hInst;
100 data->inHookProc = 0;
101 dprintf_hook( stddeb, "Setting hook %d: ret=%04x\n", id, handle );
103 /* Insert it in the correct linked list */
105 if (hQueue)
107 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
108 data->next = queue->hooks[id - WH_FIRST_HOOK];
109 queue->hooks[id - WH_FIRST_HOOK] = handle;
111 else
113 data->next = HOOK_systemHooks[id - WH_FIRST_HOOK];
114 HOOK_systemHooks[id - WH_FIRST_HOOK] = handle;
116 return handle;
120 /***********************************************************************
121 * HOOK_RemoveHook
123 * Remove a hook from the list.
125 static BOOL32 HOOK_RemoveHook( HANDLE16 hook )
127 HOOKDATA *data;
128 HANDLE16 *prevHook;
130 dprintf_hook( stddeb, "Removing hook %04x\n", hook );
132 if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook))) return FALSE;
133 if (data->inHookProc)
135 /* Mark it for deletion later on */
136 dprintf_hook( stddeb, "Hook still running, deletion delayed\n" );
137 data->proc = (HOOKPROC16)0;
138 return TRUE;
141 /* Remove it from the linked list */
143 if (data->ownerQueue)
145 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( data->ownerQueue );
146 if (!queue) return FALSE;
147 prevHook = &queue->hooks[data->id - WH_FIRST_HOOK];
149 else prevHook = &HOOK_systemHooks[data->id - WH_FIRST_HOOK];
151 while (*prevHook && *prevHook != hook)
152 prevHook = &((HOOKDATA *)USER_HEAP_LIN_ADDR(*prevHook))->next;
154 if (!*prevHook) return FALSE;
155 *prevHook = data->next;
156 USER_HEAP_FREE( hook );
157 return TRUE;
161 /***********************************************************************
162 * HOOK_CallHook
164 * Call a hook procedure.
166 static LRESULT HOOK_CallHook( HANDLE16 hook, INT16 code,
167 WPARAM16 wParam, LPARAM lParam )
169 HOOKDATA *data;
170 MESSAGEQUEUE *queue;
171 HANDLE16 prevHook;
172 LRESULT ret;
174 /* Find the first hook with a valid proc */
176 for (;;)
178 if (!hook) return 0;
179 if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook))) return 0;
180 if (data->proc) break;
181 hook = data->next;
184 /* Now call it */
186 if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
187 prevHook = queue->hCurHook;
188 queue->hCurHook = hook;
189 data->inHookProc = 1;
191 dprintf_hook( stddeb, "Calling hook %04x: %d %04lx %08lx\n",
192 hook, code, (DWORD)wParam, lParam );
193 ret = CallHookProc( data->proc, code, wParam, lParam );
194 dprintf_hook( stddeb, "Ret hook %04x = %08lx\n", hook, ret );
196 data->inHookProc = 0;
197 queue->hCurHook = prevHook;
198 if (!data->proc) HOOK_RemoveHook( hook );
199 return ret;
203 /***********************************************************************
204 * HOOK_CallHooks
206 * Call a hook chain.
208 LRESULT HOOK_CallHooks( INT16 id, INT16 code, WPARAM16 wParam, LPARAM lParam )
210 HANDLE16 hook = HOOK_GetHook( id , GetTaskQueue(0) );
211 if (!hook) return 0;
212 return HOOK_CallHook( hook, code, wParam, lParam );
216 /***********************************************************************
217 * HOOK_FreeModuleHooks
219 void HOOK_FreeModuleHooks( HMODULE16 hModule )
221 /* remove all system hooks registered by this module */
223 HOOKDATA* hptr;
224 HHOOK hook, next;
225 int id;
227 for( id = WH_FIRST_HOOK; id <= WH_LAST_HOOK; id++ )
229 hook = HOOK_systemHooks[id - WH_FIRST_HOOK];
230 while( hook )
231 if( (hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook)) )
233 next = hptr->next;
234 if( hptr->ownerModule == hModule )
236 hptr->inHookProc = 0;
237 HOOK_RemoveHook(hook);
239 hook = next;
241 else hook = 0;
245 /***********************************************************************
246 * HOOK_FreeQueueHooks
248 void HOOK_FreeQueueHooks( HQUEUE16 hQueue )
250 /* remove all hooks registered by this queue */
252 HOOKDATA* hptr = NULL;
253 HHOOK hook, next;
254 int id;
256 for( id = WH_FIRST_HOOK; id <= WH_LAST_HOOK; id++ )
258 hook = HOOK_GetHook( id, hQueue );
259 while( hook )
261 next = HOOK_GetNextHook(hook);
263 hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook);
264 if( hptr && hptr->ownerQueue == hQueue )
266 hptr->inHookProc = 0;
267 HOOK_RemoveHook(hook);
269 hook = next;
274 /***********************************************************************
275 * SetWindowsHook (USER.121)
277 FARPROC16 SetWindowsHook( INT16 id, HOOKPROC16 proc )
279 HINSTANCE16 hInst = __winelib ? 0 : FarGetOwner( HIWORD(proc) );
280 /* WH_MSGFILTER is the only task-specific hook for SetWindowsHook() */
281 HTASK16 hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0;
283 HANDLE16 handle = HOOK_SetHook( id, proc, hInst, hTask );
284 if (!handle) return (FARPROC16)-1;
285 if (!((HOOKDATA *)USER_HEAP_LIN_ADDR( handle ))->next) return 0;
286 /* Not sure if the return value is correct; should not matter much
287 * since it's never used (see DefHookProc). -- AJ */
288 return (FARPROC16)MAKELONG( handle, HOOK_MAGIC );
292 /***********************************************************************
293 * UnhookWindowsHook (USER.234)
295 BOOL16 UnhookWindowsHook( INT16 id, HOOKPROC16 proc )
297 HANDLE16 hook = HOOK_GetHook( id , 0 );
299 dprintf_hook( stddeb, "UnhookWindowsHook: %d %08lx\n", id, (DWORD)proc );
301 while (hook)
303 HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook);
304 if (data->proc == proc) break;
305 hook = HOOK_GetNextHook( hook );
307 if (!hook) return FALSE;
308 return HOOK_RemoveHook( hook );
312 /***********************************************************************
313 * DefHookProc (USER.235)
315 LRESULT DefHookProc( INT16 code, WPARAM16 wParam, LPARAM lParam, HHOOK *hhook )
317 /* Note: the *hhook parameter is never used, since we rely on the
318 * current hook value from the task queue to find the next hook. */
319 MESSAGEQUEUE *queue;
320 HANDLE16 next;
322 if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
323 if (!(next = HOOK_GetNextHook( queue->hCurHook ))) return 0;
324 return HOOK_CallHook( next, code, wParam, lParam );
328 /***********************************************************************
329 * CallMsgFilter (USER.123)
331 BOOL16 CallMsgFilter( SEGPTR msg, INT16 code )
333 if (GetSysModalWindow16()) return FALSE;
334 if (HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)msg )) return TRUE;
335 return HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)msg );
339 /***********************************************************************
340 * SetWindowsHookEx (USER.291)
342 HHOOK SetWindowsHookEx( INT16 id, HOOKPROC16 proc, HINSTANCE16 hInst,
343 HTASK16 hTask )
345 HANDLE16 handle = HOOK_SetHook( id, proc, hInst, hTask );
346 return MAKELONG( handle, HOOK_MAGIC );
350 /***********************************************************************
351 * UnhookWindowHookEx (USER.292)
353 BOOL16 UnhookWindowsHookEx( HHOOK hhook )
355 if (HIWORD(hhook) != HOOK_MAGIC) return FALSE; /* Not a new format hook */
356 return HOOK_RemoveHook( LOWORD(hhook) );
360 /***********************************************************************
361 * CallNextHookEx (USER.293)
363 LRESULT CallNextHookEx(HHOOK hhook, INT16 code, WPARAM16 wParam, LPARAM lParam)
365 HANDLE16 next;
366 if (HIWORD(hhook) != HOOK_MAGIC) return 0; /* Not a new format hook */
367 if (!(next = HOOK_GetNextHook( LOWORD(hhook) ))) return 0;
368 return HOOK_CallHook( next, code, wParam, lParam );