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