winevulkan: Avoid zero-sized allocations.
[wine.git] / dlls / user32 / hook.c
blob783ded6c12ac4474d77712f0ec2ab4a370e4bedd
1 /*
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
21 * NOTES:
22 * Status of the various hooks:
23 * WH_MSGFILTER OK
24 * WH_JOURNALRECORD Partially implemented
25 * WH_JOURNALPLAYBACK Partially implemented
26 * WH_KEYBOARD OK
27 * WH_GETMESSAGE OK (FIXME: A/W mapping?)
28 * WH_CALLWNDPROC OK (FIXME: A/W mapping?)
29 * WH_CBT
30 * HCBT_MOVESIZE OK
31 * HCBT_MINMAX OK
32 * HCBT_QS OK
33 * HCBT_CREATEWND OK
34 * HCBT_DESTROYWND OK
35 * HCBT_ACTIVATE OK
36 * HCBT_CLICKSKIPPED OK
37 * HCBT_KEYSKIPPED OK
38 * HCBT_SYSCOMMAND OK
39 * HCBT_SETFOCUS OK
40 * WH_SYSMSGFILTER OK
41 * WH_MOUSE OK
42 * WH_HARDWARE Not supported in Win32
43 * WH_DEBUG Not implemented
44 * WH_SHELL
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
65 #include <stdarg.h>
66 #include <assert.h>
68 #include "windef.h"
69 #include "winbase.h"
70 #include "winnls.h"
71 #include "wingdi.h"
72 #include "winuser.h"
73 #include "winerror.h"
74 #include "win.h"
75 #include "user_private.h"
76 #include "wine/server.h"
77 #include "wine/asm.h"
78 #include "wine/debug.h"
79 #include "winternl.h"
81 WINE_DEFAULT_DEBUG_CHANNEL(hook);
82 WINE_DECLARE_DEBUG_CHANNEL(relay);
84 static struct user_api_hook original_user_api =
86 USER_DefDlgProc,
87 USER_ScrollBarDraw,
88 USER_ScrollBarProc,
90 static struct user_api_hook hooked_user_api;
91 struct user_api_hook *user_api = &original_user_api;
93 struct hook_info
95 INT id;
96 void *proc;
97 void *handle;
98 DWORD pid, tid;
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] =
107 "WH_MSGFILTER",
108 "WH_JOURNALRECORD",
109 "WH_JOURNALPLAYBACK",
110 "WH_KEYBOARD",
111 "WH_GETMESSAGE",
112 "WH_CALLWNDPROC",
113 "WH_CBT",
114 "WH_SYSMSGFILTER",
115 "WH_MOUSE",
116 "WH_HARDWARE",
117 "WH_DEBUG",
118 "WH_SHELL",
119 "WH_FOREGROUNDIDLE",
120 "WH_CALLWNDPROCRET",
121 "WH_KEYBOARD_LL",
122 "WH_MOUSE_LL",
123 "WH_WINEVENT"
127 /***********************************************************************
128 * set_windows_hook
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];
135 UNICODE_STRING str;
137 if (!inst)
139 RtlInitUnicodeString( &str, NULL );
141 else
143 size_t len = GetModuleFileNameW( inst, module, ARRAYSIZE(module) );
144 if (!len || len >= ARRAYSIZE(module))
146 SetLastError( ERROR_INVALID_PARAMETER );
147 return 0;
149 str.Buffer = module;
150 str.MaximumLength = str.Length = len * sizeof(WCHAR);
153 return NtUserSetWindowsHookEx( inst, &str, tid, id, proc, ansi );
156 #ifdef __i386__
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,
163 "pushl %ebp\n\t"
164 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
165 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
166 "movl %esp,%ebp\n\t"
167 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
168 "pushl %edi\n\t"
169 __ASM_CFI(".cfi_rel_offset %edi,-4\n\t")
170 "pushl %esi\n\t"
171 __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
172 "pushl %ebx\n\t"
173 __ASM_CFI(".cfi_rel_offset %ebx,-12\n\t")
174 "pushl 20(%ebp)\n\t"
175 "pushl 16(%ebp)\n\t"
176 "pushl 12(%ebp)\n\t"
177 "movl 8(%ebp),%eax\n\t"
178 "call *%eax\n\t"
179 "leal -12(%ebp),%esp\n\t"
180 "popl %ebx\n\t"
181 __ASM_CFI(".cfi_same_value %ebx\n\t")
182 "popl %esi\n\t"
183 __ASM_CFI(".cfi_same_value %esi\n\t")
184 "popl %edi\n\t"
185 __ASM_CFI(".cfi_same_value %edi\n\t")
186 "leave\n\t"
187 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
188 __ASM_CFI(".cfi_same_value %ebp\n\t")
189 "ret" )
190 #else
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 /***********************************************************************
200 * call_hook_AtoW
202 static LRESULT call_hook_AtoW( HOOKPROC proc, INT id, INT code, WPARAM wparam, LPARAM lparam )
204 LRESULT ret;
205 UNICODE_STRING usBuffer;
206 if (id != WH_CBT || code != HCBT_CREATEWND)
207 ret = HOOKPROC_wrapper( proc, code, wparam, lparam );
208 else
210 CBT_CREATEWNDA *cbtcwA = (CBT_CREATEWNDA *)lparam;
211 CBT_CREATEWNDW cbtcwW;
212 CREATESTRUCTW csW;
213 LPWSTR nameW = NULL;
214 LPWSTR classW = NULL;
216 cbtcwW.lpcs = &csW;
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 );
235 return ret;
239 /***********************************************************************
240 * call_hook_WtoA
242 static LRESULT call_hook_WtoA( HOOKPROC proc, INT id, INT code, WPARAM wparam, LPARAM lparam )
244 LRESULT ret;
246 if (id != WH_CBT || code != HCBT_CREATEWND)
247 ret = HOOKPROC_wrapper( proc, code, wparam, lparam );
248 else
250 CBT_CREATEWNDW *cbtcwW = (CBT_CREATEWNDW *)lparam;
251 CBT_CREATEWNDA cbtcwA;
252 CREATESTRUCTA csA;
253 int len;
254 LPSTR nameA = NULL;
255 LPSTR classA = NULL;
257 cbtcwA.lpcs = &csA;
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 );
280 return ret;
284 /***********************************************************************
285 * call_hook_proc
287 static LRESULT call_hook_proc( HOOKPROC proc, INT id, INT code, WPARAM wparam, LPARAM lparam,
288 BOOL prev_unicode, BOOL next_unicode )
290 LRESULT ret;
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 );
302 return ret;
306 /***********************************************************************
307 * get_hook_proc
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 )
313 HMODULE mod;
315 GetModuleHandleExW( 0, module, &mod );
316 *free_module = mod;
317 if (!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 /***********************************************************************
328 * HOOK_CallHooks
330 LRESULT HOOK_CallHooks( INT id, INT code, WPARAM wparam, LPARAM lparam, BOOL unicode )
332 struct win_hook_params params;
333 params.id = id;
334 params.code = code;
335 params.wparam = wparam;
336 params.lparam = lparam;
337 params.next_unicode = unicode;
338 return NtUserCallOneParam( (UINT_PTR)&params, 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.
411 * PARAMS
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
420 * RETURNS
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];
429 UNICODE_STRING str;
430 DWORD len = 0;
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))
437 inst = 0;
438 len = 0;
440 str.Buffer = module;
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 );
464 return TRUE;
467 BOOL WINAPI User32CallWindowsHook( const struct win_hook_params *params, ULONG size )
469 HOOKPROC proc = params->proc;
470 HMODULE free_module = 0;
471 LRESULT ret;
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 );
479 return ret;
482 /***********************************************************************
483 * IsWinEventHookInstalled [USER32.@]
485 * Determine if an event hook is installed for an event.
487 * PARAMS
488 * dwEvent [I] Id of the event
490 * RETURNS
491 * TRUE, If there are any hooks installed for the event.
492 * FALSE, Otherwise.
494 * BUGS
495 * Not implemented.
497 BOOL WINAPI IsWinEventHookInstalled(DWORD dwEvent)
499 /* FIXME: Needed by Office 2007 installer */
500 WARN("(%d)-stub!\n", dwEvent);
501 return TRUE;
504 /* Undocumented RegisterUserApiHook() */
505 BOOL WINAPI RegisterUserApiHook(const struct user_api_hook *new, struct user_api_hook *old)
507 if (!new)
508 return FALSE;
510 USER_Lock();
511 hooked_user_api = *new;
512 user_api = &hooked_user_api;
513 if (old)
514 *old = original_user_api;
515 USER_Unlock();
516 return TRUE;
519 /* Undocumented UnregisterUserApiHook() */
520 void WINAPI UnregisterUserApiHook(void)
522 InterlockedExchangePointer((void **)&user_api, &original_user_api);