Sync with trunk (r49303)
[reactos.git] / 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 BOOL ret = FALSE;
158
159 if (nCode != HCBT_CREATEWND) ret = NtUserCallMsgFilter((LPMSG) lpMsg, nCode);
160 else
161 {
162 UNICODE_STRING usBuffer;
163 CBT_CREATEWNDA *cbtcwA = (CBT_CREATEWNDA *)lpMsg->lParam;
164 CBT_CREATEWNDW cbtcwW;
165 CREATESTRUCTW csW;
166 MSG Msg;
167
168 Msg.hwnd = lpMsg->hwnd;
169 Msg.message = lpMsg->message;
170 Msg.time = lpMsg->time;
171 Msg.pt = lpMsg->pt;
172 Msg.wParam = lpMsg->wParam;
173
174 cbtcwW.lpcs = &csW;
175 cbtcwW.hwndInsertAfter = cbtcwA->hwndInsertAfter;
176 csW = *(CREATESTRUCTW *)cbtcwA->lpcs;
177
178 if (HIWORD(cbtcwA->lpcs->lpszName))
179 {
180 RtlCreateUnicodeStringFromAsciiz(&usBuffer,cbtcwA->lpcs->lpszName);
181 csW.lpszName = usBuffer.Buffer;
182 }
183 if (HIWORD(cbtcwA->lpcs->lpszClass))
184 {
185 RtlCreateUnicodeStringFromAsciiz(&usBuffer,cbtcwA->lpcs->lpszClass);
186 csW.lpszClass = usBuffer.Buffer;
187 }
188 Msg.lParam =(LPARAM) &cbtcwW;
189
190 ret = NtUserCallMsgFilter((LPMSG)&Msg, nCode);
191
192 lpMsg->time = Msg.time;
193 lpMsg->pt = Msg.pt;
194
195 cbtcwA->hwndInsertAfter = cbtcwW.hwndInsertAfter;
196 if (HIWORD(csW.lpszName)) HeapFree( GetProcessHeap(), 0, (LPWSTR)csW.lpszName );
197 if (HIWORD(csW.lpszClass)) HeapFree( GetProcessHeap(), 0, (LPWSTR)csW.lpszClass );
198 }
199 return ret;
200 }
201
202
203 /*
204 * @implemented
205 */
206 BOOL
207 WINAPI
208 CallMsgFilterW(
209 LPMSG lpMsg,
210 int nCode)
211 {
212 return NtUserCallMsgFilter((LPMSG) lpMsg, nCode);
213 }
214
215
216 /*
217 * @implemented
218 */
219 LRESULT
220 WINAPI
221 CallNextHookEx(
222 HHOOK Hook, // Windows NT/XP/2003: Ignored.
223 int Code,
224 WPARAM wParam,
225 LPARAM lParam)
226 {
227 PCLIENTINFO ClientInfo;
228 DWORD Flags, Save;
229 PHOOK pHook, phkNext;
230 LRESULT lResult = 0;
231
232 GetConnected();
233
234 ClientInfo = GetWin32ClientInfo();
235
236 if (!ClientInfo->phkCurrent) return 0;
237
238 pHook = DesktopPtrToUser(ClientInfo->phkCurrent);
239
240 if (!pHook->phkNext) return 0; // Nothing to do....
241
242 phkNext = DesktopPtrToUser(pHook->phkNext);
243
244 if ( phkNext->HookId == WH_CALLWNDPROC ||
245 phkNext->HookId == WH_CALLWNDPROCRET)
246 {
247 Save = ClientInfo->dwHookData;
248 Flags = ClientInfo->CI_flags & CI_CURTHPRHOOK;
249 // wParam: If the message was sent by the current thread/process, it is
250 // nonzero; otherwise, it is zero.
251 if (wParam) ClientInfo->CI_flags |= CI_CURTHPRHOOK;
252 else ClientInfo->CI_flags &= ~CI_CURTHPRHOOK;
253
254 if (phkNext->HookId == WH_CALLWNDPROC)
255 {
256 PCWPSTRUCT pCWP = (PCWPSTRUCT)lParam;
257
258 NtUserMessageCall( pCWP->hwnd,
259 pCWP->message,
260 pCWP->wParam,
261 pCWP->lParam,
262 (ULONG_PTR)&lResult,
263 FNID_CALLWNDPROC,
264 phkNext->Ansi);
265 }
266 else
267 {
268 PCWPRETSTRUCT pCWPR = (PCWPRETSTRUCT)lParam;
269
270 ClientInfo->dwHookData = pCWPR->lResult;
271
272 NtUserMessageCall( pCWPR->hwnd,
273 pCWPR->message,
274 pCWPR->wParam,
275 pCWPR->lParam,
276 (ULONG_PTR)&lResult,
277 FNID_CALLWNDPROCRET,
278 phkNext->Ansi);
279 }
280 ClientInfo->CI_flags ^= ((ClientInfo->CI_flags ^ Flags) & CI_CURTHPRHOOK);
281 ClientInfo->dwHookData = Save;
282 }
283 else
284 lResult = NtUserCallNextHookEx(Code, wParam, lParam, pHook->Ansi);
285
286 return lResult;
287 }
288
289
290 /*
291 * @implemented
292 */
293 HHOOK
294 WINAPI
295 SetWindowsHookW(int idHook, HOOKPROC lpfn)
296 {
297 DWORD ThreadId = PtrToUint(NtCurrentTeb()->ClientId.UniqueThread);
298 return IntSetWindowsHook(idHook, lpfn, NULL, ThreadId, FALSE);
299 // return NtUserSetWindowsHookAW(idHook, lpfn, FALSE);
300 }
301
302 /*
303 * @implemented
304 */
305 HHOOK
306 WINAPI
307 SetWindowsHookA(int idHook, HOOKPROC lpfn)
308 {
309 DWORD ThreadId = PtrToUint(NtCurrentTeb()->ClientId.UniqueThread);
310 return IntSetWindowsHook(idHook, lpfn, NULL, ThreadId, TRUE);
311 // return NtUserSetWindowsHookAW(idHook, lpfn, TRUE);
312 }
313
314 /*
315 * @unimplemented
316 */
317 BOOL
318 WINAPI
319 DeregisterShellHookWindow(HWND hWnd)
320 {
321 return NtUserCallHwnd(hWnd, HWND_ROUTINE_DEREGISTERSHELLHOOKWINDOW);
322 }
323
324 /*
325 * @unimplemented
326 */
327 BOOL
328 WINAPI
329 RegisterShellHookWindow(HWND hWnd)
330 {
331 return NtUserCallHwnd(hWnd, HWND_ROUTINE_REGISTERSHELLHOOKWINDOW);
332 }
333
334 /*
335 * @implemented
336 */
337 BOOL
338 WINAPI
339 UnhookWindowsHook ( int nCode, HOOKPROC pfnFilterProc )
340 {
341 return NtUserCallTwoParam(nCode, (DWORD_PTR)pfnFilterProc, TWOPARAM_ROUTINE_UNHOOKWINDOWSHOOK);
342 }
343
344 /*
345 * @implemented
346 */
347 VOID
348 WINAPI
349 NotifyWinEvent(
350 DWORD event,
351 HWND hwnd,
352 LONG idObject,
353 LONG idChild
354 )
355 {
356 // "Servers call NotifyWinEvent to announce the event to the system after the
357 // event has occurred; they must never notify the system of an event before
358 // the event has occurred." msdn on NotifyWinEvent.
359 if (gpsi->dwInstalledEventHooks & GetMaskFromEvent(event)) // Check to see.
360 NtUserNotifyWinEvent(event, hwnd, idObject, idChild);
361 }
362
363 /*
364 * @implemented
365 */
366 HWINEVENTHOOK
367 WINAPI
368 SetWinEventHook(
369 UINT eventMin,
370 UINT eventMax,
371 HMODULE hmodWinEventProc,
372 WINEVENTPROC pfnWinEventProc,
373 DWORD idProcess,
374 DWORD idThread,
375 UINT dwFlags
376 )
377 {
378 WCHAR ModuleName[MAX_PATH];
379 UNICODE_STRING USModuleName;
380
381 if ((hmodWinEventProc != NULL) && (dwFlags & WINEVENT_INCONTEXT))
382 {
383 if (0 == GetModuleFileNameW(hmodWinEventProc, ModuleName, MAX_PATH))
384 {
385 return NULL;
386 }
387 RtlInitUnicodeString(&USModuleName, ModuleName);
388 }
389 else
390 {
391 RtlInitUnicodeString(&USModuleName, NULL);
392 }
393
394 return NtUserSetWinEventHook(eventMin,
395 eventMax,
396 hmodWinEventProc,
397 &USModuleName,
398 pfnWinEventProc,
399 idProcess,
400 idThread,
401 dwFlags);
402 }
403
404 /*
405 * @implemented
406 */
407 BOOL
408 WINAPI
409 IsWinEventHookInstalled(
410 DWORD event)
411 {
412 if ((PTHREADINFO)NtCurrentTeb()->Win32ThreadInfo)
413 {
414 return (gpsi->dwInstalledEventHooks & GetMaskFromEvent(event)) != 0;
415 }
416 return FALSE;
417 }
418
419 /*
420 * @implemented
421 */
422 HHOOK
423 WINAPI
424 SetWindowsHookExA(
425 int idHook,
426 HOOKPROC lpfn,
427 HINSTANCE hMod,
428 DWORD dwThreadId)
429 {
430 return IntSetWindowsHook(idHook, lpfn, hMod, dwThreadId, TRUE);
431 }
432
433
434 /*
435 * @implemented
436 */
437 HHOOK
438 WINAPI
439 SetWindowsHookExW(
440 int idHook,
441 HOOKPROC lpfn,
442 HINSTANCE hMod,
443 DWORD dwThreadId)
444 {
445 return IntSetWindowsHook(idHook, lpfn, hMod, dwThreadId, FALSE);
446 }
447
448 NTSTATUS WINAPI
449 User32CallHookProcFromKernel(PVOID Arguments, ULONG ArgumentLength)
450 {
451 PHOOKPROC_CALLBACK_ARGUMENTS Common;
452 CREATESTRUCTW Csw;
453 CBT_CREATEWNDW CbtCreatewndw;
454 PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS CbtCreatewndExtra = NULL;
455 KBDLLHOOKSTRUCT KeyboardLlData, *pKeyboardLlData;
456 MSLLHOOKSTRUCT MouseLlData, *pMouseLlData;
457 MSG Msg, *pMsg;
458 PMOUSEHOOKSTRUCT pMHook;
459 CWPSTRUCT CWP, *pCWP;
460 CWPRETSTRUCT CWPR, *pCWPR;
461 PRECTL prl;
462 LPCBTACTIVATESTRUCT pcbtas;
463 WPARAM wParam = 0;
464 LPARAM lParam = 0;
465 LRESULT Result = 0;
466 BOOL Hit = FALSE;
467
468 Common = (PHOOKPROC_CALLBACK_ARGUMENTS) Arguments;
469
470 switch(Common->HookId)
471 {
472 case WH_CBT:
473 {
474 switch(Common->Code)
475 {
476 case HCBT_CREATEWND:
477 CbtCreatewndExtra = (PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS)
478 ((PCHAR) Common + Common->lParam);
479 Csw = CbtCreatewndExtra->Cs;
480 Csw.lpszName = CbtCreatewndExtra->Cs.lpszName;
481 Csw.lpszClass = CbtCreatewndExtra->Cs.lpszClass;
482 wParam = Common->wParam;
483 CbtCreatewndw.lpcs = &Csw;
484 CbtCreatewndw.hwndInsertAfter = CbtCreatewndExtra->WndInsertAfter;
485 lParam = (LPARAM) &CbtCreatewndw;
486 break;
487 case HCBT_CLICKSKIPPED:
488 pMHook = (PMOUSEHOOKSTRUCT)((PCHAR) Common + Common->lParam);
489 lParam = (LPARAM) pMHook;
490 break;
491 case HCBT_MOVESIZE:
492 prl = (PRECTL)((PCHAR) Common + Common->lParam);
493 lParam = (LPARAM) prl;
494 break;
495 case HCBT_ACTIVATE:
496 pcbtas = (LPCBTACTIVATESTRUCT)((PCHAR) Common + Common->lParam);
497 lParam = (LPARAM) pcbtas;
498 break;
499 case HCBT_KEYSKIPPED: /* The rest SEH support */
500 case HCBT_MINMAX:
501 case HCBT_SETFOCUS:
502 case HCBT_SYSCOMMAND:
503 case HCBT_DESTROYWND:
504 case HCBT_QS:
505 wParam = Common->wParam;
506 lParam = Common->lParam;
507 break;
508 default:
509 ERR("HCBT_ not supported = %d\n", Common->Code);
510 return ZwCallbackReturn(NULL, 0, STATUS_NOT_SUPPORTED);
511 }
512
513 if (Common->Proc)
514 {
515 _SEH2_TRY
516 {
517 Result = Common->Proc(Common->Code, wParam, lParam);
518 }
519 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
520 {
521 Hit = TRUE;
522 }
523 _SEH2_END;
524 }
525 else
526 {
527 ERR("Common = 0x%x, Proc = 0x%x\n",Common,Common->Proc);
528 }
529 switch(Common->Code)
530 {
531 case HCBT_CREATEWND:
532 CbtCreatewndExtra->WndInsertAfter = CbtCreatewndw.hwndInsertAfter;
533 CbtCreatewndExtra->Cs.x = CbtCreatewndw.lpcs->x;
534 CbtCreatewndExtra->Cs.y = CbtCreatewndw.lpcs->y;
535 CbtCreatewndExtra->Cs.cx = CbtCreatewndw.lpcs->cx;
536 CbtCreatewndExtra->Cs.cy = CbtCreatewndw.lpcs->cy;
537 break;
538 }
539 break;
540 }
541 case WH_KEYBOARD_LL:
542 ERR("WH_KEYBOARD_LL: Code %d, wParam %d\n",Common->Code,Common->wParam);
543 pKeyboardLlData = (PKBDLLHOOKSTRUCT)((PCHAR) Common + Common->lParam);
544 RtlCopyMemory(&KeyboardLlData, pKeyboardLlData, sizeof(KBDLLHOOKSTRUCT));
545 Result = Common->Proc(Common->Code, Common->wParam, (LPARAM) &KeyboardLlData);
546 break;
547 case WH_MOUSE_LL:
548 pMouseLlData = (PMSLLHOOKSTRUCT)((PCHAR) Common + Common->lParam);
549 RtlCopyMemory(&MouseLlData, pMouseLlData, sizeof(MSLLHOOKSTRUCT));
550 Result = Common->Proc(Common->Code, Common->wParam, (LPARAM) &MouseLlData);
551 break;
552 case WH_MOUSE: /* SEH support */
553 pMHook = (PMOUSEHOOKSTRUCT)((PCHAR) Common + Common->lParam);
554 _SEH2_TRY
555 {
556 Result = Common->Proc(Common->Code, Common->wParam, (LPARAM) pMHook);
557 }
558 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
559 {
560 Hit = TRUE;
561 }
562 _SEH2_END;
563 break;
564 case WH_CALLWNDPROC:
565 ERR("WH_CALLWNDPROC: Code %d, wParam %d\n",Common->Code,Common->wParam);
566 pCWP = (PCWPSTRUCT)((PCHAR) Common + Common->lParam);
567 RtlCopyMemory(&CWP, pCWP, sizeof(CWPSTRUCT));
568 Result = Common->Proc(Common->Code, Common->wParam, (LPARAM) &CWP);
569 break;
570 case WH_CALLWNDPROCRET:
571 pCWPR = (PCWPRETSTRUCT)((PCHAR) Common + Common->lParam);
572 RtlCopyMemory(&CWPR, pCWPR, sizeof(CWPRETSTRUCT));
573 Result = Common->Proc(Common->Code, Common->wParam, (LPARAM) &CWPR);
574 break;
575 case WH_MSGFILTER: /* All SEH support */
576 ERR("WH_MSGFILTER: Code %d, wParam %d\n",Common->Code,Common->wParam);
577 case WH_SYSMSGFILTER:
578 case WH_GETMESSAGE:
579 pMsg = (PMSG)((PCHAR) Common + Common->lParam);
580 RtlCopyMemory(&Msg, pMsg, sizeof(MSG));
581 _SEH2_TRY
582 {
583 Result = Common->Proc(Common->Code, Common->wParam, (LPARAM) &Msg);
584 }
585 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
586 {
587 Hit = TRUE;
588 }
589 _SEH2_END;
590 if (!Hit && Common->HookId == WH_GETMESSAGE)
591 RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
592 break;
593 case WH_FOREGROUNDIDLE: /* <-- SEH support */
594 case WH_KEYBOARD:
595 case WH_SHELL:
596 _SEH2_TRY
597 {
598 Result = Common->Proc(Common->Code, Common->wParam, Common->lParam);
599 }
600 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
601 {
602 Hit = TRUE;
603 }
604 _SEH2_END;
605 break;
606 default:
607 return ZwCallbackReturn(NULL, 0, STATUS_NOT_SUPPORTED);
608 }
609 if (Hit)
610 {
611 ERR("Hook Exception! Id: %d, Code %d, Proc 0x%x\n",Common->HookId,Common->Code,Common->Proc);
612 }
613 return ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS);
614 }
615
616 NTSTATUS WINAPI
617 User32CallEventProcFromKernel(PVOID Arguments, ULONG ArgumentLength)
618 {
619 PEVENTPROC_CALLBACK_ARGUMENTS Common;
620
621 Common = (PEVENTPROC_CALLBACK_ARGUMENTS) Arguments;
622
623 Common->Proc(Common->hook,
624 Common->event,
625 Common->hwnd,
626 Common->idObject,
627 Common->idChild,
628 Common->dwEventThread,
629 Common->dwmsEventTime);
630
631 return ZwCallbackReturn(NULL, 0, STATUS_SUCCESS);
632 }
633
634
635