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_MINHOOK
];
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_MINHOOK
];
56 if (!hook
) hook
= HOOK_systemHooks
[id
- WH_MINHOOK
];
61 /***********************************************************************
64 * Install a given hook.
66 static HANDLE16
HOOK_SetHook( INT16 id
, HOOKPROC16 proc
, HINSTANCE16 hInst
,
73 if ((id
< WH_MINHOOK
) || (id
> WH_MAXHOOK
)) 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;
88 fprintf( stdnimp
,"WH_DEBUG is broken in 16-bit Windows.\n");
91 else if (id
== WH_CBT
|| id
== WH_SHELL
)
93 fprintf( stdnimp
, "Half-implemented hook set: (%s,%08lx,%04x,%04x)!\n",
94 (id
==WH_CBT
)?"WH_CBT":"WH_SHELL", (DWORD
)proc
, hInst
, hTask
);
97 if (id
== WH_JOURNALPLAYBACK
) EnableHardwareInput(FALSE
);
99 /* Create the hook structure */
101 if (!(handle
= USER_HEAP_ALLOC( sizeof(HOOKDATA
) ))) return 0;
102 data
= (HOOKDATA
*) USER_HEAP_LIN_ADDR( handle
);
105 data
->ownerQueue
= hQueue
;
106 data
->ownerModule
= hInst
;
107 data
->inHookProc
= 0;
108 dprintf_hook( stddeb
, "Setting hook %d: ret=%04x\n", id
, handle
);
110 /* Insert it in the correct linked list */
114 MESSAGEQUEUE
*queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
);
115 data
->next
= queue
->hooks
[id
- WH_MINHOOK
];
116 queue
->hooks
[id
- WH_MINHOOK
] = handle
;
120 data
->next
= HOOK_systemHooks
[id
- WH_MINHOOK
];
121 HOOK_systemHooks
[id
- WH_MINHOOK
] = handle
;
127 /***********************************************************************
130 * Remove a hook from the list.
132 static BOOL32
HOOK_RemoveHook( HANDLE16 hook
)
137 dprintf_hook( stddeb
, "Removing hook %04x\n", hook
);
139 if (!(data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
))) return FALSE
;
140 if (data
->inHookProc
)
142 /* Mark it for deletion later on */
143 dprintf_hook( stddeb
, "Hook still running, deletion delayed\n" );
144 data
->proc
= (HOOKPROC16
)0;
148 if (data
->id
== WH_JOURNALPLAYBACK
) EnableHardwareInput(TRUE
);
150 /* Remove it from the linked list */
152 if (data
->ownerQueue
)
154 MESSAGEQUEUE
*queue
= (MESSAGEQUEUE
*)GlobalLock16( data
->ownerQueue
);
155 if (!queue
) return FALSE
;
156 prevHook
= &queue
->hooks
[data
->id
- WH_MINHOOK
];
158 else prevHook
= &HOOK_systemHooks
[data
->id
- WH_MINHOOK
];
160 while (*prevHook
&& *prevHook
!= hook
)
161 prevHook
= &((HOOKDATA
*)USER_HEAP_LIN_ADDR(*prevHook
))->next
;
163 if (!*prevHook
) return FALSE
;
164 *prevHook
= data
->next
;
165 USER_HEAP_FREE( hook
);
170 /***********************************************************************
173 * Call a hook procedure.
175 static LRESULT
HOOK_CallHook( HANDLE16 hook
, INT16 code
,
176 WPARAM16 wParam
, LPARAM lParam
)
183 /* Find the first hook with a valid proc */
188 if (!(data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
))) return 0;
189 if (data
->proc
) break;
195 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
196 prevHook
= queue
->hCurHook
;
197 queue
->hCurHook
= hook
;
198 data
->inHookProc
= 1;
200 dprintf_hook( stddeb
, "Calling hook %04x: %d %04lx %08lx\n",
201 hook
, code
, (DWORD
)wParam
, lParam
);
202 ret
= CallHookProc( data
->proc
, code
, wParam
, lParam
);
203 dprintf_hook( stddeb
, "Ret hook %04x = %08lx\n", hook
, ret
);
205 data
->inHookProc
= 0;
206 queue
->hCurHook
= prevHook
;
207 if (!data
->proc
) HOOK_RemoveHook( hook
);
212 /***********************************************************************
217 LRESULT
HOOK_CallHooks( INT16 id
, INT16 code
, WPARAM16 wParam
, LPARAM lParam
)
219 HANDLE16 hook
= HOOK_GetHook( id
, GetTaskQueue(0) );
221 return HOOK_CallHook( hook
, code
, wParam
, lParam
);
225 /***********************************************************************
226 * HOOK_FreeModuleHooks
228 void HOOK_FreeModuleHooks( HMODULE16 hModule
)
230 /* remove all system hooks registered by this module */
236 for( id
= WH_MINHOOK
; id
<= WH_MAXHOOK
; id
++ )
238 hook
= HOOK_systemHooks
[id
- WH_MINHOOK
];
240 if( (hptr
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
)) )
243 if( hptr
->ownerModule
== hModule
)
245 hptr
->inHookProc
= 0;
246 HOOK_RemoveHook(hook
);
254 /***********************************************************************
255 * HOOK_FreeQueueHooks
257 void HOOK_FreeQueueHooks( HQUEUE16 hQueue
)
259 /* remove all hooks registered by this queue */
261 HOOKDATA
* hptr
= NULL
;
265 for( id
= WH_MINHOOK
; id
<= WH_MAXHOOK
; id
++ )
267 hook
= HOOK_GetHook( id
, hQueue
);
270 next
= HOOK_GetNextHook(hook
);
272 hptr
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
);
273 if( hptr
&& hptr
->ownerQueue
== hQueue
)
275 hptr
->inHookProc
= 0;
276 HOOK_RemoveHook(hook
);
283 /***********************************************************************
284 * SetWindowsHook (USER.121)
286 FARPROC16
SetWindowsHook( INT16 id
, HOOKPROC16 proc
)
288 HINSTANCE16 hInst
= __winelib
? 0 : FarGetOwner( HIWORD(proc
) );
289 HTASK16 hTask
= (id
== WH_MSGFILTER
) ? GetCurrentTask() : 0;
290 HANDLE16 handle
= HOOK_SetHook( id
, proc
, hInst
, hTask
);
292 return (handle
) ? (FARPROC16
)MAKELONG( handle
, HOOK_MAGIC
) : NULL
;
296 /***********************************************************************
297 * UnhookWindowsHook (USER.234)
299 BOOL16
UnhookWindowsHook( INT16 id
, HOOKPROC16 proc
)
301 HANDLE16 hook
= HOOK_GetHook( id
, 0 );
303 dprintf_hook( stddeb
, "UnhookWindowsHook: %d %08lx\n", id
, (DWORD
)proc
);
307 HOOKDATA
*data
= (HOOKDATA
*)USER_HEAP_LIN_ADDR(hook
);
308 if (data
->proc
== proc
) break;
309 hook
= HOOK_GetNextHook( hook
);
311 if (!hook
) return FALSE
;
312 return HOOK_RemoveHook( hook
);
316 /***********************************************************************
317 * DefHookProc (USER.235)
319 LRESULT
DefHookProc( INT16 code
, WPARAM16 wParam
, LPARAM lParam
, HHOOK
*hhook
)
321 /* Note: the *hhook parameter is never used, since we rely on the
322 * current hook value from the task queue to find the next hook. */
326 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
327 if (!(next
= HOOK_GetNextHook( queue
->hCurHook
))) return 0;
328 return HOOK_CallHook( next
, code
, wParam
, lParam
);
332 /***********************************************************************
333 * CallMsgFilter (USER.123)
335 BOOL16
CallMsgFilter( SEGPTR msg
, INT16 code
)
337 if (GetSysModalWindow16()) return FALSE
;
338 if (HOOK_CallHooks( WH_SYSMSGFILTER
, code
, 0, (LPARAM
)msg
)) return TRUE
;
339 return HOOK_CallHooks( WH_MSGFILTER
, code
, 0, (LPARAM
)msg
);
343 /***********************************************************************
344 * SetWindowsHookEx (USER.291)
346 HHOOK
SetWindowsHookEx( INT16 id
, HOOKPROC16 proc
, HINSTANCE16 hInst
,
349 HANDLE16 handle
= HOOK_SetHook( id
, proc
, hInst
, hTask
);
350 return (handle
) ? MAKELONG( handle
, HOOK_MAGIC
) : NULL
;
354 /***********************************************************************
355 * UnhookWindowHookEx (USER.292)
357 BOOL16
UnhookWindowsHookEx( HHOOK hhook
)
359 if (HIWORD(hhook
) != HOOK_MAGIC
) return FALSE
; /* Not a new format hook */
360 return HOOK_RemoveHook( LOWORD(hhook
) );
364 /***********************************************************************
365 * CallNextHookEx (USER.293)
367 LRESULT
CallNextHookEx(HHOOK hhook
, INT16 code
, WPARAM16 wParam
, LPARAM lParam
)
370 if (HIWORD(hhook
) != HOOK_MAGIC
) return 0; /* Not a new format hook */
371 if (!(next
= HOOK_GetNextHook( LOWORD(hhook
) ))) return 0;
372 return HOOK_CallHook( next
, code
, wParam
, lParam
);