417dc3211b4c45e1d3bb3651a3f6d849eeff279a
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / hook.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Window hooks
5 * FILE: subsystem/win32/win32k/ntuser/hook.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISION HISTORY:
8 * 06-06-2001 CSH Created
9 * NOTE: Most of this code was adapted from Wine,
10 * Copyright (C) 2002 Alexandre Julliard
11 */
12
13 #include <w32k.h>
14
15 #define NDEBUG
16 #include <debug.h>
17
18 static PHOOKTABLE GlobalHooks;
19
20
21 /* PRIVATE FUNCTIONS *********************************************************/
22
23
24 /* create a new hook table */
25 static PHOOKTABLE
26 IntAllocHookTable(void)
27 {
28 PHOOKTABLE Table;
29 UINT i;
30
31 Table = ExAllocatePoolWithTag(PagedPool, sizeof(HOOKTABLE), TAG_HOOK);
32 if (NULL != Table)
33 {
34 for (i = 0; i < NB_HOOKS; i++)
35 {
36 InitializeListHead(&Table->Hooks[i]);
37 Table->Counts[i] = 0;
38 }
39 }
40
41 return Table;
42 }
43
44
45 PHOOK FASTCALL IntGetHookObject(HHOOK hHook)
46 {
47 PHOOK Hook;
48
49 if (!hHook)
50 {
51 SetLastWin32Error(ERROR_INVALID_HOOK_HANDLE);
52 return NULL;
53 }
54
55 Hook = (PHOOK)UserGetObject(gHandleTable, hHook, otHook);
56 if (!Hook)
57 {
58 SetLastWin32Error(ERROR_INVALID_HOOK_HANDLE);
59 return NULL;
60 }
61
62 ASSERT(USER_BODY_TO_HEADER(Hook)->RefCount >= 0);
63
64 USER_BODY_TO_HEADER(Hook)->RefCount++;
65
66 return Hook;
67 }
68
69
70
71 /* create a new hook and add it to the specified table */
72 static PHOOK
73 IntAddHook(PETHREAD Thread, int HookId, BOOLEAN Global, PWINSTATION_OBJECT WinStaObj)
74 {
75 PW32THREAD W32Thread;
76 PHOOK Hook;
77 PHOOKTABLE Table = Global ? GlobalHooks : MsqGetHooks(((PW32THREAD)Thread->Tcb.Win32Thread)->MessageQueue);
78 HANDLE Handle;
79
80 if (NULL == Table)
81 {
82 Table = IntAllocHookTable();
83 if (NULL == Table)
84 {
85 return NULL;
86 }
87 if (Global)
88 {
89 GlobalHooks = Table;
90 }
91 else
92 {
93 MsqSetHooks(((PW32THREAD)Thread->Tcb.Win32Thread)->MessageQueue, Table);
94 }
95 }
96
97 Hook = UserCreateObject(gHandleTable, &Handle, otHook, sizeof(HOOK));
98 if (NULL == Hook)
99 {
100 return NULL;
101 }
102
103 Hook->Self = Handle;
104 Hook->Thread = Thread;
105 Hook->HookId = HookId;
106
107 if (Thread)
108 {
109 W32Thread = ((PW32THREAD)Thread->Tcb.Win32Thread);
110 ASSERT(W32Thread != NULL);
111 W32Thread->Hooks |= HOOKID_TO_FLAG(HookId);
112 if (W32Thread->ThreadInfo != NULL)
113 W32Thread->ThreadInfo->Hooks = W32Thread->Hooks;
114 }
115
116 RtlInitUnicodeString(&Hook->ModuleName, NULL);
117
118 InsertHeadList(&Table->Hooks[HOOKID_TO_INDEX(HookId)], &Hook->Chain);
119
120 return Hook;
121 }
122
123 /* get the hook table that a given hook belongs to */
124 static PHOOKTABLE FASTCALL
125 IntGetTable(PHOOK Hook)
126 {
127 if (NULL == Hook->Thread || WH_KEYBOARD_LL == Hook->HookId ||
128 WH_MOUSE_LL == Hook->HookId)
129 {
130 return GlobalHooks;
131 }
132
133 return MsqGetHooks(((PW32THREAD)Hook->Thread->Tcb.Win32Thread)->MessageQueue);
134 }
135
136 /* get the first hook in the chain */
137 static PHOOK FASTCALL
138 IntGetFirstHook(PHOOKTABLE Table, int HookId)
139 {
140 PLIST_ENTRY Elem = Table->Hooks[HOOKID_TO_INDEX(HookId)].Flink;
141 return Elem == &Table->Hooks[HOOKID_TO_INDEX(HookId)]
142 ? NULL : CONTAINING_RECORD(Elem, HOOK, Chain);
143 }
144
145 /* find the first non-deleted hook in the chain */
146 static PHOOK FASTCALL
147 IntGetFirstValidHook(PHOOKTABLE Table, int HookId)
148 {
149 PHOOK Hook;
150 PLIST_ENTRY Elem;
151
152 Hook = IntGetFirstHook(Table, HookId);
153 while (NULL != Hook && NULL == Hook->Proc)
154 {
155 Elem = Hook->Chain.Flink;
156 Hook = (Elem == &Table->Hooks[HOOKID_TO_INDEX(HookId)]
157 ? NULL : CONTAINING_RECORD(Elem, HOOK, Chain));
158 }
159
160 return Hook;
161 }
162
163 /* find the next hook in the chain, skipping the deleted ones */
164 static PHOOK FASTCALL
165 IntGetNextHook(PHOOK Hook)
166 {
167 PHOOKTABLE Table = IntGetTable(Hook);
168 int HookId = Hook->HookId;
169 PLIST_ENTRY Elem;
170
171 Elem = Hook->Chain.Flink;
172 while (Elem != &Table->Hooks[HOOKID_TO_INDEX(HookId)])
173 {
174 Hook = CONTAINING_RECORD(Elem, HOOK, Chain);
175 if (NULL != Hook->Proc)
176 {
177 return Hook;
178 }
179 }
180
181 if (NULL != GlobalHooks && Table != GlobalHooks) /* now search through the global table */
182 {
183 return IntGetFirstValidHook(GlobalHooks, HookId);
184 }
185
186 return NULL;
187 }
188
189 /* free a hook, removing it from its chain */
190 static VOID FASTCALL
191 IntFreeHook(PHOOKTABLE Table, PHOOK Hook, PWINSTATION_OBJECT WinStaObj)
192 {
193 RemoveEntryList(&Hook->Chain);
194 RtlFreeUnicodeString(&Hook->ModuleName);
195
196 /* Dereference thread if required */
197 if (Hook->Flags & HOOK_THREAD_REFERENCED)
198 {
199 ObDereferenceObject(Hook->Thread);
200 }
201
202 /* Close handle */
203 UserDeleteObject(Hook->Self, otHook);
204 }
205
206 /* remove a hook, freeing it if the chain is not in use */
207 static VOID
208 IntRemoveHook(PHOOK Hook, PWINSTATION_OBJECT WinStaObj, BOOL TableAlreadyLocked)
209 {
210 PW32THREAD W32Thread;
211 PHOOKTABLE Table = IntGetTable(Hook);
212
213 ASSERT(NULL != Table);
214 if (NULL == Table)
215 {
216 return;
217 }
218
219 W32Thread = ((PW32THREAD)Hook->Thread->Tcb.Win32Thread);
220 ASSERT(W32Thread != NULL);
221 W32Thread->Hooks &= ~HOOKID_TO_FLAG(Hook->HookId);
222 if (W32Thread->ThreadInfo != NULL)
223 W32Thread->ThreadInfo->Hooks = W32Thread->Hooks;
224
225 if (0 != Table->Counts[HOOKID_TO_INDEX(Hook->HookId)])
226 {
227 Hook->Proc = NULL; /* chain is in use, just mark it and return */
228 }
229 else
230 {
231 IntFreeHook(Table, Hook, WinStaObj);
232 }
233 }
234
235 /* release a hook chain, removing deleted hooks if the use count drops to 0 */
236 static VOID FASTCALL
237 IntReleaseHookChain(PHOOKTABLE Table, int HookId, PWINSTATION_OBJECT WinStaObj)
238 {
239 PLIST_ENTRY Elem;
240 PHOOK HookObj;
241
242 if (NULL == Table)
243 {
244 return;
245 }
246
247 /* use count shouldn't already be 0 */
248 ASSERT(0 != Table->Counts[HOOKID_TO_INDEX(HookId)]);
249 if (0 == Table->Counts[HOOKID_TO_INDEX(HookId)])
250 {
251 return;
252 }
253 if (0 == --Table->Counts[HOOKID_TO_INDEX(HookId)])
254 {
255 Elem = Table->Hooks[HOOKID_TO_INDEX(HookId)].Flink;
256 while (Elem != &Table->Hooks[HOOKID_TO_INDEX(HookId)])
257 {
258 HookObj = CONTAINING_RECORD(Elem, HOOK, Chain);
259 Elem = Elem->Flink;
260 if (NULL == HookObj->Proc)
261 {
262 IntFreeHook(Table, HookObj, WinStaObj);
263 }
264 }
265 }
266 }
267
268 static LRESULT FASTCALL
269 IntCallLowLevelHook(INT HookId, INT Code, WPARAM wParam, LPARAM lParam, PHOOK Hook)
270 {
271 NTSTATUS Status;
272 ULONG_PTR uResult;
273
274 /* FIXME should get timeout from
275 * HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */
276 Status = co_MsqSendMessage(((PW32THREAD)Hook->Thread->Tcb.Win32Thread)->MessageQueue, (HWND)(INT_PTR) Code, HookId,
277 wParam, lParam, 5000, TRUE, TRUE, &uResult);
278
279 return NT_SUCCESS(Status) ? uResult : 0;
280 }
281
282 LRESULT FASTCALL
283 co_HOOK_CallHooks(INT HookId, INT Code, WPARAM wParam, LPARAM lParam)
284 {
285 PHOOK Hook;
286 PW32THREAD Win32Thread;
287 PHOOKTABLE Table;
288 LRESULT Result;
289 PWINSTATION_OBJECT WinStaObj;
290 NTSTATUS Status;
291
292 ASSERT(WH_MINHOOK <= HookId && HookId <= WH_MAXHOOK);
293
294 Win32Thread = PsGetCurrentThreadWin32Thread();
295 if (NULL == Win32Thread)
296 {
297 Table = NULL;
298 }
299 else
300 {
301 Table = MsqGetHooks(Win32Thread->MessageQueue);
302 }
303
304 if (NULL == Table || ! (Hook = IntGetFirstValidHook(Table, HookId)))
305 {
306 /* try global table */
307 Table = GlobalHooks;
308 if (NULL == Table || ! (Hook = IntGetFirstValidHook(Table, HookId)))
309 {
310 return 0; /* no hook set */
311 }
312 }
313
314 if (Hook->Thread != PsGetCurrentThread()
315 && (WH_KEYBOARD_LL == HookId || WH_MOUSE_LL == HookId))
316 {
317 DPRINT("Calling hook in owning thread\n");
318 return IntCallLowLevelHook(HookId, Code, wParam, lParam, Hook);
319 }
320
321 if ((Hook->Thread != PsGetCurrentThread()) && (Hook->Thread != NULL))
322 {
323 DPRINT1("Calling hooks in other threads not implemented yet");
324 return 0;
325 }
326
327 Table->Counts[HOOKID_TO_INDEX(HookId)]++;
328 if (Table != GlobalHooks && GlobalHooks != NULL)
329 {
330 GlobalHooks->Counts[HOOKID_TO_INDEX(HookId)]++;
331 }
332
333 Result = co_IntCallHookProc(HookId, Code, wParam, lParam, Hook->Proc,
334 Hook->Ansi, &Hook->ModuleName);
335
336 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
337 KernelMode,
338 0,
339 &WinStaObj);
340
341 if (! NT_SUCCESS(Status))
342 {
343 DPRINT1("Invalid window station????\n");
344 }
345 else
346 {
347 IntReleaseHookChain(MsqGetHooks(PsGetCurrentThreadWin32Thread()->MessageQueue), HookId, WinStaObj);
348 IntReleaseHookChain(GlobalHooks, HookId, WinStaObj);
349 ObDereferenceObject(WinStaObj);
350 }
351
352 return Result;
353 }
354
355 VOID FASTCALL
356 HOOK_DestroyThreadHooks(PETHREAD Thread)
357 {
358 int HookId;
359 PLIST_ENTRY Elem;
360 PHOOK HookObj;
361 PWINSTATION_OBJECT WinStaObj;
362 NTSTATUS Status;
363
364 if (NULL != GlobalHooks)
365 {
366 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
367 KernelMode,
368 0,
369 &WinStaObj);
370
371 if (! NT_SUCCESS(Status))
372 {
373 DPRINT1("Invalid window station????\n");
374 return;
375 }
376
377 for (HookId = WH_MINHOOK; HookId <= WH_MAXHOOK; HookId++)
378 {
379 /* only low-level keyboard/mouse global hooks can be owned by a thread */
380 switch(HookId)
381 {
382 case WH_KEYBOARD_LL:
383 case WH_MOUSE_LL:
384 Elem = GlobalHooks->Hooks[HOOKID_TO_INDEX(HookId)].Flink;
385 while (Elem != &GlobalHooks->Hooks[HOOKID_TO_INDEX(HookId)])
386 {
387 HookObj = CONTAINING_RECORD(Elem, HOOK, Chain);
388 Elem = Elem->Flink;
389 if (HookObj->Thread == Thread)
390 {
391 IntRemoveHook(HookObj, WinStaObj, TRUE);
392 }
393 }
394 break;
395 }
396 }
397 }
398 }
399
400 LRESULT
401 FASTCALL
402 IntCallDebugHook(
403 int Code,
404 WPARAM wParam,
405 LPARAM lParam)
406 {
407 LRESULT lResult = 0;
408 ULONG Size;
409 DEBUGHOOKINFO Debug;
410 PVOID HooklParam = NULL;
411 BOOL BadChk = FALSE;
412
413 if (lParam)
414 {
415 _SEH_TRY
416 {
417 ProbeForRead((PVOID)lParam,
418 sizeof(DEBUGHOOKINFO),
419 1);
420 RtlCopyMemory( &Debug,
421 (PVOID)lParam,
422 sizeof(DEBUGHOOKINFO));
423 }
424 _SEH_HANDLE
425 {
426 BadChk = TRUE;
427 }
428 _SEH_END;
429 if (BadChk)
430 {
431 DPRINT1("HOOK WH_DEBUG read from lParam ERROR!\n");
432 return lResult;
433 }
434 }
435 else
436 return lResult; // Need lParam!
437
438 switch (wParam)
439 {
440 case WH_CBT:
441 {
442 switch (Debug.code)
443 {
444 case HCBT_CLICKSKIPPED:
445 Size = sizeof(MOUSEHOOKSTRUCTEX);
446 break;
447 case HCBT_MOVESIZE:
448 Size = sizeof(RECT);
449 break;
450 case HCBT_ACTIVATE:
451 Size = sizeof(CBTACTIVATESTRUCT);
452 break;
453 case HCBT_CREATEWND: // Handle Ansi?
454 Size = sizeof(CBT_CREATEWND);
455 // What shall we do? Size += sizeof(CREATESTRUCTEX);
456 break;
457 default:
458 Size = sizeof(LPARAM);
459 }
460 }
461 break;
462
463 case WH_MOUSE_LL:
464 Size = sizeof(MSLLHOOKSTRUCT);
465 break;
466
467 case WH_KEYBOARD_LL:
468 Size = sizeof(KBDLLHOOKSTRUCT);
469 break;
470
471 case WH_MSGFILTER:
472 case WH_SYSMSGFILTER:
473 case WH_GETMESSAGE:
474 Size = sizeof(MSG);
475 break;
476
477 case WH_JOURNALPLAYBACK:
478 case WH_JOURNALRECORD:
479 Size = sizeof(EVENTMSG);
480 break;
481
482 case WH_FOREGROUNDIDLE:
483 case WH_KEYBOARD:
484 case WH_SHELL:
485 default:
486 Size = sizeof(LPARAM);
487 }
488
489 if (Size > sizeof(LPARAM))
490 HooklParam = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_HOOK);
491
492 if (HooklParam)
493 {
494 _SEH_TRY
495 {
496 ProbeForRead((PVOID)Debug.lParam,
497 Size,
498 1);
499 RtlCopyMemory( HooklParam,
500 (PVOID)Debug.lParam,
501 Size);
502 }
503 _SEH_HANDLE
504 {
505 BadChk = TRUE;
506 }
507 _SEH_END;
508 if (BadChk)
509 {
510 DPRINT1("HOOK WH_DEBUG read from Debug.lParam ERROR!\n");
511 ExFreePool(HooklParam);
512 return lResult;
513 }
514 }
515
516 if (HooklParam) Debug.lParam = (LPARAM)HooklParam;
517 lResult = co_HOOK_CallHooks(WH_DEBUG, Code, wParam, (LPARAM)&Debug);
518 if (HooklParam) ExFreePool(HooklParam);
519 return lResult;
520 }
521
522 LRESULT
523 FASTCALL
524 UserCallNextHookEx(
525 int HookId,
526 int Code,
527 WPARAM wParam,
528 LPARAM lParam,
529 BOOL Ansi)
530 {
531 LRESULT lResult = 0;
532 BOOL BadChk = FALSE;
533
534 // Handle this one first.
535 if ((HookId == WH_MOUSE) || (HookId == WH_CBT && Code == HCBT_CLICKSKIPPED))
536 {
537 MOUSEHOOKSTRUCTEX Mouse;
538 if (lParam)
539 {
540 _SEH_TRY
541 {
542 ProbeForRead((PVOID)lParam,
543 sizeof(MOUSEHOOKSTRUCTEX),
544 1);
545 RtlCopyMemory( &Mouse,
546 (PVOID)lParam,
547 sizeof(MOUSEHOOKSTRUCTEX));
548 }
549 _SEH_HANDLE
550 {
551 BadChk = TRUE;
552 }
553 _SEH_END;
554 if (BadChk)
555 {
556 DPRINT1("HOOK WH_MOUSE read from lParam ERROR!\n");
557 }
558 }
559 if (!BadChk)
560 {
561 lResult = co_HOOK_CallHooks(HookId, Code, wParam, (LPARAM)&Mouse);
562 }
563 return lResult;
564 }
565
566 switch(HookId)
567 {
568 case WH_MOUSE_LL:
569 {
570 MSLLHOOKSTRUCT Mouse;
571 if (lParam)
572 {
573 _SEH_TRY
574 {
575 ProbeForRead((PVOID)lParam,
576 sizeof(MSLLHOOKSTRUCT),
577 1);
578 RtlCopyMemory( &Mouse,
579 (PVOID)lParam,
580 sizeof(MSLLHOOKSTRUCT));
581 }
582 _SEH_HANDLE
583 {
584 BadChk = TRUE;
585 }
586 _SEH_END;
587 if (BadChk)
588 {
589 DPRINT1("HOOK WH_MOUSE_LL read from lParam ERROR!\n");
590 }
591 }
592 if (!BadChk)
593 {
594 lResult = co_HOOK_CallHooks(HookId, Code, wParam, (LPARAM)&Mouse);
595 }
596 break;
597 }
598
599 case WH_KEYBOARD_LL:
600 {
601 KBDLLHOOKSTRUCT Keyboard;
602 if (lParam)
603 {
604 _SEH_TRY
605 {
606 ProbeForRead((PVOID)lParam,
607 sizeof(KBDLLHOOKSTRUCT),
608 1);
609 RtlCopyMemory( &Keyboard,
610 (PVOID)lParam,
611 sizeof(KBDLLHOOKSTRUCT));
612 }
613 _SEH_HANDLE
614 {
615 BadChk = TRUE;
616 }
617 _SEH_END;
618 if (BadChk)
619 {
620 DPRINT1("HOOK WH_KEYBORD_LL read from lParam ERROR!\n");
621 }
622 }
623 if (!BadChk)
624 {
625 lResult = co_HOOK_CallHooks(HookId, Code, wParam, (LPARAM)&Keyboard);
626 }
627 break;
628 }
629
630 case WH_MSGFILTER:
631 case WH_SYSMSGFILTER:
632 case WH_GETMESSAGE:
633 {
634 MSG Msg;
635 if (lParam)
636 {
637 _SEH_TRY
638 {
639 ProbeForRead((PVOID)lParam,
640 sizeof(MSG),
641 1);
642 RtlCopyMemory( &Msg,
643 (PVOID)lParam,
644 sizeof(MSG));
645 }
646 _SEH_HANDLE
647 {
648 BadChk = TRUE;
649 }
650 _SEH_END;
651 if (BadChk)
652 {
653 DPRINT1("HOOK WH_XMESSAGEX read from lParam ERROR!\n");
654 }
655 }
656 if (!BadChk)
657 {
658 lResult = co_HOOK_CallHooks(HookId, Code, wParam, (LPARAM)&Msg);
659 if (lParam && (HookId == WH_GETMESSAGE))
660 {
661 _SEH_TRY
662 {
663 ProbeForWrite((PVOID)lParam,
664 sizeof(MSG),
665 1);
666 RtlCopyMemory((PVOID)lParam,
667 &Msg,
668 sizeof(MSG));
669 }
670 _SEH_HANDLE
671 {
672 BadChk = TRUE;
673 }
674 _SEH_END;
675 if (BadChk)
676 {
677 DPRINT1("HOOK WH_GETMESSAGE write to lParam ERROR!\n");
678 }
679 }
680 }
681 break;
682 }
683
684 case WH_CBT:
685 switch (Code)
686 {
687 case HCBT_CREATEWND: // Use Ansi.
688 lResult = co_HOOK_CallHooks(HookId, Code, wParam, lParam);
689 break;
690
691 case HCBT_MOVESIZE:
692 {
693 RECT rt;
694
695 if (lParam)
696 {
697 _SEH_TRY
698 {
699 ProbeForRead((PVOID)lParam,
700 sizeof(RECT),
701 1);
702 RtlCopyMemory( &rt,
703 (PVOID)lParam,
704 sizeof(RECT));
705 }
706 _SEH_HANDLE
707 {
708 BadChk = TRUE;
709 }
710 _SEH_END;
711 if (BadChk)
712 {
713 DPRINT1("HOOK HCBT_MOVESIZE read from lParam ERROR!\n");
714 }
715 }
716 if (!BadChk)
717 {
718 lResult = co_HOOK_CallHooks(HookId, Code, wParam, (LPARAM)&rt);
719 }
720 break;
721 }
722
723 case HCBT_ACTIVATE:
724 {
725 CBTACTIVATESTRUCT CbAs;
726
727 if (lParam)
728 {
729 _SEH_TRY
730 {
731 ProbeForRead((PVOID)lParam,
732 sizeof(CBTACTIVATESTRUCT),
733 1);
734 RtlCopyMemory( &CbAs,
735 (PVOID)lParam,
736 sizeof(CBTACTIVATESTRUCT));
737 }
738 _SEH_HANDLE
739 {
740 BadChk = TRUE;
741 }
742 _SEH_END;
743 if (BadChk)
744 {
745 DPRINT1("HOOK HCBT_ACTIVATE read from lParam ERROR!\n");
746 }
747 }
748 if (!BadChk)
749 {
750 lResult = co_HOOK_CallHooks(HookId, Code, wParam, (LPARAM)&CbAs);
751 }
752 break;
753 }
754 /*
755 The rest just use default.
756 */
757 default:
758 lResult = co_HOOK_CallHooks(HookId, Code, wParam, lParam);
759 break;
760 }
761 break;
762
763 case WH_JOURNALPLAYBACK:
764 case WH_JOURNALRECORD:
765 {
766 EVENTMSG EventMsg;
767 if (lParam)
768 {
769 _SEH_TRY
770 {
771 ProbeForRead((PVOID)lParam,
772 sizeof(EVENTMSG),
773 1);
774 RtlCopyMemory( &EventMsg,
775 (PVOID)lParam,
776 sizeof(EVENTMSG));
777 }
778 _SEH_HANDLE
779 {
780 BadChk = TRUE;
781 }
782 _SEH_END;
783 if (BadChk)
784 {
785 DPRINT1("HOOK WH_JOURNAL read from lParam ERROR!\n");
786 }
787 }
788 if (!BadChk)
789 {
790 lResult = co_HOOK_CallHooks(HookId, Code, wParam, (LPARAM)(lParam ? &EventMsg : NULL));
791 if (lParam)
792 {
793 _SEH_TRY
794 {
795 ProbeForWrite((PVOID)lParam,
796 sizeof(EVENTMSG),
797 1);
798 RtlCopyMemory((PVOID)lParam,
799 &EventMsg,
800 sizeof(EVENTMSG));
801 }
802 _SEH_HANDLE
803 {
804 BadChk = TRUE;
805 }
806 _SEH_END;
807 if (BadChk)
808 {
809 DPRINT1("HOOK WH_JOURNAL write to lParam ERROR!\n");
810 }
811 }
812 }
813 break;
814 }
815
816 case WH_DEBUG:
817 lResult = IntCallDebugHook( Code, wParam, lParam);
818 break;
819 /*
820 Default the rest like, WH_FOREGROUNDIDLE, WH_KEYBOARD and WH_SHELL.
821 */
822 case WH_FOREGROUNDIDLE:
823 case WH_KEYBOARD:
824 case WH_SHELL:
825 lResult = co_HOOK_CallHooks(HookId, Code, wParam, lParam);
826 break;
827
828 default:
829 DPRINT1("Unsupported HOOK Id -> %d\n",HookId);
830 break;
831 }
832 return lResult;
833 }
834
835 LRESULT
836 STDCALL
837 NtUserCallNextHookEx(
838 int Code,
839 WPARAM wParam,
840 LPARAM lParam,
841 BOOL Ansi)
842 {
843 PHOOK HookObj, NextObj;
844 PW32CLIENTINFO ClientInfo;
845 PWINSTATION_OBJECT WinStaObj;
846 NTSTATUS Status;
847 LRESULT lResult;
848 INT HookId;
849 DECLARE_RETURN(LRESULT);
850
851 DPRINT("Enter NtUserCallNextHookEx\n");
852 UserEnterExclusive();
853
854 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
855 KernelMode,
856 0,
857 &WinStaObj);
858
859 if (!NT_SUCCESS(Status))
860 {
861 SetLastNtError(Status);
862 RETURN( 0);
863 }
864
865 ObDereferenceObject(WinStaObj);
866
867 ClientInfo = GetWin32ClientInfo();
868
869 HookObj = ClientInfo->phkCurrent; // Use this one set from SetWindowHook.
870
871 HookId = HookObj->HookId;
872 Ansi = HookObj->Ansi;
873
874 if (NULL != HookObj->Thread && (HookObj->Thread != PsGetCurrentThread()))
875 {
876 DPRINT1("Thread mismatch\n");
877 UserDereferenceObject(HookObj);
878 SetLastWin32Error(ERROR_INVALID_HANDLE);
879 RETURN( 0);
880 }
881
882 NextObj = IntGetNextHook(HookObj);
883 UserDereferenceObject(HookObj);
884 if (NULL != NextObj)
885 {
886 lResult = UserCallNextHookEx( HookId, Code, wParam, lParam, Ansi);
887
888 ClientInfo->phkCurrent = NextObj;
889
890 if (lResult == 0) RETURN( 0);
891 RETURN( (LRESULT)NextObj);
892 }
893 ClientInfo->phkCurrent = NextObj;
894
895 RETURN( 0);
896
897 CLEANUP:
898 DPRINT("Leave NtUserCallNextHookEx, ret=%i\n",_ret_);
899 UserLeave();
900 END_CLEANUP;
901 }
902
903 HHOOK
904 STDCALL
905 NtUserSetWindowsHookAW(
906 int idHook,
907 HOOKPROC lpfn,
908 BOOL Ansi)
909 {
910 UNICODE_STRING USModuleName;
911 RtlInitUnicodeString(&USModuleName, NULL);
912 return NtUserSetWindowsHookEx(NULL, &USModuleName, 0, idHook, lpfn, Ansi);
913 }
914
915 HHOOK
916 STDCALL
917 NtUserSetWindowsHookEx(
918 HINSTANCE Mod,
919 PUNICODE_STRING UnsafeModuleName,
920 DWORD ThreadId,
921 int HookId,
922 HOOKPROC HookProc,
923 BOOL Ansi)
924 {
925 PWINSTATION_OBJECT WinStaObj;
926 PW32CLIENTINFO ClientInfo;
927 BOOLEAN Global;
928 PETHREAD Thread;
929 PHOOK Hook;
930 UNICODE_STRING ModuleName;
931 NTSTATUS Status;
932 HHOOK Handle;
933 DECLARE_RETURN(HHOOK);
934
935 DPRINT("Enter NtUserSetWindowsHookEx\n");
936 UserEnterExclusive();
937
938 if (HookId < WH_MINHOOK || WH_MAXHOOK < HookId || NULL == HookProc)
939 {
940 SetLastWin32Error(ERROR_INVALID_PARAMETER);
941 RETURN( NULL);
942 }
943
944 ClientInfo = GetWin32ClientInfo();
945
946 if (ThreadId) /* thread-local hook */
947 {
948 if (HookId == WH_JOURNALRECORD ||
949 HookId == WH_JOURNALPLAYBACK ||
950 HookId == WH_KEYBOARD_LL ||
951 HookId == WH_MOUSE_LL ||
952 HookId == WH_SYSMSGFILTER)
953 {
954 /* these can only be global */
955 SetLastWin32Error(ERROR_INVALID_PARAMETER);
956 RETURN( NULL);
957 }
958 Mod = NULL;
959 Global = FALSE;
960 if (! NT_SUCCESS(PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)ThreadId, &Thread)))
961 {
962 DPRINT1("Invalid thread id 0x%x\n", ThreadId);
963 SetLastWin32Error(ERROR_INVALID_PARAMETER);
964 RETURN( NULL);
965 }
966 if (Thread->ThreadsProcess != PsGetCurrentProcess())
967 {
968 ObDereferenceObject(Thread);
969 DPRINT1("Can't specify thread belonging to another process\n");
970 SetLastWin32Error(ERROR_INVALID_PARAMETER);
971 RETURN( NULL);
972 }
973 }
974 else /* system-global hook */
975 {
976 if (HookId == WH_KEYBOARD_LL || HookId == WH_MOUSE_LL)
977 {
978 Mod = NULL;
979 Thread = PsGetCurrentThread();
980 Status = ObReferenceObjectByPointer(Thread,
981 THREAD_ALL_ACCESS,
982 PsThreadType,
983 KernelMode);
984
985 if (! NT_SUCCESS(Status))
986 {
987 SetLastNtError(Status);
988 RETURN( (HANDLE) NULL);
989 }
990 }
991 else if (NULL == Mod)
992 {
993 SetLastWin32Error(ERROR_INVALID_PARAMETER);
994 RETURN( NULL);
995 }
996 else
997 {
998 Thread = NULL;
999 }
1000 Global = TRUE;
1001 }
1002
1003 /* We only (partially) support local WH_CBT hooks and
1004 * WH_KEYBOARD_LL, WH_MOUSE_LL and WH_GETMESSAGE hooks for now
1005 */
1006 if (WH_DEBUG == HookId ||
1007 WH_JOURNALPLAYBACK == HookId ||
1008 WH_JOURNALRECORD == HookId ||
1009 WH_FOREGROUNDIDLE == HookId ||
1010 WH_SHELL == HookId)
1011 {
1012 #if 0 /* Removed to get winEmbed working again */
1013 UNIMPLEMENTED
1014 #else
1015 DPRINT1("Not implemented: HookId %d Global %s\n", HookId, Global ? "TRUE" : "FALSE");
1016 #endif
1017
1018 if (NULL != Thread)
1019 {
1020 ObDereferenceObject(Thread);
1021 }
1022 SetLastWin32Error(ERROR_NOT_SUPPORTED);
1023 RETURN( NULL);
1024 }
1025
1026 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
1027 KernelMode,
1028 0,
1029 &WinStaObj);
1030
1031 if (! NT_SUCCESS(Status))
1032 {
1033 if (NULL != Thread)
1034 {
1035 ObDereferenceObject(Thread);
1036 }
1037 SetLastNtError(Status);
1038 RETURN( (HANDLE) NULL);
1039 }
1040
1041 Hook = IntAddHook(Thread, HookId, Global, WinStaObj);
1042 if (NULL == Hook)
1043 {
1044 if (NULL != Thread)
1045 {
1046 ObDereferenceObject(Thread);
1047 }
1048 ObDereferenceObject(WinStaObj);
1049 RETURN( NULL);
1050 }
1051
1052 if (NULL != Thread)
1053 {
1054 Hook->Flags |= HOOK_THREAD_REFERENCED;
1055 }
1056
1057 if (NULL != Mod)
1058 {
1059 Status = MmCopyFromCaller(&ModuleName, UnsafeModuleName, sizeof(UNICODE_STRING));
1060 if (! NT_SUCCESS(Status))
1061 {
1062 UserDereferenceObject(Hook);
1063 IntRemoveHook(Hook, WinStaObj, FALSE);
1064 if (NULL != Thread)
1065 {
1066 ObDereferenceObject(Thread);
1067 }
1068 ObDereferenceObject(WinStaObj);
1069 SetLastNtError(Status);
1070 RETURN( NULL);
1071 }
1072 Hook->ModuleName.Buffer = ExAllocatePoolWithTag(PagedPool,
1073 ModuleName.MaximumLength,
1074 TAG_HOOK);
1075 if (NULL == Hook->ModuleName.Buffer)
1076 {
1077 UserDereferenceObject(Hook);
1078 IntRemoveHook(Hook, WinStaObj, FALSE);
1079 if (NULL != Thread)
1080 {
1081 ObDereferenceObject(Thread);
1082 }
1083 ObDereferenceObject(WinStaObj);
1084 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1085 RETURN( NULL);
1086 }
1087 Hook->ModuleName.MaximumLength = ModuleName.MaximumLength;
1088 Status = MmCopyFromCaller(Hook->ModuleName.Buffer,
1089 ModuleName.Buffer,
1090 ModuleName.MaximumLength);
1091 if (! NT_SUCCESS(Status))
1092 {
1093 ExFreePool(Hook->ModuleName.Buffer);
1094 UserDereferenceObject(Hook);
1095 IntRemoveHook(Hook, WinStaObj, FALSE);
1096 if (NULL != Thread)
1097 {
1098 ObDereferenceObject(Thread);
1099 }
1100 ObDereferenceObject(WinStaObj);
1101 SetLastNtError(Status);
1102 RETURN( NULL);
1103 }
1104 Hook->ModuleName.Length = ModuleName.Length;
1105 }
1106
1107 Hook->Proc = HookProc;
1108 Hook->Ansi = Ansi;
1109 Handle = Hook->Self;
1110
1111 // Set the client threads next hook based on the hooks type.
1112 ClientInfo->phkCurrent = IntGetNextHook( Hook);
1113
1114 UserDereferenceObject(Hook);
1115 ObDereferenceObject(WinStaObj);
1116
1117 RETURN( Handle);
1118
1119 CLEANUP:
1120 DPRINT("Leave NtUserSetWindowsHookEx, ret=%i\n",_ret_);
1121 UserLeave();
1122 END_CLEANUP;
1123 }
1124
1125
1126 BOOL
1127 STDCALL
1128 NtUserUnhookWindowsHookEx(
1129 HHOOK Hook)
1130 {
1131 PWINSTATION_OBJECT WinStaObj;
1132 PHOOK HookObj;
1133 NTSTATUS Status;
1134 DECLARE_RETURN(BOOL);
1135
1136 DPRINT("Enter NtUserUnhookWindowsHookEx\n");
1137 UserEnterExclusive();
1138
1139 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
1140 KernelMode,
1141 0,
1142 &WinStaObj);
1143
1144 if (! NT_SUCCESS(Status))
1145 {
1146 SetLastNtError(Status);
1147 RETURN( FALSE);
1148 }
1149
1150 // Status = UserReferenceObjectByHandle(gHandleTable, Hook,
1151 // otHookProc, (PVOID *) &HookObj);
1152 if (!(HookObj = IntGetHookObject(Hook)))
1153 {
1154 DPRINT1("Invalid handle passed to NtUserUnhookWindowsHookEx\n");
1155 ObDereferenceObject(WinStaObj);
1156 // SetLastNtError(Status);
1157 RETURN( FALSE);
1158 }
1159 ASSERT(Hook == HookObj->Self);
1160
1161 IntRemoveHook(HookObj, WinStaObj, FALSE);
1162
1163 UserDereferenceObject(HookObj);
1164 ObDereferenceObject(WinStaObj);
1165
1166 RETURN( TRUE);
1167
1168 CLEANUP:
1169 DPRINT("Leave NtUserUnhookWindowsHookEx, ret=%i\n",_ret_);
1170 UserLeave();
1171 END_CLEANUP;
1172 }
1173
1174 /* EOF */