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
);
35 if (!data
|| !hook
) 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 /***********************************************************************
46 * Get the first hook for a given type.
48 HANDLE
HOOK_GetHook( short id
, HQUEUE hQueue
)
53 if ((queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(hQueue
) )) != 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
*)GlobalLock16( 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
*)GlobalLock16( 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
*)GlobalLock16( 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
, 0 );
211 return HOOK_CallHook( hook
, code
, wParam
, lParam
);
215 /***********************************************************************
216 * HOOK_FreeModuleHooks
218 void HOOK_FreeModuleHooks( HMODULE hModule
)
220 /* remove all system hooks registered by this module */
226 for( id
= WH_FIRST_HOOK
; id
<= WH_LAST_HOOK
; id
++ )
228 hook
= HOOK_systemHooks
[id
- WH_FIRST_HOOK
];
230 if( (hptr
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
)) )
233 if( hptr
->ownerModule
== hModule
)
235 hptr
->inHookProc
= 0;
236 HOOK_RemoveHook(hook
);
244 /***********************************************************************
245 * HOOK_FreeQueueHooks
247 void HOOK_FreeQueueHooks( HQUEUE hQueue
)
249 /* remove all hooks registered by this queue */
251 HOOKDATA
* hptr
= NULL
;
255 for( id
= WH_FIRST_HOOK
; id
<= WH_LAST_HOOK
; id
++ )
257 hook
= HOOK_GetHook( id
, hQueue
);
260 next
= HOOK_GetNextHook(hook
);
262 hptr
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
);
263 if( hptr
&& hptr
->ownerQueue
== hQueue
)
265 hptr
->inHookProc
= 0;
266 HOOK_RemoveHook(hook
);
273 /***********************************************************************
274 * SetWindowsHook (USER.121)
276 FARPROC
SetWindowsHook( short id
, HOOKPROC proc
)
281 HINSTANCE hInst
= FarGetOwner( HIWORD(proc
) );
283 /* WH_MSGFILTER is the only task-specific hook for SetWindowsHook() */
284 HTASK hTask
= (id
== WH_MSGFILTER
) ? GetCurrentTask() : 0;
286 HANDLE handle
= HOOK_SetHook( id
, proc
, hInst
, hTask
);
287 if (!handle
) return (FARPROC
)-1;
288 if (!((HOOKDATA
*)USER_HEAP_LIN_ADDR( handle
))->next
) return 0;
289 /* Not sure if the return value is correct; should not matter much
290 * since it's never used (see DefHookProc). -- AJ */
292 return (FARPROC
)handle
;
294 return (FARPROC
)MAKELONG( handle
, HOOK_MAGIC
);
299 /***********************************************************************
300 * UnhookWindowsHook (USER.234)
302 BOOL
UnhookWindowsHook( short id
, HOOKPROC proc
)
304 HANDLE hook
= HOOK_GetHook( id
, 0 );
306 dprintf_hook( stddeb
, "UnhookWindowsHook: %d %08lx\n", id
, (DWORD
)proc
);
310 HOOKDATA
*data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
);
311 if (data
->proc
== proc
) break;
312 hook
= HOOK_GetNextHook( hook
);
314 if (!hook
) return FALSE
;
315 return HOOK_RemoveHook( hook
);
319 /***********************************************************************
320 * DefHookProc (USER.235)
322 DWORD
DefHookProc( short code
, WORD wParam
, DWORD lParam
, HHOOK
*hhook
)
324 /* Note: the *hhook parameter is never used, since we rely on the
325 * current hook value from the task queue to find the next hook. */
329 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
330 if (!(next
= HOOK_GetNextHook( queue
->hCurHook
))) return 0;
331 return HOOK_CallHook( next
, code
, wParam
, lParam
);
335 /***********************************************************************
336 * CallMsgFilter (USER.123)
338 BOOL
CallMsgFilter( SEGPTR msg
, INT code
)
340 if (GetSysModalWindow()) return FALSE
;
341 if (HOOK_CallHooks( WH_SYSMSGFILTER
, code
, 0, (LPARAM
)msg
)) return TRUE
;
342 return HOOK_CallHooks( WH_MSGFILTER
, code
, 0, (LPARAM
)msg
);
346 /***********************************************************************
347 * SetWindowsHookEx (USER.291)
349 HHOOK
SetWindowsHookEx( short id
, HOOKPROC proc
, HINSTANCE hInst
, HTASK hTask
)
351 HANDLE handle
= HOOK_SetHook( id
, proc
, hInst
, hTask
);
353 return (HHOOK
)handle
;
355 return MAKELONG( handle
, HOOK_MAGIC
);
360 /***********************************************************************
361 * UnhookWindowHookEx (USER.292)
363 BOOL
UnhookWindowsHookEx( HHOOK hhook
)
366 return HOOK_RemoveHook( (HANDLE
)hhook
);
368 if (HIWORD(hhook
) != HOOK_MAGIC
) return FALSE
; /* Not a new format hook */
369 return HOOK_RemoveHook( LOWORD(hhook
) );
374 /***********************************************************************
375 * CallNextHookEx (USER.293)
377 LRESULT
CallNextHookEx( HHOOK hhook
, INT code
, WPARAM wParam
, LPARAM lParam
)
381 if (!(next
= HOOK_GetNextHook( (HANDLE
)hhook
))) return 0;
383 if (HIWORD(hhook
) != HOOK_MAGIC
) return 0; /* Not a new format hook */
384 if (!(next
= HOOK_GetNextHook( LOWORD(hhook
) ))) return 0;
386 return HOOK_CallHook( next
, code
, wParam
, lParam
);