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 */
166 IntGetNextHook(PHOOK Hook
)
168 PHOOKTABLE Table
= IntGetTable(Hook
);
169 int HookId
= Hook
->HookId
;
172 Elem
= Hook
->Chain
.Flink
;
173 while (Elem
!= &Table
->Hooks
[HOOKID_TO_INDEX(HookId
)])
175 Hook
= CONTAINING_RECORD(Elem
, HOOK
, Chain
);
176 if (NULL
!= Hook
->Proc
)
182 if (NULL
!= GlobalHooks
&& Table
!= GlobalHooks
) /* now search through the global table */
184 return IntGetFirstValidHook(GlobalHooks
, HookId
);
190 /* free a hook, removing it from its chain */
192 IntFreeHook(PHOOKTABLE Table
, PHOOK Hook
, PWINSTATION_OBJECT WinStaObj
)
194 RemoveEntryList(&Hook
->Chain
);
195 RtlFreeUnicodeString(&Hook
->ModuleName
);
197 /* Dereference thread if required */
198 if (Hook
->Flags
& HOOK_THREAD_REFERENCED
)
200 ObDereferenceObject(Hook
->Thread
);
204 UserDeleteObject(Hook
->Self
, otHook
);
207 /* remove a hook, freeing it if the chain is not in use */
209 IntRemoveHook(PHOOK Hook
, PWINSTATION_OBJECT WinStaObj
, BOOL TableAlreadyLocked
)
211 PW32THREAD W32Thread
;
212 PHOOKTABLE Table
= IntGetTable(Hook
);
214 ASSERT(NULL
!= Table
);
220 W32Thread
= ((PW32THREAD
)Hook
->Thread
->Tcb
.Win32Thread
);
221 ASSERT(W32Thread
!= NULL
);
222 W32Thread
->Hooks
&= ~HOOKID_TO_FLAG(Hook
->HookId
);
223 if (W32Thread
->ThreadInfo
!= NULL
)
224 W32Thread
->ThreadInfo
->Hooks
= W32Thread
->Hooks
;
226 if (0 != Table
->Counts
[HOOKID_TO_INDEX(Hook
->HookId
)])
228 Hook
->Proc
= NULL
; /* chain is in use, just mark it and return */
232 IntFreeHook(Table
, Hook
, WinStaObj
);
236 /* release a hook chain, removing deleted hooks if the use count drops to 0 */
238 IntReleaseHookChain(PHOOKTABLE Table
, int HookId
, PWINSTATION_OBJECT WinStaObj
)
248 /* use count shouldn't already be 0 */
249 ASSERT(0 != Table
->Counts
[HOOKID_TO_INDEX(HookId
)]);
250 if (0 == Table
->Counts
[HOOKID_TO_INDEX(HookId
)])
254 if (0 == --Table
->Counts
[HOOKID_TO_INDEX(HookId
)])
256 Elem
= Table
->Hooks
[HOOKID_TO_INDEX(HookId
)].Flink
;
257 while (Elem
!= &Table
->Hooks
[HOOKID_TO_INDEX(HookId
)])
259 HookObj
= CONTAINING_RECORD(Elem
, HOOK
, Chain
);
261 if (NULL
== HookObj
->Proc
)
263 IntFreeHook(Table
, HookObj
, WinStaObj
);
269 static LRESULT FASTCALL
270 IntCallLowLevelHook(INT HookId
, INT Code
, WPARAM wParam
, LPARAM lParam
, PHOOK Hook
)
275 /* FIXME should get timeout from
276 * HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */
277 Status
= co_MsqSendMessage(((PW32THREAD
)Hook
->Thread
->Tcb
.Win32Thread
)->MessageQueue
, (HWND
)(INT_PTR
) Code
, HookId
,
278 wParam
, lParam
, 5000, TRUE
, TRUE
, &uResult
);
280 return NT_SUCCESS(Status
) ? uResult
: 0;
284 Called from inside kernel space.
288 co_HOOK_CallHooks(INT HookId
, INT Code
, WPARAM wParam
, LPARAM lParam
)
290 PHOOK Hook
, SaveHook
;
291 PW32THREAD Win32Thread
;
292 PW32CLIENTINFO ClientInfo
;
295 PWINSTATION_OBJECT WinStaObj
;
298 ASSERT(WH_MINHOOK
<= HookId
&& HookId
<= WH_MAXHOOK
);
300 Win32Thread
= PsGetCurrentThreadWin32Thread();
301 if (NULL
== Win32Thread
)
307 Table
= MsqGetHooks(Win32Thread
->MessageQueue
);
310 if (NULL
== Table
|| ! (Hook
= IntGetFirstValidHook(Table
, HookId
)))
312 /* try global table */
314 if (NULL
== Table
|| ! (Hook
= IntGetFirstValidHook(Table
, HookId
)))
316 return 0; /* no hook set */
320 if (Hook
->Thread
!= PsGetCurrentThread()
321 && (WH_KEYBOARD_LL
== HookId
|| WH_MOUSE_LL
== HookId
))
323 DPRINT("Calling hook in owning thread\n");
324 return IntCallLowLevelHook(HookId
, Code
, wParam
, lParam
, Hook
);
327 if ((Hook
->Thread
!= PsGetCurrentThread()) && (Hook
->Thread
!= NULL
))
329 DPRINT1("Calling hooks in other threads not implemented yet");
333 Table
->Counts
[HOOKID_TO_INDEX(HookId
)]++;
334 if (Table
!= GlobalHooks
&& GlobalHooks
!= NULL
)
336 GlobalHooks
->Counts
[HOOKID_TO_INDEX(HookId
)]++;
339 ClientInfo
= GetWin32ClientInfo();
340 SaveHook
= ClientInfo
->phkCurrent
;
341 ClientInfo
->phkCurrent
= Hook
; // Load the call.
343 Result
= co_IntCallHookProc(HookId
, Code
, wParam
, lParam
, Hook
->Proc
,
344 Hook
->Ansi
, &Hook
->ModuleName
);
346 ClientInfo
->phkCurrent
= SaveHook
;
348 Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
353 if (! NT_SUCCESS(Status
))
355 DPRINT1("Invalid window station????\n");
359 IntReleaseHookChain(MsqGetHooks(PsGetCurrentThreadWin32Thread()->MessageQueue
), HookId
, WinStaObj
);
360 IntReleaseHookChain(GlobalHooks
, HookId
, WinStaObj
);
361 ObDereferenceObject(WinStaObj
);
368 HOOK_DestroyThreadHooks(PETHREAD Thread
)
373 PWINSTATION_OBJECT WinStaObj
;
376 if (NULL
!= GlobalHooks
)
378 Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
383 if (! NT_SUCCESS(Status
))
385 DPRINT1("Invalid window station????\n");
389 for (HookId
= WH_MINHOOK
; HookId
<= WH_MAXHOOK
; HookId
++)
391 /* only low-level keyboard/mouse global hooks can be owned by a thread */
396 Elem
= GlobalHooks
->Hooks
[HOOKID_TO_INDEX(HookId
)].Flink
;
397 while (Elem
!= &GlobalHooks
->Hooks
[HOOKID_TO_INDEX(HookId
)])
399 HookObj
= CONTAINING_RECORD(Elem
, HOOK
, Chain
);
401 if (HookObj
->Thread
== Thread
)
403 IntRemoveHook(HookObj
, WinStaObj
, TRUE
);
414 co_HOOK_CallHookNext(PHOOK Hook
, INT Code
, WPARAM wParam
, LPARAM lParam
)
416 DPRINT("CALLING HOOK %d\n",Hook
->HookId
);
417 return co_IntCallHookProc(Hook
->HookId
, Code
, wParam
, lParam
, Hook
->Proc
,
418 Hook
->Ansi
, &Hook
->ModuleName
);
433 PVOID HooklParam
= NULL
;
440 ProbeForRead((PVOID
)lParam
,
441 sizeof(DEBUGHOOKINFO
),
443 RtlCopyMemory( &Debug
,
445 sizeof(DEBUGHOOKINFO
));
454 DPRINT1("HOOK WH_DEBUG read from lParam ERROR!\n");
459 return lResult
; // Need lParam!
467 case HCBT_CLICKSKIPPED
:
468 Size
= sizeof(MOUSEHOOKSTRUCTEX
);
474 Size
= sizeof(CBTACTIVATESTRUCT
);
476 case HCBT_CREATEWND
: // Handle Ansi?
477 Size
= sizeof(CBT_CREATEWND
);
478 // What shall we do? Size += sizeof(CREATESTRUCTEX);
481 Size
= sizeof(LPARAM
);
487 Size
= sizeof(MSLLHOOKSTRUCT
);
491 Size
= sizeof(KBDLLHOOKSTRUCT
);
495 case WH_SYSMSGFILTER
:
500 case WH_JOURNALPLAYBACK
:
501 case WH_JOURNALRECORD
:
502 Size
= sizeof(EVENTMSG
);
505 case WH_FOREGROUNDIDLE
:
509 Size
= sizeof(LPARAM
);
512 if (Size
> sizeof(LPARAM
))
513 HooklParam
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_HOOK
);
519 ProbeForRead((PVOID
)Debug
.lParam
,
522 RtlCopyMemory( HooklParam
,
533 DPRINT1("HOOK WH_DEBUG read from Debug.lParam ERROR!\n");
534 ExFreePool(HooklParam
);
539 if (HooklParam
) Debug
.lParam
= (LPARAM
)HooklParam
;
540 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Debug
);
541 if (HooklParam
) ExFreePool(HooklParam
);
546 Called from user space via CallNextHook.
560 // Handle this one first.
561 if ((Hook
->HookId
== WH_MOUSE
) ||
562 (Hook
->HookId
== WH_CBT
&& Code
== HCBT_CLICKSKIPPED
))
564 MOUSEHOOKSTRUCTEX Mouse
;
569 ProbeForRead((PVOID
)lParam
,
570 sizeof(MOUSEHOOKSTRUCTEX
),
572 RtlCopyMemory( &Mouse
,
574 sizeof(MOUSEHOOKSTRUCTEX
));
583 DPRINT1("HOOK WH_MOUSE read from lParam ERROR!\n");
588 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Mouse
);
597 MSLLHOOKSTRUCT Mouse
;
602 ProbeForRead((PVOID
)lParam
,
603 sizeof(MSLLHOOKSTRUCT
),
605 RtlCopyMemory( &Mouse
,
607 sizeof(MSLLHOOKSTRUCT
));
616 DPRINT1("HOOK WH_MOUSE_LL read from lParam ERROR!\n");
621 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Mouse
);
628 KBDLLHOOKSTRUCT Keyboard
;
633 ProbeForRead((PVOID
)lParam
,
634 sizeof(KBDLLHOOKSTRUCT
),
636 RtlCopyMemory( &Keyboard
,
638 sizeof(KBDLLHOOKSTRUCT
));
647 DPRINT1("HOOK WH_KEYBORD_LL read from lParam ERROR!\n");
652 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Keyboard
);
658 case WH_SYSMSGFILTER
:
666 ProbeForRead((PVOID
)lParam
,
680 DPRINT1("HOOK WH_XMESSAGEX read from lParam ERROR!\n");
685 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Msg
);
686 if (lParam
&& (Hook
->HookId
== WH_GETMESSAGE
))
690 ProbeForWrite((PVOID
)lParam
,
693 RtlCopyMemory((PVOID
)lParam
,
704 DPRINT1("HOOK WH_GETMESSAGE write to lParam ERROR!\n");
712 DPRINT1("HOOK WH_CBT!\n");
715 case HCBT_CREATEWND
: // Use Ansi.
716 DPRINT1("HOOK HCBT_CREATEWND\n");
717 // lResult = co_HOOK_CallHookNext(Hook, Code, wParam, lParam);
723 DPRINT1("HOOK HCBT_MOVESIZE\n");
728 ProbeForRead((PVOID
)lParam
,
742 DPRINT1("HOOK HCBT_MOVESIZE read from lParam ERROR!\n");
747 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&rt
);
754 CBTACTIVATESTRUCT CbAs
;
755 DPRINT1("HOOK HCBT_ACTIVATE\n");
760 ProbeForRead((PVOID
)lParam
,
761 sizeof(CBTACTIVATESTRUCT
),
763 RtlCopyMemory( &CbAs
,
765 sizeof(CBTACTIVATESTRUCT
));
774 DPRINT1("HOOK HCBT_ACTIVATE read from lParam ERROR!\n");
779 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&CbAs
);
784 The rest just use default.
787 DPRINT1("HOOK HCBT_ %d\n",Code
);
788 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, lParam
);
793 case WH_JOURNALPLAYBACK
:
794 case WH_JOURNALRECORD
:
801 ProbeForRead((PVOID
)lParam
,
804 RtlCopyMemory( &EventMsg
,
815 DPRINT1("HOOK WH_JOURNAL read from lParam ERROR!\n");
820 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)(lParam
? &EventMsg
: NULL
));
825 ProbeForWrite((PVOID
)lParam
,
828 RtlCopyMemory((PVOID
)lParam
,
839 DPRINT1("HOOK WH_JOURNAL write to lParam ERROR!\n");
847 lResult
= IntCallDebugHook(Hook
, Code
, wParam
, lParam
);
850 Default the rest like, WH_FOREGROUNDIDLE, WH_KEYBOARD and WH_SHELL.
852 case WH_FOREGROUNDIDLE
:
855 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, lParam
);
859 DPRINT1("Unsupported HOOK Id -> %d\n",Hook
->HookId
);
867 NtUserCallNextHookEx(
873 PHOOK HookObj
, NextObj
;
874 PW32CLIENTINFO ClientInfo
;
875 PWINSTATION_OBJECT WinStaObj
;
877 DECLARE_RETURN(LRESULT
);
879 DPRINT("Enter NtUserCallNextHookEx\n");
880 UserEnterExclusive();
882 Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
886 if (!NT_SUCCESS(Status
))
888 SetLastNtError(Status
);
892 ObDereferenceObject(WinStaObj
);
894 ClientInfo
= GetWin32ClientInfo();
896 if (!ClientInfo
) RETURN( 0);
898 HookObj
= ClientInfo
->phkCurrent
;
900 if (!HookObj
) RETURN( 0);
902 UserReferenceObject(HookObj
);
904 Ansi
= HookObj
->Ansi
;
906 if (NULL
!= HookObj
->Thread
&& (HookObj
->Thread
!= PsGetCurrentThread()))
908 DPRINT1("Thread mismatch\n");
909 UserDereferenceObject(HookObj
);
910 SetLastWin32Error(ERROR_INVALID_HANDLE
);
914 NextObj
= IntGetNextHook(HookObj
);
915 ClientInfo
->phkCurrent
= NextObj
; // Preset next hook from list.
916 UserCallNextHookEx( HookObj
, Code
, wParam
, lParam
, Ansi
);
917 UserDereferenceObject(HookObj
);
919 RETURN( (LRESULT
)NextObj
);
922 DPRINT("Leave NtUserCallNextHookEx, ret=%i\n",_ret_
);
929 NtUserSetWindowsHookAW(
934 UNICODE_STRING USModuleName
;
935 RtlInitUnicodeString(&USModuleName
, NULL
);
936 return NtUserSetWindowsHookEx(NULL
, &USModuleName
, 0, idHook
, lpfn
, Ansi
);
941 NtUserSetWindowsHookEx(
943 PUNICODE_STRING UnsafeModuleName
,
949 PWINSTATION_OBJECT WinStaObj
;
950 PW32CLIENTINFO ClientInfo
;
954 UNICODE_STRING ModuleName
;
957 DECLARE_RETURN(HHOOK
);
959 DPRINT("Enter NtUserSetWindowsHookEx\n");
960 UserEnterExclusive();
962 if (HookId
< WH_MINHOOK
|| WH_MAXHOOK
< HookId
|| NULL
== HookProc
)
964 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
968 ClientInfo
= GetWin32ClientInfo();
970 if (ThreadId
) /* thread-local hook */
972 if (HookId
== WH_JOURNALRECORD
||
973 HookId
== WH_JOURNALPLAYBACK
||
974 HookId
== WH_KEYBOARD_LL
||
975 HookId
== WH_MOUSE_LL
||
976 HookId
== WH_SYSMSGFILTER
)
978 /* these can only be global */
979 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
984 if (! NT_SUCCESS(PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
)ThreadId
, &Thread
)))
986 DPRINT1("Invalid thread id 0x%x\n", ThreadId
);
987 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
990 if (Thread
->ThreadsProcess
!= PsGetCurrentProcess())
992 ObDereferenceObject(Thread
);
993 DPRINT1("Can't specify thread belonging to another process\n");
994 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
998 else /* system-global hook */
1000 if (HookId
== WH_KEYBOARD_LL
|| HookId
== WH_MOUSE_LL
)
1003 Thread
= PsGetCurrentThread();
1004 Status
= ObReferenceObjectByPointer(Thread
,
1009 if (! NT_SUCCESS(Status
))
1011 SetLastNtError(Status
);
1012 RETURN( (HANDLE
) NULL
);
1015 else if (NULL
== Mod
)
1017 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1027 /* We only (partially) support local WH_CBT hooks and
1028 * WH_KEYBOARD_LL, WH_MOUSE_LL and WH_GETMESSAGE hooks for now
1031 WH_DEBUG
== HookId
||
1032 WH_JOURNALPLAYBACK
== HookId
||
1033 WH_JOURNALRECORD
== HookId
||
1034 WH_FOREGROUNDIDLE
== HookId
||
1037 #if 0 /* Removed to get winEmbed working again */
1040 DPRINT1("Not implemented: HookId %d Global %s\n", HookId
, Global
? "TRUE" : "FALSE");
1045 ObDereferenceObject(Thread
);
1047 SetLastWin32Error(ERROR_NOT_SUPPORTED
);
1051 Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
1056 if (! NT_SUCCESS(Status
))
1060 ObDereferenceObject(Thread
);
1062 SetLastNtError(Status
);
1063 RETURN( (HANDLE
) NULL
);
1066 Hook
= IntAddHook(Thread
, HookId
, Global
, WinStaObj
);
1071 ObDereferenceObject(Thread
);
1073 ObDereferenceObject(WinStaObj
);
1079 Hook
->Flags
|= HOOK_THREAD_REFERENCED
;
1084 Status
= MmCopyFromCaller(&ModuleName
, UnsafeModuleName
, sizeof(UNICODE_STRING
));
1085 if (! NT_SUCCESS(Status
))
1087 UserDereferenceObject(Hook
);
1088 IntRemoveHook(Hook
, WinStaObj
, FALSE
);
1091 ObDereferenceObject(Thread
);
1093 ObDereferenceObject(WinStaObj
);
1094 SetLastNtError(Status
);
1097 Hook
->ModuleName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1098 ModuleName
.MaximumLength
,
1100 if (NULL
== Hook
->ModuleName
.Buffer
)
1102 UserDereferenceObject(Hook
);
1103 IntRemoveHook(Hook
, WinStaObj
, FALSE
);
1106 ObDereferenceObject(Thread
);
1108 ObDereferenceObject(WinStaObj
);
1109 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1112 Hook
->ModuleName
.MaximumLength
= ModuleName
.MaximumLength
;
1113 Status
= MmCopyFromCaller(Hook
->ModuleName
.Buffer
,
1115 ModuleName
.MaximumLength
);
1116 if (! NT_SUCCESS(Status
))
1118 ExFreePool(Hook
->ModuleName
.Buffer
);
1119 UserDereferenceObject(Hook
);
1120 IntRemoveHook(Hook
, WinStaObj
, FALSE
);
1123 ObDereferenceObject(Thread
);
1125 ObDereferenceObject(WinStaObj
);
1126 SetLastNtError(Status
);
1129 Hook
->ModuleName
.Length
= ModuleName
.Length
;
1132 Hook
->Proc
= HookProc
;
1134 Handle
= Hook
->Self
;
1136 // Clear the client threads next hook.
1137 ClientInfo
->phkCurrent
= 0;
1139 UserDereferenceObject(Hook
);
1140 ObDereferenceObject(WinStaObj
);
1145 DPRINT("Leave NtUserSetWindowsHookEx, ret=%i\n",_ret_
);
1153 NtUserUnhookWindowsHookEx(
1156 PWINSTATION_OBJECT WinStaObj
;
1159 DECLARE_RETURN(BOOL
);
1161 DPRINT("Enter NtUserUnhookWindowsHookEx\n");
1162 UserEnterExclusive();
1164 Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
1169 if (! NT_SUCCESS(Status
))
1171 SetLastNtError(Status
);
1175 // Status = UserReferenceObjectByHandle(gHandleTable, Hook,
1176 // otHookProc, (PVOID *) &HookObj);
1177 if (!(HookObj
= IntGetHookObject(Hook
)))
1179 DPRINT1("Invalid handle passed to NtUserUnhookWindowsHookEx\n");
1180 ObDereferenceObject(WinStaObj
);
1181 // SetLastNtError(Status);
1184 ASSERT(Hook
== HookObj
->Self
);
1186 IntRemoveHook(HookObj
, WinStaObj
, FALSE
);
1188 UserDereferenceObject(HookObj
);
1189 ObDereferenceObject(WinStaObj
);
1194 DPRINT("Leave NtUserUnhookWindowsHookEx, ret=%i\n",_ret_
);