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( 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_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
);
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 */
107 MESSAGEQUEUE
*queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
);
108 data
->next
= queue
->hooks
[id
- WH_FIRST_HOOK
];
109 queue
->hooks
[id
- WH_FIRST_HOOK
] = handle
;
113 data
->next
= HOOK_systemHooks
[id
- WH_FIRST_HOOK
];
114 HOOK_systemHooks
[id
- WH_FIRST_HOOK
] = handle
;
120 /***********************************************************************
123 * Remove a hook from the list.
125 static BOOL32
HOOK_RemoveHook( HANDLE16 hook
)
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;
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
);
161 /***********************************************************************
164 * Call a hook procedure.
166 static LRESULT
HOOK_CallHook( HANDLE16 hook
, INT16 code
,
167 WPARAM16 wParam
, LPARAM lParam
)
174 /* Find the first hook with a valid proc */
179 if (!(data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
))) return 0;
180 if (data
->proc
) break;
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
);
203 /***********************************************************************
208 LRESULT
HOOK_CallHooks( INT16 id
, INT16 code
, WPARAM16 wParam
, LPARAM lParam
)
210 HANDLE16 hook
= HOOK_GetHook( id
, GetTaskQueue(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 */
227 for( id
= WH_FIRST_HOOK
; id
<= WH_LAST_HOOK
; id
++ )
229 hook
= HOOK_systemHooks
[id
- WH_FIRST_HOOK
];
231 if( (hptr
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
)) )
234 if( hptr
->ownerModule
== hModule
)
236 hptr
->inHookProc
= 0;
237 HOOK_RemoveHook(hook
);
245 /***********************************************************************
246 * HOOK_FreeQueueHooks
248 void HOOK_FreeQueueHooks( HQUEUE16 hQueue
)
250 /* remove all hooks registered by this queue */
252 HOOKDATA
* hptr
= NULL
;
256 for( id
= WH_FIRST_HOOK
; id
<= WH_LAST_HOOK
; id
++ )
258 hook
= HOOK_GetHook( id
, hQueue
);
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
);
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
);
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. */
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
,
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
)
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
);