dxgi: Add IDXGISwapChain2 stubs for D3D11.
[wine.git] / dlls / user32 / hook.c
blobb7d9da6fd5a3a1adf6fdf8e587618d3c7943a818
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 "ntstatus.h"
66 #define WIN32_NO_STATUS
67 #include "user_private.h"
68 #include "wine/asm.h"
69 #include "wine/debug.h"
71 WINE_DEFAULT_DEBUG_CHANNEL(hook);
72 WINE_DECLARE_DEBUG_CHANNEL(relay);
74 static struct user_api_hook original_user_api =
76 USER_DefDlgProc,
77 USER_NonClientButtonDraw,
78 USER_ScrollBarDraw,
79 USER_ScrollBarProc,
81 static struct user_api_hook hooked_user_api;
82 struct user_api_hook *user_api = &original_user_api;
84 struct hook_info
86 INT id;
87 void *proc;
88 void *handle;
89 DWORD pid, tid;
90 BOOL prev_unicode, next_unicode;
91 WCHAR module[MAX_PATH];
94 static CRITICAL_SECTION api_hook_cs;
95 static CRITICAL_SECTION_DEBUG critsect_debug =
97 0, 0, &api_hook_cs,
98 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
99 0, 0, { (DWORD_PTR)(__FILE__ ": api_hook_cs") }
101 static CRITICAL_SECTION api_hook_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
104 #define WH_WINEVENT (WH_MAXHOOK+1)
106 static const char * const hook_names[WH_WINEVENT - WH_MINHOOK + 1] =
108 "WH_MSGFILTER",
109 "WH_JOURNALRECORD",
110 "WH_JOURNALPLAYBACK",
111 "WH_KEYBOARD",
112 "WH_GETMESSAGE",
113 "WH_CALLWNDPROC",
114 "WH_CBT",
115 "WH_SYSMSGFILTER",
116 "WH_MOUSE",
117 "WH_HARDWARE",
118 "WH_DEBUG",
119 "WH_SHELL",
120 "WH_FOREGROUNDIDLE",
121 "WH_CALLWNDPROCRET",
122 "WH_KEYBOARD_LL",
123 "WH_MOUSE_LL",
124 "WH_WINEVENT"
128 /***********************************************************************
129 * set_windows_hook
131 * Implementation of SetWindowsHookExA and SetWindowsHookExW.
133 static HHOOK set_windows_hook( INT id, HOOKPROC proc, HINSTANCE inst, DWORD tid, BOOL ansi )
135 WCHAR module[MAX_PATH];
136 UNICODE_STRING str;
138 if (!inst)
140 RtlInitUnicodeString( &str, NULL );
142 else
144 size_t len = GetModuleFileNameW( inst, module, ARRAYSIZE(module) );
145 if (!len || len >= ARRAYSIZE(module))
147 SetLastError( ERROR_INVALID_PARAMETER );
148 return 0;
150 str.Buffer = module;
151 str.MaximumLength = str.Length = len * sizeof(WCHAR);
154 return NtUserSetWindowsHookEx( inst, &str, tid, id, proc, ansi );
157 #ifdef __i386__
158 /* Some apps pass a non-stdcall proc to SetWindowsHookExA,
159 * so we need a small assembly wrapper to call the proc.
161 extern LRESULT HOOKPROC_wrapper( HOOKPROC proc,
162 INT code, WPARAM wParam, LPARAM lParam );
163 __ASM_GLOBAL_FUNC( HOOKPROC_wrapper,
164 "pushl %ebp\n\t"
165 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
166 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
167 "movl %esp,%ebp\n\t"
168 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
169 "pushl %edi\n\t"
170 __ASM_CFI(".cfi_rel_offset %edi,-4\n\t")
171 "pushl %esi\n\t"
172 __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
173 "pushl %ebx\n\t"
174 __ASM_CFI(".cfi_rel_offset %ebx,-12\n\t")
175 "pushl 20(%ebp)\n\t"
176 "pushl 16(%ebp)\n\t"
177 "pushl 12(%ebp)\n\t"
178 "movl 8(%ebp),%eax\n\t"
179 "call *%eax\n\t"
180 "leal -12(%ebp),%esp\n\t"
181 "popl %ebx\n\t"
182 __ASM_CFI(".cfi_same_value %ebx\n\t")
183 "popl %esi\n\t"
184 __ASM_CFI(".cfi_same_value %esi\n\t")
185 "popl %edi\n\t"
186 __ASM_CFI(".cfi_same_value %edi\n\t")
187 "leave\n\t"
188 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
189 __ASM_CFI(".cfi_same_value %ebp\n\t")
190 "ret" )
191 #else
192 static inline LRESULT HOOKPROC_wrapper( HOOKPROC proc,
193 INT code, WPARAM wParam, LPARAM lParam )
195 return proc( code, wParam, lParam );
197 #endif /* __i386__ */
200 /***********************************************************************
201 * call_hook_AtoW
203 static LRESULT call_hook_AtoW( HOOKPROC proc, INT id, INT code, WPARAM wparam, LPARAM lparam )
205 LRESULT ret;
206 UNICODE_STRING usBuffer;
207 if (id != WH_CBT || code != HCBT_CREATEWND)
208 ret = HOOKPROC_wrapper( proc, code, wparam, lparam );
209 else
211 CBT_CREATEWNDA *cbtcwA = (CBT_CREATEWNDA *)lparam;
212 CBT_CREATEWNDW cbtcwW;
213 CREATESTRUCTW csW;
214 LPWSTR nameW = NULL;
215 LPWSTR classW = NULL;
216 WCHAR name_buf[3];
218 cbtcwW.lpcs = &csW;
219 cbtcwW.hwndInsertAfter = cbtcwA->hwndInsertAfter;
220 csW = *(CREATESTRUCTW *)cbtcwA->lpcs;
222 if (!IS_INTRESOURCE(cbtcwA->lpcs->lpszName))
224 if (cbtcwA->lpcs->lpszName[0] != '\xff')
226 RtlCreateUnicodeStringFromAsciiz( &usBuffer, cbtcwA->lpcs->lpszName );
227 csW.lpszName = nameW = usBuffer.Buffer;
229 else
231 name_buf[0] = 0xffff;
232 name_buf[1] = MAKEWORD( cbtcwA->lpcs->lpszName[1], cbtcwA->lpcs->lpszName[2] );
233 name_buf[2] = 0;
234 csW.lpszName = name_buf;
237 if (!IS_INTRESOURCE(cbtcwA->lpcs->lpszClass))
239 RtlCreateUnicodeStringFromAsciiz(&usBuffer,cbtcwA->lpcs->lpszClass);
240 csW.lpszClass = classW = usBuffer.Buffer;
242 ret = HOOKPROC_wrapper( proc, code, wparam, (LPARAM)&cbtcwW );
243 cbtcwA->hwndInsertAfter = cbtcwW.hwndInsertAfter;
244 HeapFree( GetProcessHeap(), 0, nameW );
245 HeapFree( GetProcessHeap(), 0, classW );
247 return ret;
251 /***********************************************************************
252 * call_hook_WtoA
254 static LRESULT call_hook_WtoA( HOOKPROC proc, INT id, INT code, WPARAM wparam, LPARAM lparam )
256 LRESULT ret;
258 if (id != WH_CBT || code != HCBT_CREATEWND)
259 ret = HOOKPROC_wrapper( proc, code, wparam, lparam );
260 else
262 CBT_CREATEWNDW *cbtcwW = (CBT_CREATEWNDW *)lparam;
263 CBT_CREATEWNDA cbtcwA;
264 CREATESTRUCTA csA;
265 int len;
266 LPSTR nameA = NULL;
267 LPSTR classA = NULL;
268 char name_buf[4];
270 cbtcwA.lpcs = &csA;
271 cbtcwA.hwndInsertAfter = cbtcwW->hwndInsertAfter;
272 csA = *(CREATESTRUCTA *)cbtcwW->lpcs;
274 if (!IS_INTRESOURCE(cbtcwW->lpcs->lpszName))
276 if (cbtcwW->lpcs->lpszName[0] != 0xffff)
278 len = WideCharToMultiByte( CP_ACP, 0, cbtcwW->lpcs->lpszName, -1, NULL, 0, NULL, NULL );
279 nameA = HeapAlloc( GetProcessHeap(), 0, len*sizeof(CHAR) );
280 WideCharToMultiByte( CP_ACP, 0, cbtcwW->lpcs->lpszName, -1, nameA, len, NULL, NULL );
281 csA.lpszName = nameA;
283 else
285 name_buf[0] = '\xff';
286 name_buf[1] = cbtcwW->lpcs->lpszName[1];
287 name_buf[2] = cbtcwW->lpcs->lpszName[1] >> 8;
288 name_buf[3] = 0;
289 csA.lpszName = name_buf;
293 if (!IS_INTRESOURCE(cbtcwW->lpcs->lpszClass)) {
294 len = WideCharToMultiByte( CP_ACP, 0, cbtcwW->lpcs->lpszClass, -1, NULL, 0, NULL, NULL );
295 classA = HeapAlloc( GetProcessHeap(), 0, len*sizeof(CHAR) );
296 WideCharToMultiByte( CP_ACP, 0, cbtcwW->lpcs->lpszClass, -1, classA, len, NULL, NULL );
297 csA.lpszClass = classA;
300 ret = HOOKPROC_wrapper( proc, code, wparam, (LPARAM)&cbtcwA );
301 cbtcwW->hwndInsertAfter = cbtcwA.hwndInsertAfter;
302 HeapFree( GetProcessHeap(), 0, nameA );
303 HeapFree( GetProcessHeap(), 0, classA );
305 return ret;
309 /***********************************************************************
310 * call_hook_proc
312 static LRESULT call_hook_proc( HOOKPROC proc, INT id, INT code, WPARAM wparam, LPARAM lparam,
313 BOOL prev_unicode, BOOL next_unicode )
315 LRESULT ret;
317 TRACE_(relay)( "\1Call hook proc %p (id=%s,code=%x,wp=%08Ix,lp=%08Ix)\n",
318 proc, hook_names[id-WH_MINHOOK], code, wparam, lparam );
320 if (!prev_unicode == !next_unicode) ret = proc( code, wparam, lparam );
321 else if (prev_unicode) ret = call_hook_WtoA( proc, id, code, wparam, lparam );
322 else ret = call_hook_AtoW( proc, id, code, wparam, lparam );
324 TRACE_(relay)( "\1Ret hook proc %p (id=%s,code=%x,wp=%08Ix,lp=%08Ix) retval=%08Ix\n",
325 proc, hook_names[id-WH_MINHOOK], code, wparam, lparam, ret );
327 return ret;
331 /***********************************************************************
332 * get_hook_proc
334 * Retrieve the hook procedure real value for a module-relative proc
336 void *get_hook_proc( void *proc, const WCHAR *module, HMODULE *free_module )
338 HMODULE mod;
340 GetModuleHandleExW( 0, module, &mod );
341 *free_module = mod;
342 if (!mod)
344 TRACE( "loading %s\n", debugstr_w(module) );
345 /* FIXME: the library will never be freed */
346 if (!(mod = LoadLibraryExW(module, NULL, LOAD_WITH_ALTERED_SEARCH_PATH))) return NULL;
348 return (char *)mod + (ULONG_PTR)proc;
352 /***********************************************************************
353 * SetWindowsHookA (USER32.@)
355 HHOOK WINAPI SetWindowsHookA( INT id, HOOKPROC proc )
357 return SetWindowsHookExA( id, proc, 0, GetCurrentThreadId() );
361 /***********************************************************************
362 * SetWindowsHookW (USER32.@)
364 HHOOK WINAPI SetWindowsHookW( INT id, HOOKPROC proc )
366 return SetWindowsHookExW( id, proc, 0, GetCurrentThreadId() );
370 /***********************************************************************
371 * SetWindowsHookExA (USER32.@)
373 HHOOK WINAPI SetWindowsHookExA( INT id, HOOKPROC proc, HINSTANCE inst, DWORD tid )
375 return set_windows_hook( id, proc, inst, tid, TRUE );
378 /***********************************************************************
379 * SetWindowsHookExW (USER32.@)
381 HHOOK WINAPI SetWindowsHookExW( INT id, HOOKPROC proc, HINSTANCE inst, DWORD tid )
383 return set_windows_hook( id, proc, inst, tid, FALSE );
387 /***********************************************************************
388 * UnhookWindowsHook (USER32.@)
390 BOOL WINAPI UnhookWindowsHook( INT id, HOOKPROC proc )
392 return NtUserUnhookWindowsHook( id, proc );
396 /***********************************************************************
397 * SetWinEventHook [USER32.@]
399 * Set up an event hook for a set of events.
401 * PARAMS
402 * event_min [I] Lowest event handled by pfnProc
403 * event_max [I] Highest event handled by pfnProc
404 * inst [I] DLL containing pfnProc
405 * proc [I] Callback event hook function
406 * pid [I] Process to get events from, or 0 for all processes
407 * tid [I] Thread to get events from, or 0 for all threads
408 * flags [I] Flags indicating the status of pfnProc
410 * RETURNS
411 * Success: A handle representing the hook.
412 * Failure: A NULL handle.
414 HWINEVENTHOOK WINAPI SetWinEventHook(DWORD event_min, DWORD event_max,
415 HMODULE inst, WINEVENTPROC proc,
416 DWORD pid, DWORD tid, DWORD flags)
418 WCHAR module[MAX_PATH];
419 UNICODE_STRING str;
420 DWORD len = 0;
422 TRACE("%ld,%ld,%p,%p,%08lx,%04lx,%08lx\n", event_min, event_max, inst,
423 proc, pid, tid, flags);
425 if (inst && (!(len = GetModuleFileNameW( inst, module, MAX_PATH )) || len >= MAX_PATH))
427 inst = 0;
428 len = 0;
430 str.Buffer = module;
431 str.Length = str.MaximumLength = len * sizeof(WCHAR);
432 return NtUserSetWinEventHook( event_min, event_max, inst, &str, proc, pid, tid, flags );
435 NTSTATUS WINAPI User32CallWinEventHook( void *args, ULONG size )
437 const struct win_event_hook_params *params = args;
438 WINEVENTPROC proc = params->proc;
439 HMODULE free_module = 0;
441 if (params->module[0] && !(proc = get_hook_proc( proc, params->module, &free_module )))
442 return STATUS_INVALID_PARAMETER;
444 TRACE_(relay)( "\1Call winevent hook proc %p (hhook=%p,event=%lx,hwnd=%p,object_id=%lx,child_id=%lx,tid=%04lx,time=%lx)\n",
445 proc, params->handle, params->event, params->hwnd, params->object_id,
446 params->child_id, params->tid, params->time );
448 proc( params->handle, params->event, params->hwnd, params->object_id, params->child_id,
449 params->tid, params->time );
451 TRACE_(relay)( "\1Ret winevent hook proc %p (hhook=%p,event=%lx,hwnd=%p,object_id=%lx,child_id=%lx,tid=%04lx,time=%lx)\n",
452 proc, params->handle, params->event, params->hwnd, params->object_id,
453 params->child_id, params->tid, params->time );
455 if (free_module) FreeLibrary( free_module );
456 return STATUS_SUCCESS;
459 NTSTATUS WINAPI User32CallWindowsHook( void *args, ULONG size )
461 struct win_hook_params *params = args;
462 HOOKPROC proc = params->proc;
463 HMODULE free_module = 0;
464 void *ret_ptr = NULL;
465 CBT_CREATEWNDW cbtc;
466 UINT ret_size = 0;
467 size_t lparam_offset;
468 LRESULT ret;
470 lparam_offset = FIELD_OFFSET( struct win_hook_params, module[wcslen( params->module ) + 1]);
472 if (lparam_offset < size)
474 lparam_offset = (lparam_offset + 15) & ~15; /* align */
475 ret_size = size - lparam_offset;
476 ret_ptr = (char *)params + lparam_offset;
477 params->lparam = (LPARAM)ret_ptr;
479 switch (params->id)
481 case WH_CBT:
482 if (params->code == HCBT_CREATEWND)
484 cbtc.hwndInsertAfter = HWND_TOP;
485 unpack_message( (HWND)params->wparam, WM_CREATE, NULL, (LPARAM *)&cbtc.lpcs,
486 ret_ptr, FALSE );
487 params->lparam = (LPARAM)&cbtc;
488 ret_size = sizeof(*cbtc.lpcs);
490 break;
491 case WH_CALLWNDPROC:
492 if (ret_size > sizeof(CWPSTRUCT))
494 CWPSTRUCT *cwp = (CWPSTRUCT *)params->lparam;
495 size_t offset = (lparam_offset + sizeof(*cwp) + 15) & ~15;
497 unpack_message( cwp->hwnd, cwp->message, &cwp->wParam, &cwp->lParam,
498 (char *)params + offset, !params->prev_unicode );
499 ret_size = 0;
500 break;
502 case WH_CALLWNDPROCRET:
503 if (ret_size > sizeof(CWPRETSTRUCT))
505 CWPRETSTRUCT *cwpret = (CWPRETSTRUCT *)params->lparam;
506 size_t offset = (lparam_offset + sizeof(*cwpret) + 15) & ~15;
508 unpack_message( cwpret->hwnd, cwpret->message, &cwpret->wParam, &cwpret->lParam,
509 (char *)params + offset, !params->prev_unicode );
510 ret_size = 0;
511 break;
515 if (params->module[0] && !(proc = get_hook_proc( proc, params->module, &free_module )))
516 return FALSE;
518 ret = call_hook_proc( proc, params->id, params->code, params->wparam, params->lparam,
519 params->prev_unicode, params->next_unicode );
521 if (free_module) FreeLibrary( free_module );
523 if (ret_size)
525 LRESULT *result_ptr = (LRESULT *)ret_ptr - 1;
526 *result_ptr = ret;
527 return NtCallbackReturn( result_ptr, sizeof(*result_ptr) + ret_size, STATUS_SUCCESS );
529 return NtCallbackReturn( &ret, sizeof(ret), STATUS_SUCCESS );
532 /***********************************************************************
533 * IsWinEventHookInstalled [USER32.@]
535 * Determine if an event hook is installed for an event.
537 * PARAMS
538 * dwEvent [I] Id of the event
540 * RETURNS
541 * TRUE, If there are any hooks installed for the event.
542 * FALSE, Otherwise.
544 * BUGS
545 * Not implemented.
547 BOOL WINAPI IsWinEventHookInstalled(DWORD dwEvent)
549 /* FIXME: Needed by Office 2007 installer */
550 WARN("(%ld)-stub!\n", dwEvent);
551 return TRUE;
554 /* Undocumented RegisterUserApiHook() */
555 BOOL WINAPI RegisterUserApiHook(const struct user_api_hook *new_hook, struct user_api_hook *old_hook)
557 if (!new_hook)
558 return FALSE;
560 EnterCriticalSection( &api_hook_cs );
561 hooked_user_api = *new_hook;
562 user_api = &hooked_user_api;
563 if (old_hook)
564 *old_hook = original_user_api;
565 LeaveCriticalSection( &api_hook_cs );
566 return TRUE;
569 /* Undocumented UnregisterUserApiHook() */
570 void WINAPI UnregisterUserApiHook(void)
572 InterlockedExchangePointer((void **)&user_api, &original_user_api);