2 * Windows hook functions
4 * Copyright 2002 Alexandre Julliard
5 * Copyright 2005 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * Status of the various hooks:
24 * WH_JOURNALRECORD Partially implemented
25 * WH_JOURNALPLAYBACK Partially implemented
27 * WH_GETMESSAGE OK (FIXME: A/W mapping?)
28 * WH_CALLWNDPROC OK (FIXME: A/W mapping?)
36 * HCBT_CLICKSKIPPED OK
42 * WH_HARDWARE Not supported in Win32
43 * WH_DEBUG Not implemented
45 * HSHELL_WINDOWCREATED OK
46 * HSHELL_WINDOWDESTROYED OK
47 * HSHELL_ACTIVATESHELLWINDOW Not implemented
48 * HSHELL_WINDOWACTIVATED Not implemented
49 * HSHELL_GETMINRECT Not implemented
50 * HSHELL_REDRAW Not implemented
51 * HSHELL_TASKMAN Not implemented
52 * HSHELL_LANGUAGE Not implemented
53 * HSHELL_SYSMENU Not implemented
54 * HSHELL_ENDTASK Not implemented
55 * HSHELL_ACCESSIBILITYSTATE Not implemented
56 * HSHELL_APPCOMMAND Not implemented
57 * HSHELL_WINDOWREPLACED Not implemented
58 * HSHELL_WINDOWREPLACING Not implemented
59 * WH_FOREGROUNDIDLE Not implemented
60 * WH_CALLWNDPROCRET OK (FIXME: A/W mapping?)
61 * WH_KEYBOARD_LL Implemented but should use SendMessage instead
62 * WH_MOUSE_LL Implemented but should use SendMessage instead
75 #include "user_private.h"
76 #include "wine/server.h"
78 #include "wine/debug.h"
81 WINE_DEFAULT_DEBUG_CHANNEL(hook
);
82 WINE_DECLARE_DEBUG_CHANNEL(relay
);
84 static struct user_api_hook original_user_api
=
90 static struct user_api_hook hooked_user_api
;
91 struct user_api_hook
*user_api
= &original_user_api
;
99 BOOL prev_unicode
, next_unicode
;
100 WCHAR module
[MAX_PATH
];
103 #define WH_WINEVENT (WH_MAXHOOK+1)
105 static const char * const hook_names
[WH_WINEVENT
- WH_MINHOOK
+ 1] =
109 "WH_JOURNALPLAYBACK",
127 /***********************************************************************
130 * Implementation of SetWindowsHookExA and SetWindowsHookExW.
132 static HHOOK
set_windows_hook( INT id
, HOOKPROC proc
, HINSTANCE inst
, DWORD tid
, BOOL ansi
)
134 WCHAR module
[MAX_PATH
];
139 RtlInitUnicodeString( &str
, NULL
);
143 size_t len
= GetModuleFileNameW( inst
, module
, ARRAYSIZE(module
) );
144 if (!len
|| len
>= ARRAYSIZE(module
))
146 SetLastError( ERROR_INVALID_PARAMETER
);
150 str
.MaximumLength
= str
.Length
= len
* sizeof(WCHAR
);
153 return NtUserSetWindowsHookEx( inst
, &str
, tid
, id
, proc
, ansi
);
157 /* Some apps pass a non-stdcall proc to SetWindowsHookExA,
158 * so we need a small assembly wrapper to call the proc.
160 extern LRESULT
HOOKPROC_wrapper( HOOKPROC proc
,
161 INT code
, WPARAM wParam
, LPARAM lParam
);
162 __ASM_GLOBAL_FUNC( HOOKPROC_wrapper
,
164 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
165 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
167 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
169 __ASM_CFI(".cfi_rel_offset %edi,-4\n\t")
171 __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
173 __ASM_CFI(".cfi_rel_offset %ebx,-12\n\t")
177 "movl 8(%ebp),%eax\n\t"
179 "leal -12(%ebp),%esp\n\t"
181 __ASM_CFI(".cfi_same_value %ebx\n\t")
183 __ASM_CFI(".cfi_same_value %esi\n\t")
185 __ASM_CFI(".cfi_same_value %edi\n\t")
187 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
188 __ASM_CFI(".cfi_same_value %ebp\n\t")
191 static inline LRESULT
HOOKPROC_wrapper( HOOKPROC proc
,
192 INT code
, WPARAM wParam
, LPARAM lParam
)
194 return proc( code
, wParam
, lParam
);
196 #endif /* __i386__ */
199 /***********************************************************************
202 static LRESULT
call_hook_AtoW( HOOKPROC proc
, INT id
, INT code
, WPARAM wparam
, LPARAM lparam
)
205 UNICODE_STRING usBuffer
;
206 if (id
!= WH_CBT
|| code
!= HCBT_CREATEWND
)
207 ret
= HOOKPROC_wrapper( proc
, code
, wparam
, lparam
);
210 CBT_CREATEWNDA
*cbtcwA
= (CBT_CREATEWNDA
*)lparam
;
211 CBT_CREATEWNDW cbtcwW
;
214 LPWSTR classW
= NULL
;
217 cbtcwW
.hwndInsertAfter
= cbtcwA
->hwndInsertAfter
;
218 csW
= *(CREATESTRUCTW
*)cbtcwA
->lpcs
;
220 if (!IS_INTRESOURCE(cbtcwA
->lpcs
->lpszName
))
222 RtlCreateUnicodeStringFromAsciiz(&usBuffer
,cbtcwA
->lpcs
->lpszName
);
223 csW
.lpszName
= nameW
= usBuffer
.Buffer
;
225 if (!IS_INTRESOURCE(cbtcwA
->lpcs
->lpszClass
))
227 RtlCreateUnicodeStringFromAsciiz(&usBuffer
,cbtcwA
->lpcs
->lpszClass
);
228 csW
.lpszClass
= classW
= usBuffer
.Buffer
;
230 ret
= HOOKPROC_wrapper( proc
, code
, wparam
, (LPARAM
)&cbtcwW
);
231 cbtcwA
->hwndInsertAfter
= cbtcwW
.hwndInsertAfter
;
232 HeapFree( GetProcessHeap(), 0, nameW
);
233 HeapFree( GetProcessHeap(), 0, classW
);
239 /***********************************************************************
242 static LRESULT
call_hook_WtoA( HOOKPROC proc
, INT id
, INT code
, WPARAM wparam
, LPARAM lparam
)
246 if (id
!= WH_CBT
|| code
!= HCBT_CREATEWND
)
247 ret
= HOOKPROC_wrapper( proc
, code
, wparam
, lparam
);
250 CBT_CREATEWNDW
*cbtcwW
= (CBT_CREATEWNDW
*)lparam
;
251 CBT_CREATEWNDA cbtcwA
;
258 cbtcwA
.hwndInsertAfter
= cbtcwW
->hwndInsertAfter
;
259 csA
= *(CREATESTRUCTA
*)cbtcwW
->lpcs
;
261 if (!IS_INTRESOURCE(cbtcwW
->lpcs
->lpszName
)) {
262 len
= WideCharToMultiByte( CP_ACP
, 0, cbtcwW
->lpcs
->lpszName
, -1, NULL
, 0, NULL
, NULL
);
263 nameA
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof(CHAR
) );
264 WideCharToMultiByte( CP_ACP
, 0, cbtcwW
->lpcs
->lpszName
, -1, nameA
, len
, NULL
, NULL
);
265 csA
.lpszName
= nameA
;
268 if (!IS_INTRESOURCE(cbtcwW
->lpcs
->lpszClass
)) {
269 len
= WideCharToMultiByte( CP_ACP
, 0, cbtcwW
->lpcs
->lpszClass
, -1, NULL
, 0, NULL
, NULL
);
270 classA
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof(CHAR
) );
271 WideCharToMultiByte( CP_ACP
, 0, cbtcwW
->lpcs
->lpszClass
, -1, classA
, len
, NULL
, NULL
);
272 csA
.lpszClass
= classA
;
275 ret
= HOOKPROC_wrapper( proc
, code
, wparam
, (LPARAM
)&cbtcwA
);
276 cbtcwW
->hwndInsertAfter
= cbtcwA
.hwndInsertAfter
;
277 HeapFree( GetProcessHeap(), 0, nameA
);
278 HeapFree( GetProcessHeap(), 0, classA
);
284 /***********************************************************************
287 static LRESULT
call_hook_proc( HOOKPROC proc
, INT id
, INT code
, WPARAM wparam
, LPARAM lparam
,
288 BOOL prev_unicode
, BOOL next_unicode
)
292 TRACE_(relay
)( "\1Call hook proc %p (id=%s,code=%x,wp=%08lx,lp=%08lx)\n",
293 proc
, hook_names
[id
-WH_MINHOOK
], code
, wparam
, lparam
);
295 if (!prev_unicode
== !next_unicode
) ret
= proc( code
, wparam
, lparam
);
296 else if (prev_unicode
) ret
= call_hook_WtoA( proc
, id
, code
, wparam
, lparam
);
297 else ret
= call_hook_AtoW( proc
, id
, code
, wparam
, lparam
);
299 TRACE_(relay
)( "\1Ret hook proc %p (id=%s,code=%x,wp=%08lx,lp=%08lx) retval=%08lx\n",
300 proc
, hook_names
[id
-WH_MINHOOK
], code
, wparam
, lparam
, ret
);
306 /***********************************************************************
309 * Retrieve the hook procedure real value for a module-relative proc
311 void *get_hook_proc( void *proc
, const WCHAR
*module
, HMODULE
*free_module
)
315 GetModuleHandleExW( 0, module
, &mod
);
319 TRACE( "loading %s\n", debugstr_w(module
) );
320 /* FIXME: the library will never be freed */
321 if (!(mod
= LoadLibraryExW(module
, NULL
, LOAD_WITH_ALTERED_SEARCH_PATH
))) return NULL
;
323 return (char *)mod
+ (ULONG_PTR
)proc
;
327 /***********************************************************************
330 LRESULT
HOOK_CallHooks( INT id
, INT code
, WPARAM wparam
, LPARAM lparam
, BOOL unicode
)
332 struct win_hook_params params
;
335 params
.wparam
= wparam
;
336 params
.lparam
= lparam
;
337 params
.next_unicode
= unicode
;
338 return NtUserCallOneParam( (UINT_PTR
)¶ms
, NtUserCallHooks
);
342 /***********************************************************************
343 * SetWindowsHookA (USER32.@)
345 HHOOK WINAPI
SetWindowsHookA( INT id
, HOOKPROC proc
)
347 return SetWindowsHookExA( id
, proc
, 0, GetCurrentThreadId() );
351 /***********************************************************************
352 * SetWindowsHookW (USER32.@)
354 HHOOK WINAPI
SetWindowsHookW( INT id
, HOOKPROC proc
)
356 return SetWindowsHookExW( id
, proc
, 0, GetCurrentThreadId() );
360 /***********************************************************************
361 * SetWindowsHookExA (USER32.@)
363 HHOOK WINAPI
SetWindowsHookExA( INT id
, HOOKPROC proc
, HINSTANCE inst
, DWORD tid
)
365 return set_windows_hook( id
, proc
, inst
, tid
, TRUE
);
368 /***********************************************************************
369 * SetWindowsHookExW (USER32.@)
371 HHOOK WINAPI
SetWindowsHookExW( INT id
, HOOKPROC proc
, HINSTANCE inst
, DWORD tid
)
373 return set_windows_hook( id
, proc
, inst
, tid
, FALSE
);
377 /***********************************************************************
378 * UnhookWindowsHook (USER32.@)
380 BOOL WINAPI
UnhookWindowsHook( INT id
, HOOKPROC proc
)
382 return NtUserCallTwoParam( id
, (UINT_PTR
)proc
, NtUserUnhookWindowsHook
);
386 /***********************************************************************
387 * CallMsgFilterA (USER32.@)
389 BOOL WINAPI
CallMsgFilterA( LPMSG msg
, INT code
)
391 if (HOOK_CallHooks( WH_SYSMSGFILTER
, code
, 0, (LPARAM
)msg
, FALSE
)) return TRUE
;
392 return HOOK_CallHooks( WH_MSGFILTER
, code
, 0, (LPARAM
)msg
, FALSE
);
396 /***********************************************************************
397 * CallMsgFilterW (USER32.@)
399 BOOL WINAPI
CallMsgFilterW( LPMSG msg
, INT code
)
401 if (HOOK_CallHooks( WH_SYSMSGFILTER
, code
, 0, (LPARAM
)msg
, TRUE
)) return TRUE
;
402 return HOOK_CallHooks( WH_MSGFILTER
, code
, 0, (LPARAM
)msg
, TRUE
);
406 /***********************************************************************
407 * SetWinEventHook [USER32.@]
409 * Set up an event hook for a set of events.
412 * event_min [I] Lowest event handled by pfnProc
413 * event_max [I] Highest event handled by pfnProc
414 * inst [I] DLL containing pfnProc
415 * proc [I] Callback event hook function
416 * pid [I] Process to get events from, or 0 for all processes
417 * tid [I] Thread to get events from, or 0 for all threads
418 * flags [I] Flags indicating the status of pfnProc
421 * Success: A handle representing the hook.
422 * Failure: A NULL handle.
424 HWINEVENTHOOK WINAPI
SetWinEventHook(DWORD event_min
, DWORD event_max
,
425 HMODULE inst
, WINEVENTPROC proc
,
426 DWORD pid
, DWORD tid
, DWORD flags
)
428 WCHAR module
[MAX_PATH
];
432 TRACE("%d,%d,%p,%p,%08x,%04x,%08x\n", event_min
, event_max
, inst
,
433 proc
, pid
, tid
, flags
);
435 if (inst
&& (!(len
= GetModuleFileNameW( inst
, module
, MAX_PATH
)) || len
>= MAX_PATH
))
441 str
.Length
= str
.MaximumLength
= len
* sizeof(WCHAR
);
442 return NtUserSetWinEventHook( event_min
, event_max
, inst
, &str
, proc
, pid
, tid
, flags
);
445 BOOL WINAPI
User32CallWinEventHook( const struct win_event_hook_params
*params
, ULONG size
)
447 WINEVENTPROC proc
= params
->proc
;
448 HMODULE free_module
= 0;
450 if (params
->module
[0] && !(proc
= get_hook_proc( proc
, params
->module
, &free_module
))) return FALSE
;
452 TRACE_(relay
)( "\1Call winevent hook proc %p (hhook=%p,event=%x,hwnd=%p,object_id=%x,child_id=%x,tid=%04x,time=%x)\n",
453 proc
, params
->handle
, params
->event
, params
->hwnd
, params
->object_id
,
454 params
->child_id
, GetCurrentThreadId(), GetCurrentTime() );
456 proc( params
->handle
, params
->event
, params
->hwnd
, params
->object_id
, params
->child_id
,
457 GetCurrentThreadId(), GetCurrentTime() );
459 TRACE_(relay
)( "\1Ret winevent hook proc %p (hhook=%p,event=%x,hwnd=%p,object_id=%x,child_id=%x,tid=%04x,time=%x)\n",
460 proc
, params
->handle
, params
->event
, params
->hwnd
, params
->object_id
,
461 params
->child_id
, GetCurrentThreadId(), GetCurrentTime() );
463 if (free_module
) FreeLibrary( free_module
);
467 BOOL WINAPI
User32CallWindowsHook( const struct win_hook_params
*params
, ULONG size
)
469 HOOKPROC proc
= params
->proc
;
470 HMODULE free_module
= 0;
473 if (params
->module
[0] && !(proc
= get_hook_proc( proc
, params
->module
, &free_module
))) return FALSE
;
475 ret
= call_hook_proc( proc
, params
->id
, params
->code
, params
->wparam
, params
->lparam
,
476 params
->prev_unicode
, params
->next_unicode
);
478 if (free_module
) FreeLibrary( free_module
);
482 /***********************************************************************
483 * IsWinEventHookInstalled [USER32.@]
485 * Determine if an event hook is installed for an event.
488 * dwEvent [I] Id of the event
491 * TRUE, If there are any hooks installed for the event.
497 BOOL WINAPI
IsWinEventHookInstalled(DWORD dwEvent
)
499 /* FIXME: Needed by Office 2007 installer */
500 WARN("(%d)-stub!\n", dwEvent
);
504 /* Undocumented RegisterUserApiHook() */
505 BOOL WINAPI
RegisterUserApiHook(const struct user_api_hook
*new, struct user_api_hook
*old
)
511 hooked_user_api
= *new;
512 user_api
= &hooked_user_api
;
514 *old
= original_user_api
;
519 /* Undocumented UnregisterUserApiHook() */
520 void WINAPI
UnregisterUserApiHook(void)
522 InterlockedExchangePointer((void **)&user_api
, &original_user_api
);