7df8e25ba814a573b9811320973bfd465ff8ae55
[reactos.git] / reactos / dll / win32 / user32 / windows / hook.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /*
20 *
21 * PROJECT: ReactOS user32.dll
22 * FILE: lib/user32/windows/input.c
23 * PURPOSE: Input
24 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * UPDATE HISTORY:
26 * 09-05-2001 CSH Created
27 */
28
29 /* INCLUDES ******************************************************************/
30
31 #include <user32.h>
32
33 #include <wine/debug.h>
34
35 WINE_DEFAULT_DEBUG_CHANNEL(user32);
36
37 typedef struct _NOTIFYEVENT
38 {
39 DWORD event;
40 LONG idObject;
41 LONG idChild;
42 DWORD flags;
43 } NOTIFYEVENT, *PNOTIFYEVENT;
44
45 /* PRIVATE FUNCTIONS *********************************************************/
46
47 static
48 DWORD
49 FASTCALL
50 GetMaskFromEvent(DWORD Event)
51 {
52 DWORD Ret = 0;
53
54 if ( Event > EVENT_OBJECT_STATECHANGE )
55 {
56 if ( Event == EVENT_OBJECT_LOCATIONCHANGE ) return SRV_EVENT_LOCATIONCHANGE;
57 if ( Event == EVENT_OBJECT_NAMECHANGE ) return SRV_EVENT_NAMECHANGE;
58 if ( Event == EVENT_OBJECT_VALUECHANGE ) return SRV_EVENT_VALUECHANGE;
59 return SRV_EVENT_CREATE;
60 }
61
62 if ( Event == EVENT_OBJECT_STATECHANGE ) return SRV_EVENT_STATECHANGE;
63
64 Ret = SRV_EVENT_RUNNING;
65
66 if ( Event < EVENT_SYSTEM_MENUSTART ) return SRV_EVENT_CREATE;
67
68 if ( Event <= EVENT_SYSTEM_MENUPOPUPEND )
69 {
70 Ret = SRV_EVENT_MENU;
71 }
72 else
73 {
74 if ( Event <= EVENT_CONSOLE_CARET-1 ) return SRV_EVENT_CREATE;
75 if ( Event <= EVENT_CONSOLE_END_APPLICATION ) return SRV_EVENT_END_APPLICATION;
76 if ( Event != EVENT_OBJECT_FOCUS ) return SRV_EVENT_CREATE;
77 }
78 return Ret;
79 }
80
81 static
82 HHOOK
83 FASTCALL
84 IntSetWindowsHook(
85 int idHook,
86 HOOKPROC lpfn,
87 HINSTANCE hMod,
88 DWORD dwThreadId,
89 BOOL bAnsi)
90 {
91 WCHAR ModuleName[MAX_PATH];
92 UNICODE_STRING USModuleName;
93
94 if (NULL != hMod)
95 {
96 if (0 == GetModuleFileNameW(hMod, ModuleName, MAX_PATH))
97 {
98 return NULL;
99 }
100 RtlInitUnicodeString(&USModuleName, ModuleName);
101 }
102 else
103 {
104 RtlInitUnicodeString(&USModuleName, NULL);
105 }
106
107 return NtUserSetWindowsHookEx(hMod, &USModuleName, dwThreadId, idHook, lpfn, bAnsi);
108 }
109
110 /*
111 Since ReactOS uses User32 as the main message source this was needed.
112 Base on the funny rules from the wine tests it left it with this option.
113 8^(
114 */
115 VOID
116 FASTCALL
117 IntNotifyWinEvent(
118 DWORD event,
119 HWND hwnd,
120 LONG idObject,
121 LONG idChild,
122 DWORD flags
123 )
124 {
125 NOTIFYEVENT ne;
126 ne.event = event;
127 ne.idObject = idObject;
128 ne.idChild = idChild;
129 ne.flags = flags;
130 if (gpsi->dwInstalledEventHooks & GetMaskFromEvent(event))
131 NtUserCallHwndParam(hwnd, (DWORD)&ne, HWNDPARAM_ROUTINE_ROS_NOTIFYWINEVENT);
132 }
133
134 /* FUNCTIONS *****************************************************************/
135
136 #if 0
137 BOOL
138 WINAPI
139 CallMsgFilter(
140 LPMSG lpMsg,
141 int nCode)
142 {
143 UNIMPLEMENTED;
144 return FALSE;
145 }
146 #endif
147
148 /*
149 * @implemented
150 */
151 BOOL
152 WINAPI
153 CallMsgFilterA(
154 LPMSG lpMsg,
155 int nCode)
156 {
157 MSG Msg;
158 if (NtCurrentTeb()->Win32ThreadInfo && IsThreadHooked(GetWin32ClientInfo()))
159 {
160 if ( lpMsg->message & ~WM_MAXIMUM )
161 {
162 SetLastError(ERROR_INVALID_PARAMETER);
163 return FALSE;
164 }
165 RtlCopyMemory(&Msg, lpMsg, sizeof(MSG));
166 return NtUserCallMsgFilter( &Msg, nCode);
167 }
168 return FALSE;
169 }
170
171
172 /*
173 * @implemented
174 */
175 BOOL
176 WINAPI
177 CallMsgFilterW(
178 LPMSG lpMsg,
179 int nCode)
180 {
181 MSG Msg;
182 if (NtCurrentTeb()->Win32ThreadInfo && IsThreadHooked(GetWin32ClientInfo()))
183 {
184 if ( lpMsg->message & ~WM_MAXIMUM )
185 {
186 SetLastError(ERROR_INVALID_PARAMETER);
187 return FALSE;
188 }
189 RtlCopyMemory(&Msg, lpMsg, sizeof(MSG));
190 return NtUserCallMsgFilter( &Msg, nCode);
191 }
192 return FALSE;
193 }
194
195
196 /*
197 * @implemented
198 */
199 LRESULT
200 WINAPI
201 CallNextHookEx(
202 HHOOK Hook, // Windows NT/XP/2003: Ignored.
203 int Code,
204 WPARAM wParam,
205 LPARAM lParam)
206 {
207 PCLIENTINFO ClientInfo;
208 DWORD Flags, Save;
209 PHOOK pHook, phkNext;
210 LRESULT lResult = 0;
211
212 GetConnected();
213
214 ClientInfo = GetWin32ClientInfo();
215
216 if (!ClientInfo->phkCurrent) return 0;
217
218 pHook = DesktopPtrToUser(ClientInfo->phkCurrent);
219
220 if (!pHook->phkNext) return 0; // Nothing to do....
221
222 phkNext = DesktopPtrToUser(pHook->phkNext);
223
224 if ( phkNext->HookId == WH_CALLWNDPROC ||
225 phkNext->HookId == WH_CALLWNDPROCRET)
226 {
227 Save = ClientInfo->dwHookData;
228 Flags = ClientInfo->CI_flags & CI_CURTHPRHOOK;
229 // wParam: If the message was sent by the current thread/process, it is
230 // nonzero; otherwise, it is zero.
231 if (wParam) ClientInfo->CI_flags |= CI_CURTHPRHOOK;
232 else ClientInfo->CI_flags &= ~CI_CURTHPRHOOK;
233
234 if (phkNext->HookId == WH_CALLWNDPROC)
235 {
236 PCWPSTRUCT pCWP = (PCWPSTRUCT)lParam;
237
238 NtUserMessageCall( pCWP->hwnd,
239 pCWP->message,
240 pCWP->wParam,
241 pCWP->lParam,
242 (ULONG_PTR)&lResult,
243 FNID_CALLWNDPROC,
244 phkNext->Ansi);
245 }
246 else
247 {
248 PCWPRETSTRUCT pCWPR = (PCWPRETSTRUCT)lParam;
249
250 ClientInfo->dwHookData = pCWPR->lResult;
251
252 NtUserMessageCall( pCWPR->hwnd,
253 pCWPR->message,
254 pCWPR->wParam,
255 pCWPR->lParam,
256 (ULONG_PTR)&lResult,
257 FNID_CALLWNDPROCRET,
258 phkNext->Ansi);
259 }
260 ClientInfo->CI_flags ^= ((ClientInfo->CI_flags ^ Flags) & CI_CURTHPRHOOK);
261 ClientInfo->dwHookData = Save;
262 }
263 else
264 lResult = NtUserCallNextHookEx(Code, wParam, lParam, pHook->Ansi);
265
266 return lResult;
267 }
268
269
270 /*
271 * @implemented
272 */
273 HHOOK
274 WINAPI
275 SetWindowsHookW(int idHook, HOOKPROC lpfn)
276 {
277 DWORD ThreadId = PtrToUint(NtCurrentTeb()->ClientId.UniqueThread);
278 return IntSetWindowsHook(idHook, lpfn, NULL, ThreadId, FALSE);
279 // return NtUserSetWindowsHookAW(idHook, lpfn, FALSE);
280 }
281
282 /*
283 * @implemented
284 */
285 HHOOK
286 WINAPI
287 SetWindowsHookA(int idHook, HOOKPROC lpfn)
288 {
289 DWORD ThreadId = PtrToUint(NtCurrentTeb()->ClientId.UniqueThread);
290 return IntSetWindowsHook(idHook, lpfn, NULL, ThreadId, TRUE);
291 // return NtUserSetWindowsHookAW(idHook, lpfn, TRUE);
292 }
293
294 /*
295 * @unimplemented
296 */
297 BOOL
298 WINAPI
299 DeregisterShellHookWindow(HWND hWnd)
300 {
301 return NtUserCallHwnd(hWnd, HWND_ROUTINE_DEREGISTERSHELLHOOKWINDOW);
302 }
303
304 /*
305 * @unimplemented
306 */
307 BOOL
308 WINAPI
309 RegisterShellHookWindow(HWND hWnd)
310 {
311 return NtUserCallHwnd(hWnd, HWND_ROUTINE_REGISTERSHELLHOOKWINDOW);
312 }
313
314 /*
315 * @implemented
316 */
317 BOOL
318 WINAPI
319 UnhookWindowsHook ( int nCode, HOOKPROC pfnFilterProc )
320 {
321 return NtUserCallTwoParam(nCode, (DWORD_PTR)pfnFilterProc, TWOPARAM_ROUTINE_UNHOOKWINDOWSHOOK);
322 }
323
324 /*
325 * @implemented
326 */
327 VOID
328 WINAPI
329 NotifyWinEvent(
330 DWORD event,
331 HWND hwnd,
332 LONG idObject,
333 LONG idChild
334 )
335 {
336 // "Servers call NotifyWinEvent to announce the event to the system after the
337 // event has occurred; they must never notify the system of an event before
338 // the event has occurred." msdn on NotifyWinEvent.
339 if (gpsi->dwInstalledEventHooks & GetMaskFromEvent(event)) // Check to see.
340 NtUserNotifyWinEvent(event, hwnd, idObject, idChild);
341 }
342
343 /*
344 * @implemented
345 */
346 HWINEVENTHOOK
347 WINAPI
348 SetWinEventHook(
349 UINT eventMin,
350 UINT eventMax,
351 HMODULE hmodWinEventProc,
352 WINEVENTPROC pfnWinEventProc,
353 DWORD idProcess,
354 DWORD idThread,
355 UINT dwFlags
356 )
357 {
358 WCHAR ModuleName[MAX_PATH];
359 UNICODE_STRING USModuleName;
360
361 if ((hmodWinEventProc != NULL) && (dwFlags & WINEVENT_INCONTEXT))
362 {
363 if (0 == GetModuleFileNameW(hmodWinEventProc, ModuleName, MAX_PATH))
364 {
365 return NULL;
366 }
367 RtlInitUnicodeString(&USModuleName, ModuleName);
368 }
369 else
370 {
371 RtlInitUnicodeString(&USModuleName, NULL);
372 }
373
374 return NtUserSetWinEventHook(eventMin,
375 eventMax,
376 hmodWinEventProc,
377 &USModuleName,
378 pfnWinEventProc,
379 idProcess,
380 idThread,
381 dwFlags);
382 }
383
384 /*
385 * @implemented
386 */
387 BOOL
388 WINAPI
389 IsWinEventHookInstalled(
390 DWORD event)
391 {
392 if ((PTHREADINFO)NtCurrentTeb()->Win32ThreadInfo)
393 {
394 return (gpsi->dwInstalledEventHooks & GetMaskFromEvent(event)) != 0;
395 }
396 return FALSE;
397 }
398
399 /*
400 * @implemented
401 */
402 HHOOK
403 WINAPI
404 SetWindowsHookExA(
405 int idHook,
406 HOOKPROC lpfn,
407 HINSTANCE hMod,
408 DWORD dwThreadId)
409 {
410 return IntSetWindowsHook(idHook, lpfn, hMod, dwThreadId, TRUE);
411 }
412
413
414 /*
415 * @implemented
416 */
417 HHOOK
418 WINAPI
419 SetWindowsHookExW(
420 int idHook,
421 HOOKPROC lpfn,
422 HINSTANCE hMod,
423 DWORD dwThreadId)
424 {
425 return IntSetWindowsHook(idHook, lpfn, hMod, dwThreadId, FALSE);
426 }
427
428 NTSTATUS WINAPI
429 User32CallHookProcFromKernel(PVOID Arguments, ULONG ArgumentLength)
430 {
431 PHOOKPROC_CALLBACK_ARGUMENTS Common;
432 CREATESTRUCTW Csw;
433 CBT_CREATEWNDW CbtCreatewndw;
434 PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS CbtCreatewndExtra = NULL;
435 KBDLLHOOKSTRUCT KeyboardLlData, *pKeyboardLlData;
436 MSLLHOOKSTRUCT MouseLlData, *pMouseLlData;
437 MSG *pcMsg, *pMsg;
438 PMOUSEHOOKSTRUCT pMHook;
439 CWPSTRUCT CWP, *pCWP;
440 CWPRETSTRUCT CWPR, *pCWPR;
441 PRECTL prl;
442 LPCBTACTIVATESTRUCT pcbtas;
443 WPARAM wParam = 0;
444 LPARAM lParam = 0;
445 LRESULT Result = 0;
446 BOOL Hit = FALSE;
447
448 Common = (PHOOKPROC_CALLBACK_ARGUMENTS) Arguments;
449
450 switch(Common->HookId)
451 {
452 case WH_CBT:
453 {
454 //ERR("WH_CBT: Code %d\n", Common->Code);
455 switch(Common->Code)
456 {
457 case HCBT_CREATEWND:
458 CbtCreatewndExtra = (PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS)
459 ((PCHAR) Common + Common->lParam);
460 RtlCopyMemory(&Csw, &CbtCreatewndExtra->Cs, sizeof(CREATESTRUCTW));
461 CbtCreatewndw.lpcs = &Csw;
462 CbtCreatewndw.hwndInsertAfter = CbtCreatewndExtra->WndInsertAfter;
463 wParam = Common->wParam;
464 lParam = (LPARAM) &CbtCreatewndw;
465 //ERR("HCBT_CREATEWND: hWnd 0x%x Name 0x%x Class 0x%x\n", Common->wParam, Csw.lpszName, Csw.lpszClass);
466 break;
467 case HCBT_CLICKSKIPPED:
468 pMHook = (PMOUSEHOOKSTRUCT)((PCHAR) Common + Common->lParam);
469 lParam = (LPARAM) pMHook;
470 break;
471 case HCBT_MOVESIZE:
472 prl = (PRECTL)((PCHAR) Common + Common->lParam);
473 lParam = (LPARAM) prl;
474 break;
475 case HCBT_ACTIVATE:
476 pcbtas = (LPCBTACTIVATESTRUCT)((PCHAR) Common + Common->lParam);
477 lParam = (LPARAM) pcbtas;
478 break;
479 case HCBT_KEYSKIPPED: /* The rest SEH support */
480 case HCBT_MINMAX:
481 case HCBT_SETFOCUS:
482 case HCBT_SYSCOMMAND:
483 case HCBT_DESTROYWND:
484 case HCBT_QS:
485 wParam = Common->wParam;
486 lParam = Common->lParam;
487 break;
488 default:
489 ERR("HCBT_ not supported = %d\n", Common->Code);
490 return ZwCallbackReturn(NULL, 0, STATUS_NOT_SUPPORTED);
491 }
492
493 if (Common->Proc)
494 {
495 _SEH2_TRY
496 {
497 Result = Common->Proc(Common->Code, wParam, lParam);
498 }
499 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
500 {
501 Hit = TRUE;
502 }
503 _SEH2_END;
504 }
505 else
506 {
507 ERR("Null Proc! Common = 0x%x, Proc = 0x%x\n",Common,Common->Proc);
508 }
509 switch(Common->Code)
510 {
511 case HCBT_CREATEWND:
512 CbtCreatewndExtra->WndInsertAfter = CbtCreatewndw.hwndInsertAfter;
513 CbtCreatewndExtra->Cs.x = CbtCreatewndw.lpcs->x;
514 CbtCreatewndExtra->Cs.y = CbtCreatewndw.lpcs->y;
515 CbtCreatewndExtra->Cs.cx = CbtCreatewndw.lpcs->cx;
516 CbtCreatewndExtra->Cs.cy = CbtCreatewndw.lpcs->cy;
517 break;
518 }
519 break;
520 }
521 case WH_KEYBOARD_LL:
522 //ERR("WH_KEYBOARD_LL: Code %d, wParam %d\n",Common->Code,Common->wParam);
523 pKeyboardLlData = (PKBDLLHOOKSTRUCT)((PCHAR) Common + Common->lParam);
524 RtlCopyMemory(&KeyboardLlData, pKeyboardLlData, sizeof(KBDLLHOOKSTRUCT));
525 Result = Common->Proc(Common->Code, Common->wParam, (LPARAM) &KeyboardLlData);
526 break;
527 case WH_MOUSE_LL:
528 //ERR("WH_MOUSE_LL: Code %d, wParam %d\n",Common->Code,Common->wParam);
529 pMouseLlData = (PMSLLHOOKSTRUCT)((PCHAR) Common + Common->lParam);
530 RtlCopyMemory(&MouseLlData, pMouseLlData, sizeof(MSLLHOOKSTRUCT));
531 Result = Common->Proc(Common->Code, Common->wParam, (LPARAM) &MouseLlData);
532 break;
533 case WH_MOUSE: /* SEH support */
534 pMHook = (PMOUSEHOOKSTRUCT)((PCHAR) Common + Common->lParam);
535 _SEH2_TRY
536 {
537 Result = Common->Proc(Common->Code, Common->wParam, (LPARAM) pMHook);
538 }
539 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
540 {
541 Hit = TRUE;
542 }
543 _SEH2_END;
544 break;
545 case WH_CALLWNDPROC:
546 // ERR("WH_CALLWNDPROC: Code %d, wParam %d\n",Common->Code,Common->wParam);
547 pCWP = (PCWPSTRUCT)((PCHAR) Common + Common->lParam);
548 RtlCopyMemory(&CWP, pCWP, sizeof(CWPSTRUCT));
549 Result = Common->Proc(Common->Code, Common->wParam, (LPARAM) &CWP);
550 break;
551 case WH_CALLWNDPROCRET:
552 pCWPR = (PCWPRETSTRUCT)((PCHAR) Common + Common->lParam);
553 RtlCopyMemory(&CWPR, pCWPR, sizeof(CWPRETSTRUCT));
554 Result = Common->Proc(Common->Code, Common->wParam, (LPARAM) &CWPR);
555 break;
556 case WH_MSGFILTER: /* All SEH support */
557 case WH_SYSMSGFILTER:
558 case WH_GETMESSAGE:
559 pMsg = (PMSG)((PCHAR) Common + Common->lParam);
560 pcMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MSG));
561 RtlCopyMemory(pcMsg, pMsg, sizeof(MSG));
562 // ERR("pMsg %d pcMsg %d\n",pMsg->message, pcMsg->message);
563 _SEH2_TRY
564 {
565 Result = Common->Proc(Common->Code, Common->wParam, (LPARAM) pcMsg);
566 }
567 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
568 {
569 Hit = TRUE;
570 }
571 _SEH2_END;
572 if (!Hit && Common->HookId == WH_GETMESSAGE)
573 RtlCopyMemory(pMsg, pcMsg, sizeof(MSG));
574 HeapFree( GetProcessHeap(), 0, pcMsg );
575 break;
576 case WH_KEYBOARD:
577 case WH_SHELL:
578 Result = Common->Proc(Common->Code, Common->wParam, Common->lParam);
579 break;
580 case WH_FOREGROUNDIDLE: /* <-- SEH support */
581 _SEH2_TRY
582 {
583 Result = Common->Proc(Common->Code, Common->wParam, Common->lParam);
584 }
585 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
586 {
587 Hit = TRUE;
588 }
589 _SEH2_END;
590 break;
591 default:
592 return ZwCallbackReturn(NULL, 0, STATUS_NOT_SUPPORTED);
593 }
594 if (Hit)
595 {
596 ERR("Hook Exception! Id: %d, Code %d, Proc 0x%x\n",Common->HookId,Common->Code,Common->Proc);
597 }
598 return ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS);
599 }
600
601 NTSTATUS WINAPI
602 User32CallEventProcFromKernel(PVOID Arguments, ULONG ArgumentLength)
603 {
604 PEVENTPROC_CALLBACK_ARGUMENTS Common;
605
606 Common = (PEVENTPROC_CALLBACK_ARGUMENTS) Arguments;
607
608 Common->Proc(Common->hook,
609 Common->event,
610 Common->hwnd,
611 Common->idObject,
612 Common->idChild,
613 Common->dwEventThread,
614 Common->dwmsEventTime);
615
616 return ZwCallbackReturn(NULL, 0, STATUS_SUCCESS);
617 }
618
619
620