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 */
26 IntAllocHookTable(void)
31 Table
= ExAllocatePoolWithTag(PagedPool
, sizeof(HOOKTABLE
), TAG_HOOK
);
34 for (i
= 0; i
< NB_HOOKS
; i
++)
36 InitializeListHead(&Table
->Hooks
[i
]);
45 PHOOK FASTCALL
IntGetHookObject(HHOOK hHook
)
51 SetLastWin32Error(ERROR_INVALID_HOOK_HANDLE
);
55 Hook
= (PHOOK
)UserGetObject(gHandleTable
, hHook
, otHook
);
58 SetLastWin32Error(ERROR_INVALID_HOOK_HANDLE
);
62 ASSERT(USER_BODY_TO_HEADER(Hook
)->RefCount
>= 0);
64 USER_BODY_TO_HEADER(Hook
)->RefCount
++;
71 /* create a new hook and add it to the specified table */
73 IntAddHook(PETHREAD Thread
, int HookId
, BOOLEAN Global
, PWINSTATION_OBJECT WinStaObj
)
77 PHOOKTABLE Table
= Global
? GlobalHooks
: MsqGetHooks(((PW32THREAD
)Thread
->Tcb
.Win32Thread
)->MessageQueue
);
82 Table
= IntAllocHookTable();
93 MsqSetHooks(((PW32THREAD
)Thread
->Tcb
.Win32Thread
)->MessageQueue
, Table
);
97 Hook
= UserCreateObject(gHandleTable
, &Handle
, otHook
, sizeof(HOOK
));
104 Hook
->Thread
= Thread
;
105 Hook
->HookId
= HookId
;
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
;
116 RtlInitUnicodeString(&Hook
->ModuleName
, NULL
);
118 InsertHeadList(&Table
->Hooks
[HOOKID_TO_INDEX(HookId
)], &Hook
->Chain
);
123 /* get the hook table that a given hook belongs to */
124 static PHOOKTABLE FASTCALL
125 IntGetTable(PHOOK Hook
)
127 if (NULL
== Hook
->Thread
|| WH_KEYBOARD_LL
== Hook
->HookId
||
128 WH_MOUSE_LL
== Hook
->HookId
)
133 return MsqGetHooks(((PW32THREAD
)Hook
->Thread
->Tcb
.Win32Thread
)->MessageQueue
);
136 /* get the first hook in the chain */
137 static PHOOK FASTCALL
138 IntGetFirstHook(PHOOKTABLE Table
, int HookId
)
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
);
145 /* find the first non-deleted hook in the chain */
146 static PHOOK FASTCALL
147 IntGetFirstValidHook(PHOOKTABLE Table
, int HookId
)
152 Hook
= IntGetFirstHook(Table
, HookId
);
153 while (NULL
!= Hook
&& NULL
== Hook
->Proc
)
155 Elem
= Hook
->Chain
.Flink
;
156 Hook
= (Elem
== &Table
->Hooks
[HOOKID_TO_INDEX(HookId
)]
157 ? NULL
: CONTAINING_RECORD(Elem
, HOOK
, Chain
));
163 /* find the next hook in the chain, skipping the deleted ones */
164 static PHOOK FASTCALL
165 IntGetNextHook(PHOOK Hook
)
167 PHOOKTABLE Table
= IntGetTable(Hook
);
168 int HookId
= Hook
->HookId
;
171 Elem
= Hook
->Chain
.Flink
;
172 while (Elem
!= &Table
->Hooks
[HOOKID_TO_INDEX(HookId
)])
174 Hook
= CONTAINING_RECORD(Elem
, HOOK
, Chain
);
175 if (NULL
!= Hook
->Proc
)
181 if (NULL
!= GlobalHooks
&& Table
!= GlobalHooks
) /* now search through the global table */
183 return IntGetFirstValidHook(GlobalHooks
, HookId
);
189 /* free a hook, removing it from its chain */
191 IntFreeHook(PHOOKTABLE Table
, PHOOK Hook
, PWINSTATION_OBJECT WinStaObj
)
193 RemoveEntryList(&Hook
->Chain
);
194 RtlFreeUnicodeString(&Hook
->ModuleName
);
196 /* Dereference thread if required */
197 if (Hook
->Flags
& HOOK_THREAD_REFERENCED
)
199 ObDereferenceObject(Hook
->Thread
);
203 UserDeleteObject(Hook
->Self
, otHook
);
206 /* remove a hook, freeing it if the chain is not in use */
208 IntRemoveHook(PHOOK Hook
, PWINSTATION_OBJECT WinStaObj
, BOOL TableAlreadyLocked
)
210 PW32THREAD W32Thread
;
211 PHOOKTABLE Table
= IntGetTable(Hook
);
213 ASSERT(NULL
!= Table
);
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
;
225 if (0 != Table
->Counts
[HOOKID_TO_INDEX(Hook
->HookId
)])
227 Hook
->Proc
= NULL
; /* chain is in use, just mark it and return */
231 IntFreeHook(Table
, Hook
, WinStaObj
);
235 /* release a hook chain, removing deleted hooks if the use count drops to 0 */
237 IntReleaseHookChain(PHOOKTABLE Table
, int HookId
, PWINSTATION_OBJECT WinStaObj
)
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
)])
253 if (0 == --Table
->Counts
[HOOKID_TO_INDEX(HookId
)])
255 Elem
= Table
->Hooks
[HOOKID_TO_INDEX(HookId
)].Flink
;
256 while (Elem
!= &Table
->Hooks
[HOOKID_TO_INDEX(HookId
)])
258 HookObj
= CONTAINING_RECORD(Elem
, HOOK
, Chain
);
260 if (NULL
== HookObj
->Proc
)
262 IntFreeHook(Table
, HookObj
, WinStaObj
);
268 static LRESULT FASTCALL
269 IntCallLowLevelHook(INT HookId
, INT Code
, WPARAM wParam
, LPARAM lParam
, PHOOK Hook
)
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
);
279 return NT_SUCCESS(Status
) ? uResult
: 0;
283 co_HOOK_CallHooks(INT HookId
, INT Code
, WPARAM wParam
, LPARAM lParam
)
286 PW32THREAD Win32Thread
;
289 PWINSTATION_OBJECT WinStaObj
;
292 ASSERT(WH_MINHOOK
<= HookId
&& HookId
<= WH_MAXHOOK
);
294 Win32Thread
= PsGetCurrentThreadWin32Thread();
295 if (NULL
== Win32Thread
)
301 Table
= MsqGetHooks(Win32Thread
->MessageQueue
);
304 if (NULL
== Table
|| ! (Hook
= IntGetFirstValidHook(Table
, HookId
)))
306 /* try global table */
308 if (NULL
== Table
|| ! (Hook
= IntGetFirstValidHook(Table
, HookId
)))
310 return 0; /* no hook set */
314 if (Hook
->Thread
!= PsGetCurrentThread()
315 && (WH_KEYBOARD_LL
== HookId
|| WH_MOUSE_LL
== HookId
))
317 DPRINT("Calling hook in owning thread\n");
318 return IntCallLowLevelHook(HookId
, Code
, wParam
, lParam
, Hook
);
321 if ((Hook
->Thread
!= PsGetCurrentThread()) && (Hook
->Thread
!= NULL
))
323 DPRINT1("Calling hooks in other threads not implemented yet");
327 Table
->Counts
[HOOKID_TO_INDEX(HookId
)]++;
328 if (Table
!= GlobalHooks
&& GlobalHooks
!= NULL
)
330 GlobalHooks
->Counts
[HOOKID_TO_INDEX(HookId
)]++;
333 Result
= co_IntCallHookProc(HookId
, Code
, wParam
, lParam
, Hook
->Proc
,
334 Hook
->Ansi
, &Hook
->ModuleName
);
336 Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
341 if (! NT_SUCCESS(Status
))
343 DPRINT1("Invalid window station????\n");
347 IntReleaseHookChain(MsqGetHooks(PsGetCurrentThreadWin32Thread()->MessageQueue
), HookId
, WinStaObj
);
348 IntReleaseHookChain(GlobalHooks
, HookId
, WinStaObj
);
349 ObDereferenceObject(WinStaObj
);
356 HOOK_DestroyThreadHooks(PETHREAD Thread
)
361 PWINSTATION_OBJECT WinStaObj
;
364 if (NULL
!= GlobalHooks
)
366 Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
371 if (! NT_SUCCESS(Status
))
373 DPRINT1("Invalid window station????\n");
377 for (HookId
= WH_MINHOOK
; HookId
<= WH_MAXHOOK
; HookId
++)
379 /* only low-level keyboard/mouse global hooks can be owned by a thread */
384 Elem
= GlobalHooks
->Hooks
[HOOKID_TO_INDEX(HookId
)].Flink
;
385 while (Elem
!= &GlobalHooks
->Hooks
[HOOKID_TO_INDEX(HookId
)])
387 HookObj
= CONTAINING_RECORD(Elem
, HOOK
, Chain
);
389 if (HookObj
->Thread
== Thread
)
391 IntRemoveHook(HookObj
, WinStaObj
, TRUE
);
410 PVOID HooklParam
= NULL
;
417 ProbeForRead((PVOID
)lParam
,
418 sizeof(DEBUGHOOKINFO
),
420 RtlCopyMemory( &Debug
,
422 sizeof(DEBUGHOOKINFO
));
431 DPRINT1("HOOK WH_DEBUG read from lParam ERROR!\n");
436 return lResult
; // Need lParam!
444 case HCBT_CLICKSKIPPED
:
445 Size
= sizeof(MOUSEHOOKSTRUCTEX
);
451 Size
= sizeof(CBTACTIVATESTRUCT
);
453 case HCBT_CREATEWND
: // Handle Ansi?
454 Size
= sizeof(CBT_CREATEWND
);
455 // What shall we do? Size += sizeof(CREATESTRUCTEX);
458 Size
= sizeof(LPARAM
);
464 Size
= sizeof(MSLLHOOKSTRUCT
);
468 Size
= sizeof(KBDLLHOOKSTRUCT
);
472 case WH_SYSMSGFILTER
:
477 case WH_JOURNALPLAYBACK
:
478 case WH_JOURNALRECORD
:
479 Size
= sizeof(EVENTMSG
);
482 case WH_FOREGROUNDIDLE
:
486 Size
= sizeof(LPARAM
);
489 if (Size
> sizeof(LPARAM
))
490 HooklParam
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_HOOK
);
496 ProbeForRead((PVOID
)Debug
.lParam
,
499 RtlCopyMemory( HooklParam
,
510 DPRINT1("HOOK WH_DEBUG read from Debug.lParam ERROR!\n");
511 ExFreePool(HooklParam
);
516 if (HooklParam
) Debug
.lParam
= (LPARAM
)HooklParam
;
517 lResult
= co_HOOK_CallHooks(WH_DEBUG
, Code
, wParam
, (LPARAM
)&Debug
);
518 if (HooklParam
) ExFreePool(HooklParam
);
534 // Handle this one first.
535 if ((HookId
== WH_MOUSE
) || (HookId
== WH_CBT
&& Code
== HCBT_CLICKSKIPPED
))
537 MOUSEHOOKSTRUCTEX Mouse
;
542 ProbeForRead((PVOID
)lParam
,
543 sizeof(MOUSEHOOKSTRUCTEX
),
545 RtlCopyMemory( &Mouse
,
547 sizeof(MOUSEHOOKSTRUCTEX
));
556 DPRINT1("HOOK WH_MOUSE read from lParam ERROR!\n");
561 lResult
= co_HOOK_CallHooks(HookId
, Code
, wParam
, (LPARAM
)&Mouse
);
570 MSLLHOOKSTRUCT Mouse
;
575 ProbeForRead((PVOID
)lParam
,
576 sizeof(MSLLHOOKSTRUCT
),
578 RtlCopyMemory( &Mouse
,
580 sizeof(MSLLHOOKSTRUCT
));
589 DPRINT1("HOOK WH_MOUSE_LL read from lParam ERROR!\n");
594 lResult
= co_HOOK_CallHooks(HookId
, Code
, wParam
, (LPARAM
)&Mouse
);
601 KBDLLHOOKSTRUCT Keyboard
;
606 ProbeForRead((PVOID
)lParam
,
607 sizeof(KBDLLHOOKSTRUCT
),
609 RtlCopyMemory( &Keyboard
,
611 sizeof(KBDLLHOOKSTRUCT
));
620 DPRINT1("HOOK WH_KEYBORD_LL read from lParam ERROR!\n");
625 lResult
= co_HOOK_CallHooks(HookId
, Code
, wParam
, (LPARAM
)&Keyboard
);
631 case WH_SYSMSGFILTER
:
639 ProbeForRead((PVOID
)lParam
,
653 DPRINT1("HOOK WH_XMESSAGEX read from lParam ERROR!\n");
658 lResult
= co_HOOK_CallHooks(HookId
, Code
, wParam
, (LPARAM
)&Msg
);
659 if (lParam
&& (HookId
== WH_GETMESSAGE
))
663 ProbeForWrite((PVOID
)lParam
,
666 RtlCopyMemory((PVOID
)lParam
,
677 DPRINT1("HOOK WH_GETMESSAGE write to lParam ERROR!\n");
687 case HCBT_CREATEWND
: // Use Ansi.
688 lResult
= co_HOOK_CallHooks(HookId
, Code
, wParam
, lParam
);
699 ProbeForRead((PVOID
)lParam
,
713 DPRINT1("HOOK HCBT_MOVESIZE read from lParam ERROR!\n");
718 lResult
= co_HOOK_CallHooks(HookId
, Code
, wParam
, (LPARAM
)&rt
);
725 CBTACTIVATESTRUCT CbAs
;
731 ProbeForRead((PVOID
)lParam
,
732 sizeof(CBTACTIVATESTRUCT
),
734 RtlCopyMemory( &CbAs
,
736 sizeof(CBTACTIVATESTRUCT
));
745 DPRINT1("HOOK HCBT_ACTIVATE read from lParam ERROR!\n");
750 lResult
= co_HOOK_CallHooks(HookId
, Code
, wParam
, (LPARAM
)&CbAs
);
755 The rest just use default.
758 lResult
= co_HOOK_CallHooks(HookId
, Code
, wParam
, lParam
);
763 case WH_JOURNALPLAYBACK
:
764 case WH_JOURNALRECORD
:
771 ProbeForRead((PVOID
)lParam
,
774 RtlCopyMemory( &EventMsg
,
785 DPRINT1("HOOK WH_JOURNAL read from lParam ERROR!\n");
790 lResult
= co_HOOK_CallHooks(HookId
, Code
, wParam
, (LPARAM
)(lParam
? &EventMsg
: NULL
));
795 ProbeForWrite((PVOID
)lParam
,
798 RtlCopyMemory((PVOID
)lParam
,
809 DPRINT1("HOOK WH_JOURNAL write to lParam ERROR!\n");
817 lResult
= IntCallDebugHook( Code
, wParam
, lParam
);
820 Default the rest like, WH_FOREGROUNDIDLE, WH_KEYBOARD and WH_SHELL.
822 case WH_FOREGROUNDIDLE
:
825 lResult
= co_HOOK_CallHooks(HookId
, Code
, wParam
, lParam
);
829 DPRINT1("Unsupported HOOK Id -> %d\n",HookId
);
837 NtUserCallNextHookEx(
843 PHOOK HookObj
, NextObj
;
844 PW32CLIENTINFO ClientInfo
;
845 PWINSTATION_OBJECT WinStaObj
;
849 DECLARE_RETURN(LRESULT
);
851 DPRINT("Enter NtUserCallNextHookEx\n");
852 UserEnterExclusive();
854 Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
859 if (!NT_SUCCESS(Status
))
861 SetLastNtError(Status
);
865 ObDereferenceObject(WinStaObj
);
867 ClientInfo
= GetWin32ClientInfo();
869 HookObj
= ClientInfo
->phkCurrent
; // Use this one set from SetWindowHook.
871 HookId
= HookObj
->HookId
;
872 Ansi
= HookObj
->Ansi
;
874 if (NULL
!= HookObj
->Thread
&& (HookObj
->Thread
!= PsGetCurrentThread()))
876 DPRINT1("Thread mismatch\n");
877 UserDereferenceObject(HookObj
);
878 SetLastWin32Error(ERROR_INVALID_HANDLE
);
882 NextObj
= IntGetNextHook(HookObj
);
883 UserDereferenceObject(HookObj
);
886 lResult
= UserCallNextHookEx( HookId
, Code
, wParam
, lParam
, Ansi
);
888 ClientInfo
->phkCurrent
= NextObj
;
890 if (lResult
== 0) RETURN( 0);
891 RETURN( (LRESULT
)NextObj
);
893 ClientInfo
->phkCurrent
= NextObj
;
898 DPRINT("Leave NtUserCallNextHookEx, ret=%i\n",_ret_
);
905 NtUserSetWindowsHookAW(
910 UNICODE_STRING USModuleName
;
911 RtlInitUnicodeString(&USModuleName
, NULL
);
912 return NtUserSetWindowsHookEx(NULL
, &USModuleName
, 0, idHook
, lpfn
, Ansi
);
917 NtUserSetWindowsHookEx(
919 PUNICODE_STRING UnsafeModuleName
,
925 PWINSTATION_OBJECT WinStaObj
;
926 PW32CLIENTINFO ClientInfo
;
930 UNICODE_STRING ModuleName
;
933 DECLARE_RETURN(HHOOK
);
935 DPRINT("Enter NtUserSetWindowsHookEx\n");
936 UserEnterExclusive();
938 if (HookId
< WH_MINHOOK
|| WH_MAXHOOK
< HookId
|| NULL
== HookProc
)
940 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
944 ClientInfo
= GetWin32ClientInfo();
946 if (ThreadId
) /* thread-local hook */
948 if (HookId
== WH_JOURNALRECORD
||
949 HookId
== WH_JOURNALPLAYBACK
||
950 HookId
== WH_KEYBOARD_LL
||
951 HookId
== WH_MOUSE_LL
||
952 HookId
== WH_SYSMSGFILTER
)
954 /* these can only be global */
955 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
960 if (! NT_SUCCESS(PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
)ThreadId
, &Thread
)))
962 DPRINT1("Invalid thread id 0x%x\n", ThreadId
);
963 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
966 if (Thread
->ThreadsProcess
!= PsGetCurrentProcess())
968 ObDereferenceObject(Thread
);
969 DPRINT1("Can't specify thread belonging to another process\n");
970 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
974 else /* system-global hook */
976 if (HookId
== WH_KEYBOARD_LL
|| HookId
== WH_MOUSE_LL
)
979 Thread
= PsGetCurrentThread();
980 Status
= ObReferenceObjectByPointer(Thread
,
985 if (! NT_SUCCESS(Status
))
987 SetLastNtError(Status
);
988 RETURN( (HANDLE
) NULL
);
991 else if (NULL
== Mod
)
993 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1003 /* We only (partially) support local WH_CBT hooks and
1004 * WH_KEYBOARD_LL, WH_MOUSE_LL and WH_GETMESSAGE hooks for now
1006 if (WH_DEBUG
== HookId
||
1007 WH_JOURNALPLAYBACK
== HookId
||
1008 WH_JOURNALRECORD
== HookId
||
1009 WH_FOREGROUNDIDLE
== HookId
||
1012 #if 0 /* Removed to get winEmbed working again */
1015 DPRINT1("Not implemented: HookId %d Global %s\n", HookId
, Global
? "TRUE" : "FALSE");
1020 ObDereferenceObject(Thread
);
1022 SetLastWin32Error(ERROR_NOT_SUPPORTED
);
1026 Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
1031 if (! NT_SUCCESS(Status
))
1035 ObDereferenceObject(Thread
);
1037 SetLastNtError(Status
);
1038 RETURN( (HANDLE
) NULL
);
1041 Hook
= IntAddHook(Thread
, HookId
, Global
, WinStaObj
);
1046 ObDereferenceObject(Thread
);
1048 ObDereferenceObject(WinStaObj
);
1054 Hook
->Flags
|= HOOK_THREAD_REFERENCED
;
1059 Status
= MmCopyFromCaller(&ModuleName
, UnsafeModuleName
, sizeof(UNICODE_STRING
));
1060 if (! NT_SUCCESS(Status
))
1062 UserDereferenceObject(Hook
);
1063 IntRemoveHook(Hook
, WinStaObj
, FALSE
);
1066 ObDereferenceObject(Thread
);
1068 ObDereferenceObject(WinStaObj
);
1069 SetLastNtError(Status
);
1072 Hook
->ModuleName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1073 ModuleName
.MaximumLength
,
1075 if (NULL
== Hook
->ModuleName
.Buffer
)
1077 UserDereferenceObject(Hook
);
1078 IntRemoveHook(Hook
, WinStaObj
, FALSE
);
1081 ObDereferenceObject(Thread
);
1083 ObDereferenceObject(WinStaObj
);
1084 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1087 Hook
->ModuleName
.MaximumLength
= ModuleName
.MaximumLength
;
1088 Status
= MmCopyFromCaller(Hook
->ModuleName
.Buffer
,
1090 ModuleName
.MaximumLength
);
1091 if (! NT_SUCCESS(Status
))
1093 ExFreePool(Hook
->ModuleName
.Buffer
);
1094 UserDereferenceObject(Hook
);
1095 IntRemoveHook(Hook
, WinStaObj
, FALSE
);
1098 ObDereferenceObject(Thread
);
1100 ObDereferenceObject(WinStaObj
);
1101 SetLastNtError(Status
);
1104 Hook
->ModuleName
.Length
= ModuleName
.Length
;
1107 Hook
->Proc
= HookProc
;
1109 Handle
= Hook
->Self
;
1111 // Set the client threads next hook based on the hooks type.
1112 ClientInfo
->phkCurrent
= IntGetNextHook( Hook
);
1114 UserDereferenceObject(Hook
);
1115 ObDereferenceObject(WinStaObj
);
1120 DPRINT("Leave NtUserSetWindowsHookEx, ret=%i\n",_ret_
);
1128 NtUserUnhookWindowsHookEx(
1131 PWINSTATION_OBJECT WinStaObj
;
1134 DECLARE_RETURN(BOOL
);
1136 DPRINT("Enter NtUserUnhookWindowsHookEx\n");
1137 UserEnterExclusive();
1139 Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
1144 if (! NT_SUCCESS(Status
))
1146 SetLastNtError(Status
);
1150 // Status = UserReferenceObjectByHandle(gHandleTable, Hook,
1151 // otHookProc, (PVOID *) &HookObj);
1152 if (!(HookObj
= IntGetHookObject(Hook
)))
1154 DPRINT1("Invalid handle passed to NtUserUnhookWindowsHookEx\n");
1155 ObDereferenceObject(WinStaObj
);
1156 // SetLastNtError(Status);
1159 ASSERT(Hook
== HookObj
->Self
);
1161 IntRemoveHook(HookObj
, WinStaObj
, FALSE
);
1163 UserDereferenceObject(HookObj
);
1164 ObDereferenceObject(WinStaObj
);
1169 DPRINT("Leave NtUserUnhookWindowsHookEx, ret=%i\n",_ret_
);