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 UserReferenceObject(HookObj
);
1055 Ansi
= HookObj
->Ansi
;
1057 if (NULL
!= HookObj
->Thread
&& (HookObj
->Thread
!= PsGetCurrentThread()))
1059 DPRINT1("Thread mismatch\n");
1060 UserDereferenceObject(HookObj
);
1061 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1065 NextObj
= IntGetNextHook(HookObj
);
1066 ClientInfo
->phkCurrent
= NextObj
; /* Preset next hook from list. */
1067 UserCallNextHookEx( HookObj
, Code
, wParam
, lParam
, Ansi
);
1068 UserDereferenceObject(HookObj
);
1070 RETURN( (LRESULT
)NextObj
);
1073 DPRINT("Leave NtUserCallNextHookEx, ret=%i\n",_ret_
);
1080 NtUserSetWindowsHookAW(int idHook
,
1084 UNICODE_STRING USModuleName
;
1086 RtlInitUnicodeString(&USModuleName
, NULL
);
1088 return NtUserSetWindowsHookEx(NULL
, &USModuleName
, 0, idHook
, lpfn
, Ansi
);
1093 NtUserSetWindowsHookEx(HINSTANCE Mod
,
1094 PUNICODE_STRING UnsafeModuleName
,
1100 PWINSTATION_OBJECT WinStaObj
;
1101 PCLIENTINFO ClientInfo
;
1105 UNICODE_STRING ModuleName
;
1108 BOOLEAN ThreadReferenced
= FALSE
;
1109 DECLARE_RETURN(HHOOK
);
1111 DPRINT("Enter NtUserSetWindowsHookEx\n");
1112 UserEnterExclusive();
1114 if (HookId
< WH_MINHOOK
|| WH_MAXHOOK
< HookId
)
1116 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1122 SetLastWin32Error(ERROR_INVALID_FILTER_PROC
);
1126 ClientInfo
= GetWin32ClientInfo();
1128 if (ThreadId
) /* thread-local hook */
1130 if (HookId
== WH_JOURNALRECORD
||
1131 HookId
== WH_JOURNALPLAYBACK
||
1132 HookId
== WH_KEYBOARD_LL
||
1133 HookId
== WH_MOUSE_LL
||
1134 HookId
== WH_SYSMSGFILTER
)
1136 /* these can only be global */
1137 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1144 if (!NT_SUCCESS(PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
) ThreadId
, &Thread
)))
1146 DPRINT1("Invalid thread id 0x%x\n", ThreadId
);
1147 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1151 /* Thread was referenced */
1152 ThreadReferenced
= TRUE
;
1153 if (Thread
->ThreadsProcess
!= PsGetCurrentProcess())
1155 ObDereferenceObject(Thread
);
1156 DPRINT1("Can't specify thread belonging to another process\n");
1157 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1161 else /* system-global hook */
1163 if (HookId
== WH_KEYBOARD_LL
|| HookId
== WH_MOUSE_LL
)
1166 Thread
= PsGetCurrentThread();
1168 Status
= ObReferenceObjectByPointer(Thread
,
1173 if (!NT_SUCCESS(Status
))
1175 SetLastNtError(Status
);
1176 RETURN( (HANDLE
) NULL
);
1179 /* Thread was referenced */
1180 ThreadReferenced
= TRUE
;
1182 else if (NULL
== Mod
)
1184 SetLastWin32Error(ERROR_HOOK_NEEDS_HMOD
);
1194 if ((Global
&& (HookId
!= WH_KEYBOARD_LL
&& HookId
!= WH_MOUSE_LL
)) ||
1195 WH_DEBUG
== HookId
||
1196 WH_JOURNALPLAYBACK
== HookId
||
1197 WH_JOURNALRECORD
== HookId
)
1199 #if 0 /* Removed to get winEmbed working again */
1202 DPRINT1("Not implemented: HookId %d Global %s\n", HookId
, Global
? "TRUE" : "FALSE");
1205 /* Dereference thread if needed */
1206 if (ThreadReferenced
) ObDereferenceObject(Thread
);
1207 SetLastWin32Error(ERROR_NOT_SUPPORTED
);
1211 Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
1216 if (!NT_SUCCESS(Status
))
1218 /* Dereference thread if needed */
1219 if (ThreadReferenced
) ObDereferenceObject(Thread
);
1220 SetLastNtError(Status
);
1221 RETURN( (HANDLE
) NULL
);
1224 Hook
= IntAddHook(Thread
, HookId
, Global
, WinStaObj
);
1227 /* Dereference thread if needed */
1228 if (ThreadReferenced
) ObDereferenceObject(Thread
);
1229 ObDereferenceObject(WinStaObj
);
1233 /* Let IntFreeHook now that this thread needs a dereference */
1234 if (ThreadReferenced
)
1236 Hook
->Flags
|= HOOK_THREAD_REFERENCED
;
1241 Status
= MmCopyFromCaller(&ModuleName
, UnsafeModuleName
, sizeof(UNICODE_STRING
));
1242 if (!NT_SUCCESS(Status
))
1244 UserDereferenceObject(Hook
);
1245 IntRemoveHook(Hook
, WinStaObj
, FALSE
);
1246 ObDereferenceObject(WinStaObj
);
1247 SetLastNtError(Status
);
1251 Hook
->ModuleName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1252 ModuleName
.MaximumLength
,
1254 if (NULL
== Hook
->ModuleName
.Buffer
)
1256 UserDereferenceObject(Hook
);
1257 IntRemoveHook(Hook
, WinStaObj
, FALSE
);
1258 ObDereferenceObject(WinStaObj
);
1259 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1263 Hook
->ModuleName
.MaximumLength
= ModuleName
.MaximumLength
;
1264 Status
= MmCopyFromCaller(Hook
->ModuleName
.Buffer
,
1266 ModuleName
.MaximumLength
);
1267 if (!NT_SUCCESS(Status
))
1269 ExFreePoolWithTag(Hook
->ModuleName
.Buffer
, TAG_HOOK
);
1270 UserDereferenceObject(Hook
);
1271 IntRemoveHook(Hook
, WinStaObj
, FALSE
);
1272 ObDereferenceObject(WinStaObj
);
1273 SetLastNtError(Status
);
1277 Hook
->ModuleName
.Length
= ModuleName
.Length
;
1278 /* make proc relative to the module base */
1279 Hook
->Proc
= (void *)((char *)HookProc
- (char *)Mod
);
1282 Hook
->Proc
= HookProc
;
1285 Handle
= UserHMGetHandle(Hook
);
1287 /* Clear the client threads next hook. */
1288 ClientInfo
->phkCurrent
= 0;
1290 UserDereferenceObject(Hook
);
1292 ObDereferenceObject(WinStaObj
);
1297 DPRINT("Leave NtUserSetWindowsHookEx, ret=%i\n",_ret_
);
1305 NtUserUnhookWindowsHookEx(HHOOK Hook
)
1307 PWINSTATION_OBJECT WinStaObj
;
1310 DECLARE_RETURN(BOOL
);
1312 DPRINT("Enter NtUserUnhookWindowsHookEx\n");
1313 UserEnterExclusive();
1315 Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
1320 if (!NT_SUCCESS(Status
))
1322 SetLastNtError(Status
);
1326 /* Status = UserReferenceObjectByHandle(gHandleTable, Hook,
1327 otHookProc, (PVOID *) &HookObj); */
1328 if (!(HookObj
= IntGetHookObject(Hook
)))
1330 DPRINT1("Invalid handle passed to NtUserUnhookWindowsHookEx\n");
1331 ObDereferenceObject(WinStaObj
);
1332 /* SetLastNtError(Status); */
1336 ASSERT(Hook
== UserHMGetHandle(HookObj
));
1338 IntRemoveHook(HookObj
, WinStaObj
, FALSE
);
1340 UserDereferenceObject(HookObj
);
1341 ObDereferenceObject(WinStaObj
);
1346 DPRINT("Leave NtUserUnhookWindowsHookEx, ret=%i\n",_ret_
);