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)
8 * 06-06-2001 CSH Created
9 * NOTE: Most of this code was adapted from Wine,
10 * Copyright (C) 2002 Alexandre Julliard
18 static PHOOKTABLE GlobalHooks
;
21 /* PRIVATE FUNCTIONS *********************************************************/
24 /* create a new hook table */
27 IntAllocHookTable(void)
32 Table
= ExAllocatePoolWithTag(PagedPool
, sizeof(HOOKTABLE
), TAG_HOOK
);
35 for (i
= 0; i
< NB_HOOKS
; i
++)
37 InitializeListHead(&Table
->Hooks
[i
]);
48 IntGetHookObject(HHOOK hHook
)
54 SetLastWin32Error(ERROR_INVALID_HOOK_HANDLE
);
58 Hook
= (PHOOK
)UserGetObject(gHandleTable
, hHook
, otHook
);
61 SetLastWin32Error(ERROR_INVALID_HOOK_HANDLE
);
65 ASSERT(Hook
->head
.cLockObj
>= 0);
67 Hook
->head
.cLockObj
++;
74 /* create a new hook and add it to the specified table */
77 IntAddHook(PETHREAD Thread
, int HookId
, BOOLEAN Global
, PWINSTATION_OBJECT WinStaObj
)
79 PTHREADINFO W32Thread
;
81 PHOOKTABLE Table
= Global
? GlobalHooks
: MsqGetHooks(((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->MessageQueue
);
86 Table
= IntAllocHookTable();
97 MsqSetHooks(((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->MessageQueue
, Table
);
101 Hook
= UserCreateObject(gHandleTable
, NULL
, &Handle
, otHook
, sizeof(HOOK
));
107 Hook
->Thread
= Thread
;
108 Hook
->HookId
= HookId
;
112 W32Thread
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
);
113 ASSERT(W32Thread
!= NULL
);
114 W32Thread
->fsHooks
|= HOOKID_TO_FLAG(HookId
);
116 if (W32Thread
->pClientInfo
)
117 W32Thread
->pClientInfo
->fsHooks
= W32Thread
->fsHooks
;
119 if (W32Thread
->pDeskInfo
) // Do this for now.
120 W32Thread
->pDeskInfo
->fsHooks
= W32Thread
->fsHooks
;
122 Hook
->head
.pti
= W32Thread
;
123 Hook
->head
.rpdesk
= W32Thread
->rpdesk
;
126 RtlInitUnicodeString(&Hook
->ModuleName
, NULL
);
128 InsertHeadList(&Table
->Hooks
[HOOKID_TO_INDEX(HookId
)], &Hook
->Chain
);
133 /* get the hook table that a given hook belongs to */
137 IntGetTable(PHOOK Hook
)
139 if (NULL
== Hook
->Thread
|| WH_KEYBOARD_LL
== Hook
->HookId
||
140 WH_MOUSE_LL
== Hook
->HookId
)
145 return MsqGetHooks(((PTHREADINFO
)Hook
->Thread
->Tcb
.Win32Thread
)->MessageQueue
);
148 /* get the first hook in the chain */
152 IntGetFirstHook(PHOOKTABLE Table
, int HookId
)
154 PLIST_ENTRY Elem
= Table
->Hooks
[HOOKID_TO_INDEX(HookId
)].Flink
;
156 return Elem
== &Table
->Hooks
[HOOKID_TO_INDEX(HookId
)]
157 ? NULL
: CONTAINING_RECORD(Elem
, HOOK
, Chain
);
160 /* find the first non-deleted hook in the chain */
164 IntGetFirstValidHook(PHOOKTABLE Table
, int HookId
)
169 Hook
= IntGetFirstHook(Table
, HookId
);
171 while (NULL
!= Hook
&& NULL
== Hook
->Proc
)
173 Elem
= Hook
->Chain
.Flink
;
174 Hook
= (Elem
== &Table
->Hooks
[HOOKID_TO_INDEX(HookId
)]
175 ? NULL
: CONTAINING_RECORD(Elem
, HOOK
, Chain
));
181 /* find the next hook in the chain, skipping the deleted ones */
184 IntGetNextHook(PHOOK Hook
)
186 PHOOKTABLE Table
= IntGetTable(Hook
);
187 int HookId
= Hook
->HookId
;
190 Elem
= Hook
->Chain
.Flink
;
191 while (Elem
!= &Table
->Hooks
[HOOKID_TO_INDEX(HookId
)])
193 Hook
= CONTAINING_RECORD(Elem
, HOOK
, Chain
);
194 if (NULL
!= Hook
->Proc
)
200 if (NULL
!= GlobalHooks
&& Table
!= GlobalHooks
) /* now search through the global table */
202 return IntGetFirstValidHook(GlobalHooks
, HookId
);
208 /* free a hook, removing it from its chain */
212 IntFreeHook(PHOOKTABLE Table
, PHOOK Hook
, PWINSTATION_OBJECT WinStaObj
)
214 RemoveEntryList(&Hook
->Chain
);
215 RtlFreeUnicodeString(&Hook
->ModuleName
);
217 /* Dereference thread if required */
218 if (Hook
->Flags
& HOOK_THREAD_REFERENCED
)
220 ObDereferenceObject(Hook
->Thread
);
224 UserDeleteObject(UserHMGetHandle(Hook
), otHook
);
227 /* remove a hook, freeing it if the chain is not in use */
230 IntRemoveHook(PHOOK Hook
, PWINSTATION_OBJECT WinStaObj
, BOOL TableAlreadyLocked
)
232 PTHREADINFO W32Thread
;
233 PHOOKTABLE Table
= IntGetTable(Hook
);
235 ASSERT(NULL
!= Table
); // At this point this should not be null!
237 W32Thread
= ((PTHREADINFO
)Hook
->Thread
->Tcb
.Win32Thread
);
238 ASSERT(W32Thread
!= NULL
);
239 W32Thread
->fsHooks
&= ~HOOKID_TO_FLAG(Hook
->HookId
);
241 GetWin32ClientInfo()->fsHooks
= W32Thread
->fsHooks
;
243 if (W32Thread
->pDeskInfo
) // Do this for now.
244 W32Thread
->pDeskInfo
->fsHooks
= W32Thread
->fsHooks
;
246 if (0 != Table
->Counts
[HOOKID_TO_INDEX(Hook
->HookId
)])
248 Hook
->Proc
= NULL
; /* chain is in use, just mark it and return */
252 IntFreeHook(Table
, Hook
, WinStaObj
);
256 /* release a hook chain, removing deleted hooks if the use count drops to 0 */
260 IntReleaseHookChain(PHOOKTABLE Table
, int HookId
, PWINSTATION_OBJECT WinStaObj
)
270 /* use count shouldn't already be 0 */
271 ASSERT(0 != Table
->Counts
[HOOKID_TO_INDEX(HookId
)]);
273 if (0 == Table
->Counts
[HOOKID_TO_INDEX(HookId
)])
278 if (0 == --Table
->Counts
[HOOKID_TO_INDEX(HookId
)])
280 Elem
= Table
->Hooks
[HOOKID_TO_INDEX(HookId
)].Flink
;
282 while (Elem
!= &Table
->Hooks
[HOOKID_TO_INDEX(HookId
)])
284 HookObj
= CONTAINING_RECORD(Elem
, HOOK
, Chain
);
287 if (NULL
== HookObj
->Proc
)
289 IntFreeHook(Table
, HookObj
, WinStaObj
);
298 IntCallLowLevelHook(PHOOK Hook
, INT Code
, WPARAM wParam
, LPARAM lParam
)
303 /* FIXME should get timeout from
304 * HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */
305 Status
= co_MsqSendMessage(((PTHREADINFO
)Hook
->Thread
->Tcb
.Win32Thread
)->MessageQueue
,
315 return NT_SUCCESS(Status
) ? uResult
: 0;
319 Called from inside kernel space.
323 co_HOOK_CallHooks(INT HookId
, INT Code
, WPARAM wParam
, LPARAM lParam
)
325 PHOOK Hook
, SaveHook
;
327 PCLIENTINFO ClientInfo
;
330 PWINSTATION_OBJECT WinStaObj
;
333 ASSERT(WH_MINHOOK
<= HookId
&& HookId
<= WH_MAXHOOK
);
335 pti
= PsGetCurrentThreadWin32Thread();
342 Table
= MsqGetHooks(pti
->MessageQueue
);
345 if (NULL
== Table
|| ! (Hook
= IntGetFirstValidHook(Table
, HookId
)))
347 /* try global table */
349 if (NULL
== Table
|| ! (Hook
= IntGetFirstValidHook(Table
, HookId
)))
351 return 0; /* no hook set */
355 if ((Hook
->Thread
!= PsGetCurrentThread()) && (Hook
->Thread
!= NULL
))
357 DPRINT1("\nHook found by Id and posted to Thread! %d\n",HookId
);
358 /* Post it in message queue. */
359 return IntCallLowLevelHook(Hook
, Code
, wParam
, lParam
);
362 Table
->Counts
[HOOKID_TO_INDEX(HookId
)]++;
363 if (Table
!= GlobalHooks
&& GlobalHooks
!= NULL
)
365 GlobalHooks
->Counts
[HOOKID_TO_INDEX(HookId
)]++;
368 ClientInfo
= GetWin32ClientInfo();
369 SaveHook
= ClientInfo
->phkCurrent
;
370 ClientInfo
->phkCurrent
= Hook
; /* Load the call. */
372 Result
= co_IntCallHookProc(HookId
,
380 ClientInfo
->phkCurrent
= SaveHook
;
382 Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
387 if (!NT_SUCCESS(Status
))
389 DPRINT1("Invalid window station????\n");
393 IntReleaseHookChain(MsqGetHooks(pti
->MessageQueue
), HookId
, WinStaObj
);
394 IntReleaseHookChain(GlobalHooks
, HookId
, WinStaObj
);
395 ObDereferenceObject(WinStaObj
);
403 HOOK_DestroyThreadHooks(PETHREAD Thread
)
408 PWINSTATION_OBJECT WinStaObj
;
411 if (NULL
!= GlobalHooks
)
413 Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
418 if (!NT_SUCCESS(Status
))
420 DPRINT1("Invalid window station????\n");
424 for (HookId
= WH_MINHOOK
; HookId
<= WH_MAXHOOK
; HookId
++)
426 /* only low-level keyboard/mouse global hooks can be owned by a thread */
431 Elem
= GlobalHooks
->Hooks
[HOOKID_TO_INDEX(HookId
)].Flink
;
433 while (Elem
!= &GlobalHooks
->Hooks
[HOOKID_TO_INDEX(HookId
)])
435 HookObj
= CONTAINING_RECORD(Elem
, HOOK
, Chain
);
438 if (HookObj
->Thread
== Thread
)
440 IntRemoveHook(HookObj
, WinStaObj
, TRUE
);
452 co_HOOK_CallHookNext(PHOOK Hook
, INT Code
, WPARAM wParam
, LPARAM lParam
)
454 if ((Hook
->Thread
!= PsGetCurrentThread()) && (Hook
->Thread
!= NULL
))
456 DPRINT1("CALLING HOOK from another Thread. %d\n", Hook
->HookId
);
457 return IntCallLowLevelHook(Hook
, Code
, wParam
, lParam
);
460 DPRINT("CALLING HOOK %d\n", Hook
->HookId
);
462 return co_IntCallHookProc(Hook
->HookId
,
474 IntCallDebugHook(PHOOK Hook
,
482 PVOID HooklParam
= NULL
;
489 ProbeForRead((PVOID
)lParam
,
490 sizeof(DEBUGHOOKINFO
),
493 RtlCopyMemory(&Debug
,
495 sizeof(DEBUGHOOKINFO
));
497 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
505 DPRINT1("HOOK WH_DEBUG read from lParam ERROR!\n");
510 return lResult
; /* Need lParam! */
518 case HCBT_CLICKSKIPPED
:
519 Size
= sizeof(MOUSEHOOKSTRUCTEX
);
527 Size
= sizeof(CBTACTIVATESTRUCT
);
530 case HCBT_CREATEWND
: /* Handle Ansi? */
531 Size
= sizeof(CBT_CREATEWND
);
532 /* What shall we do? Size += sizeof(HOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS); same as CREATESTRUCTEX */
536 Size
= sizeof(LPARAM
);
542 Size
= sizeof(MSLLHOOKSTRUCT
);
546 Size
= sizeof(KBDLLHOOKSTRUCT
);
550 case WH_SYSMSGFILTER
:
555 case WH_JOURNALPLAYBACK
:
556 case WH_JOURNALRECORD
:
557 Size
= sizeof(EVENTMSG
);
560 case WH_FOREGROUNDIDLE
:
564 Size
= sizeof(LPARAM
);
567 if (Size
> sizeof(LPARAM
))
568 HooklParam
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_HOOK
);
574 ProbeForRead((PVOID
)Debug
.lParam
,
578 RtlCopyMemory(HooklParam
,
582 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
590 DPRINT1("HOOK WH_DEBUG read from Debug.lParam ERROR!\n");
591 ExFreePool(HooklParam
);
596 if (HooklParam
) Debug
.lParam
= (LPARAM
)HooklParam
;
597 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Debug
);
598 if (HooklParam
) ExFreePoolWithTag(HooklParam
, TAG_HOOK
);
604 Called from user space via CallNextHook.
608 UserCallNextHookEx(PHOOK Hook
,
617 /* Handle this one first. */
618 if ((Hook
->HookId
== WH_MOUSE
) ||
619 (Hook
->HookId
== WH_CBT
&& Code
== HCBT_CLICKSKIPPED
))
621 MOUSEHOOKSTRUCTEX Mouse
;
626 ProbeForRead((PVOID
)lParam
,
627 sizeof(MOUSEHOOKSTRUCTEX
),
630 RtlCopyMemory(&Mouse
,
632 sizeof(MOUSEHOOKSTRUCTEX
));
634 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
642 DPRINT1("HOOK WH_MOUSE read from lParam ERROR!\n");
648 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Mouse
);
658 MSLLHOOKSTRUCT Mouse
;
664 ProbeForRead((PVOID
)lParam
,
665 sizeof(MSLLHOOKSTRUCT
),
668 RtlCopyMemory(&Mouse
,
670 sizeof(MSLLHOOKSTRUCT
));
672 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
680 DPRINT1("HOOK WH_MOUSE_LL read from lParam ERROR!\n");
686 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Mouse
);
693 KBDLLHOOKSTRUCT Keyboard
;
699 ProbeForRead((PVOID
)lParam
,
700 sizeof(KBDLLHOOKSTRUCT
),
703 RtlCopyMemory(&Keyboard
,
705 sizeof(KBDLLHOOKSTRUCT
));
707 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
715 DPRINT1("HOOK WH_KEYBORD_LL read from lParam ERROR!\n");
721 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Keyboard
);
727 case WH_SYSMSGFILTER
:
736 ProbeForRead((PVOID
)lParam
,
744 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
752 DPRINT1("HOOK WH_XMESSAGEX read from lParam ERROR!\n");
758 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Msg
);
760 if (lParam
&& (Hook
->HookId
== WH_GETMESSAGE
))
764 ProbeForWrite((PVOID
)lParam
,
768 RtlCopyMemory((PVOID
)lParam
,
772 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
780 DPRINT1("HOOK WH_GETMESSAGE write to lParam ERROR!\n");
788 DPRINT("HOOK WH_CBT!\n");
793 LPCBT_CREATEWNDW pcbtcww
= (LPCBT_CREATEWNDW
)lParam
;
795 DPRINT("HOOK HCBT_CREATEWND\n");
800 ProbeForRead( pcbtcww
,
801 sizeof(CBT_CREATEWNDA
),
803 ProbeForWrite(pcbtcww
->lpcs
,
804 sizeof(CREATESTRUCTA
),
806 ProbeForRead( pcbtcww
->lpcs
->lpszName
,
810 if (!IS_ATOM(pcbtcww
->lpcs
->lpszClass
))
812 ProbeForRead( pcbtcww
->lpcs
->lpszClass
,
819 ProbeForRead( pcbtcww
,
820 sizeof(CBT_CREATEWNDW
),
822 ProbeForWrite(pcbtcww
->lpcs
,
823 sizeof(CREATESTRUCTW
),
825 ProbeForRead( pcbtcww
->lpcs
->lpszName
,
829 if (!IS_ATOM(pcbtcww
->lpcs
->lpszClass
))
831 ProbeForRead( pcbtcww
->lpcs
->lpszClass
,
837 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
845 DPRINT1("HOOK HCBT_CREATEWND write ERROR!\n");
847 /* The next call handles the structures. */
848 if (!BadChk
&& Hook
->Proc
)
850 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, lParam
);
859 DPRINT("HOOK HCBT_MOVESIZE\n");
865 ProbeForRead((PVOID
)lParam
,
873 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
881 DPRINT1("HOOK HCBT_MOVESIZE read from lParam ERROR!\n");
887 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&rt
);
894 CBTACTIVATESTRUCT CbAs
;
896 DPRINT("HOOK HCBT_ACTIVATE\n");
901 ProbeForRead((PVOID
)lParam
,
902 sizeof(CBTACTIVATESTRUCT
),
907 sizeof(CBTACTIVATESTRUCT
));
909 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
917 DPRINT1("HOOK HCBT_ACTIVATE read from lParam ERROR!\n");
923 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&CbAs
);
928 /* The rest just use default. */
930 DPRINT("HOOK HCBT_ %d\n",Code
);
931 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, lParam
);
936 case WH_JOURNALPLAYBACK
:
937 case WH_JOURNALRECORD
:
945 ProbeForRead((PVOID
)lParam
,
949 RtlCopyMemory(&EventMsg
,
953 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
961 DPRINT1("HOOK WH_JOURNAL read from lParam ERROR!\n");
967 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)(lParam
? &EventMsg
: NULL
));
973 ProbeForWrite((PVOID
)lParam
,
977 RtlCopyMemory((PVOID
)lParam
,
981 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
989 DPRINT1("HOOK WH_JOURNAL write to lParam ERROR!\n");
997 lResult
= IntCallDebugHook(Hook
, Code
, wParam
, lParam
);
1001 * Default the rest like, WH_FOREGROUNDIDLE, WH_KEYBOARD and WH_SHELL.
1003 case WH_FOREGROUNDIDLE
:
1006 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, lParam
);
1010 DPRINT1("Unsupported HOOK Id -> %d\n",Hook
->HookId
);
1019 NtUserCallNextHookEx(int Code
,
1024 PHOOK HookObj
, NextObj
;
1025 PCLIENTINFO ClientInfo
;
1026 PWINSTATION_OBJECT WinStaObj
;
1028 DECLARE_RETURN(LRESULT
);
1030 DPRINT("Enter NtUserCallNextHookEx\n");
1031 UserEnterExclusive();
1033 Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
1037 if (!NT_SUCCESS(Status
))
1039 SetLastNtError(Status
);
1043 ObDereferenceObject(WinStaObj
);
1045 ClientInfo
= GetWin32ClientInfo();
1047 if (!ClientInfo
) RETURN( 0);
1049 HookObj
= ClientInfo
->phkCurrent
;
1051 if (!HookObj
) RETURN( 0);
1053 /* Check that the first hook in the chain is not this hook */
1054 NextObj
= IntGetFirstHook(IntGetTable(HookObj
), HookObj
->HookId
);
1056 /* Its the same so it has already been called */
1057 if (HookObj
== NextObj
) RETURN(0);
1059 UserReferenceObject(HookObj
);
1061 Ansi
= HookObj
->Ansi
;
1063 if (NULL
!= HookObj
->Thread
&& (HookObj
->Thread
!= PsGetCurrentThread()))
1065 DPRINT1("Thread mismatch\n");
1066 UserDereferenceObject(HookObj
);
1067 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1071 NextObj
= IntGetNextHook(HookObj
);
1072 ClientInfo
->phkCurrent
= NextObj
; /* Preset next hook from list. */
1073 UserCallNextHookEx( HookObj
, Code
, wParam
, lParam
, Ansi
);
1074 UserDereferenceObject(HookObj
);
1076 RETURN( (LRESULT
)NextObj
);
1079 DPRINT("Leave NtUserCallNextHookEx, ret=%i\n",_ret_
);
1086 NtUserSetWindowsHookAW(int idHook
,
1090 UNICODE_STRING USModuleName
;
1092 RtlInitUnicodeString(&USModuleName
, NULL
);
1094 return NtUserSetWindowsHookEx(NULL
, &USModuleName
, 0, idHook
, lpfn
, Ansi
);
1099 NtUserSetWindowsHookEx(HINSTANCE Mod
,
1100 PUNICODE_STRING UnsafeModuleName
,
1106 PWINSTATION_OBJECT WinStaObj
;
1107 PCLIENTINFO ClientInfo
;
1111 UNICODE_STRING ModuleName
;
1114 BOOLEAN ThreadReferenced
= FALSE
;
1115 DECLARE_RETURN(HHOOK
);
1117 DPRINT("Enter NtUserSetWindowsHookEx\n");
1118 UserEnterExclusive();
1120 if (HookId
< WH_MINHOOK
|| WH_MAXHOOK
< HookId
)
1122 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1128 SetLastWin32Error(ERROR_INVALID_FILTER_PROC
);
1132 ClientInfo
= GetWin32ClientInfo();
1134 if (ThreadId
) /* thread-local hook */
1136 if (HookId
== WH_JOURNALRECORD
||
1137 HookId
== WH_JOURNALPLAYBACK
||
1138 HookId
== WH_KEYBOARD_LL
||
1139 HookId
== WH_MOUSE_LL
||
1140 HookId
== WH_SYSMSGFILTER
)
1142 /* these can only be global */
1143 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1150 if (!NT_SUCCESS(PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
) ThreadId
, &Thread
)))
1152 DPRINT1("Invalid thread id 0x%x\n", ThreadId
);
1153 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1157 /* Thread was referenced */
1158 ThreadReferenced
= TRUE
;
1159 if (Thread
->ThreadsProcess
!= PsGetCurrentProcess())
1161 ObDereferenceObject(Thread
);
1162 DPRINT1("Can't specify thread belonging to another process\n");
1163 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1167 else /* system-global hook */
1169 if (HookId
== WH_KEYBOARD_LL
|| HookId
== WH_MOUSE_LL
)
1172 Thread
= PsGetCurrentThread();
1174 Status
= ObReferenceObjectByPointer(Thread
,
1179 if (!NT_SUCCESS(Status
))
1181 SetLastNtError(Status
);
1182 RETURN( (HANDLE
) NULL
);
1185 /* Thread was referenced */
1186 ThreadReferenced
= TRUE
;
1188 else if (NULL
== Mod
)
1190 SetLastWin32Error(ERROR_HOOK_NEEDS_HMOD
);
1200 if ((Global
&& (HookId
!= WH_KEYBOARD_LL
&& HookId
!= WH_MOUSE_LL
)) ||
1201 WH_DEBUG
== HookId
||
1202 WH_JOURNALPLAYBACK
== HookId
||
1203 WH_JOURNALRECORD
== HookId
)
1205 #if 0 /* Removed to get winEmbed working again */
1208 DPRINT1("Not implemented: HookId %d Global %s\n", HookId
, Global
? "TRUE" : "FALSE");
1211 /* Dereference thread if needed */
1212 if (ThreadReferenced
) ObDereferenceObject(Thread
);
1213 SetLastWin32Error(ERROR_NOT_SUPPORTED
);
1217 Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
1222 if (!NT_SUCCESS(Status
))
1224 /* Dereference thread if needed */
1225 if (ThreadReferenced
) ObDereferenceObject(Thread
);
1226 SetLastNtError(Status
);
1227 RETURN( (HANDLE
) NULL
);
1230 Hook
= IntAddHook(Thread
, HookId
, Global
, WinStaObj
);
1233 /* Dereference thread if needed */
1234 if (ThreadReferenced
) ObDereferenceObject(Thread
);
1235 ObDereferenceObject(WinStaObj
);
1239 /* Let IntFreeHook now that this thread needs a dereference */
1240 if (ThreadReferenced
)
1242 Hook
->Flags
|= HOOK_THREAD_REFERENCED
;
1247 Status
= MmCopyFromCaller(&ModuleName
, UnsafeModuleName
, sizeof(UNICODE_STRING
));
1248 if (!NT_SUCCESS(Status
))
1250 UserDereferenceObject(Hook
);
1251 IntRemoveHook(Hook
, WinStaObj
, FALSE
);
1252 ObDereferenceObject(WinStaObj
);
1253 SetLastNtError(Status
);
1257 Hook
->ModuleName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1258 ModuleName
.MaximumLength
,
1260 if (NULL
== Hook
->ModuleName
.Buffer
)
1262 UserDereferenceObject(Hook
);
1263 IntRemoveHook(Hook
, WinStaObj
, FALSE
);
1264 ObDereferenceObject(WinStaObj
);
1265 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1269 Hook
->ModuleName
.MaximumLength
= ModuleName
.MaximumLength
;
1270 Status
= MmCopyFromCaller(Hook
->ModuleName
.Buffer
,
1272 ModuleName
.MaximumLength
);
1273 if (!NT_SUCCESS(Status
))
1275 ExFreePoolWithTag(Hook
->ModuleName
.Buffer
, TAG_HOOK
);
1276 UserDereferenceObject(Hook
);
1277 IntRemoveHook(Hook
, WinStaObj
, FALSE
);
1278 ObDereferenceObject(WinStaObj
);
1279 SetLastNtError(Status
);
1283 Hook
->ModuleName
.Length
= ModuleName
.Length
;
1284 /* make proc relative to the module base */
1285 Hook
->Proc
= (void *)((char *)HookProc
- (char *)Mod
);
1288 Hook
->Proc
= HookProc
;
1291 Handle
= UserHMGetHandle(Hook
);
1293 /* Clear the client threads next hook. */
1294 ClientInfo
->phkCurrent
= 0;
1296 UserDereferenceObject(Hook
);
1298 ObDereferenceObject(WinStaObj
);
1303 DPRINT("Leave NtUserSetWindowsHookEx, ret=%i\n",_ret_
);
1311 NtUserUnhookWindowsHookEx(HHOOK Hook
)
1313 PWINSTATION_OBJECT WinStaObj
;
1316 DECLARE_RETURN(BOOL
);
1318 DPRINT("Enter NtUserUnhookWindowsHookEx\n");
1319 UserEnterExclusive();
1321 Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
1326 if (!NT_SUCCESS(Status
))
1328 SetLastNtError(Status
);
1332 /* Status = UserReferenceObjectByHandle(gHandleTable, Hook,
1333 otHookProc, (PVOID *) &HookObj); */
1334 if (!(HookObj
= IntGetHookObject(Hook
)))
1336 DPRINT1("Invalid handle passed to NtUserUnhookWindowsHookEx\n");
1337 ObDereferenceObject(WinStaObj
);
1338 /* SetLastNtError(Status); */
1342 ASSERT(Hook
== UserHMGetHandle(HookObj
));
1344 IntRemoveHook(HookObj
, WinStaObj
, FALSE
);
1346 UserDereferenceObject(HookObj
);
1347 ObDereferenceObject(WinStaObj
);
1352 DPRINT("Leave NtUserUnhookWindowsHookEx, ret=%i\n",_ret_
);