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 "NPFMT
" "NPFMT
"\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,"NPFMT
","NPFMT
")!\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="NPFMT
"\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 "NPFMT
"\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 "NPFMT
": %d %04lx %08lx\n",
191 hook
, code
, (DWORD
)wParam
, lParam
);
192 ret
= CallHookProc( data
->proc
, code
, wParam
, lParam
);
193 dprintf_hook( stddeb
, "Ret hook "NPFMT
" = %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
, short 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 DWORD
CallNextHookEx( HHOOK hhook
, short 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
);