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(USER_BODY_TO_HEADER(Hook
)->RefCount
>= 0);
67 USER_BODY_TO_HEADER(Hook
)->RefCount
++;
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
, &Handle
, otHook
, sizeof(HOOK
));
108 Hook
->Thread
= Thread
;
109 Hook
->HookId
= HookId
;
113 W32Thread
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
);
114 ASSERT(W32Thread
!= NULL
);
115 W32Thread
->fsHooks
|= HOOKID_TO_FLAG(HookId
);
117 GetWin32ClientInfo()->fsHooks
= W32Thread
->fsHooks
;
119 if (W32Thread
->ThreadInfo
!= NULL
)
120 W32Thread
->ThreadInfo
->fsHooks
= W32Thread
->fsHooks
;
123 RtlInitUnicodeString(&Hook
->ModuleName
, NULL
);
125 InsertHeadList(&Table
->Hooks
[HOOKID_TO_INDEX(HookId
)], &Hook
->Chain
);
130 /* get the hook table that a given hook belongs to */
134 IntGetTable(PHOOK Hook
)
136 if (NULL
== Hook
->Thread
|| WH_KEYBOARD_LL
== Hook
->HookId
||
137 WH_MOUSE_LL
== Hook
->HookId
)
142 return MsqGetHooks(((PTHREADINFO
)Hook
->Thread
->Tcb
.Win32Thread
)->MessageQueue
);
145 /* get the first hook in the chain */
149 IntGetFirstHook(PHOOKTABLE Table
, int HookId
)
151 PLIST_ENTRY Elem
= Table
->Hooks
[HOOKID_TO_INDEX(HookId
)].Flink
;
153 return Elem
== &Table
->Hooks
[HOOKID_TO_INDEX(HookId
)]
154 ? NULL
: CONTAINING_RECORD(Elem
, HOOK
, Chain
);
157 /* find the first non-deleted hook in the chain */
161 IntGetFirstValidHook(PHOOKTABLE Table
, int HookId
)
166 Hook
= IntGetFirstHook(Table
, HookId
);
168 while (NULL
!= Hook
&& NULL
== Hook
->Proc
)
170 Elem
= Hook
->Chain
.Flink
;
171 Hook
= (Elem
== &Table
->Hooks
[HOOKID_TO_INDEX(HookId
)]
172 ? NULL
: CONTAINING_RECORD(Elem
, HOOK
, Chain
));
178 /* find the next hook in the chain, skipping the deleted ones */
181 IntGetNextHook(PHOOK Hook
)
183 PHOOKTABLE Table
= IntGetTable(Hook
);
184 int HookId
= Hook
->HookId
;
187 Elem
= Hook
->Chain
.Flink
;
188 while (Elem
!= &Table
->Hooks
[HOOKID_TO_INDEX(HookId
)])
190 Hook
= CONTAINING_RECORD(Elem
, HOOK
, Chain
);
191 if (NULL
!= Hook
->Proc
)
197 if (NULL
!= GlobalHooks
&& Table
!= GlobalHooks
) /* now search through the global table */
199 return IntGetFirstValidHook(GlobalHooks
, HookId
);
205 /* free a hook, removing it from its chain */
209 IntFreeHook(PHOOKTABLE Table
, PHOOK Hook
, PWINSTATION_OBJECT WinStaObj
)
211 RemoveEntryList(&Hook
->Chain
);
212 RtlFreeUnicodeString(&Hook
->ModuleName
);
214 /* Dereference thread if required */
215 if (Hook
->Flags
& HOOK_THREAD_REFERENCED
)
217 ObDereferenceObject(Hook
->Thread
);
221 UserDeleteObject(Hook
->Self
, otHook
);
224 /* remove a hook, freeing it if the chain is not in use */
227 IntRemoveHook(PHOOK Hook
, PWINSTATION_OBJECT WinStaObj
, BOOL TableAlreadyLocked
)
229 PTHREADINFO W32Thread
;
230 PHOOKTABLE Table
= IntGetTable(Hook
);
232 ASSERT(NULL
!= Table
);
238 W32Thread
= ((PTHREADINFO
)Hook
->Thread
->Tcb
.Win32Thread
);
239 ASSERT(W32Thread
!= NULL
);
240 W32Thread
->fsHooks
&= ~HOOKID_TO_FLAG(Hook
->HookId
);
242 GetWin32ClientInfo()->fsHooks
= W32Thread
->fsHooks
;
244 if (W32Thread
->ThreadInfo
!= NULL
)
245 W32Thread
->ThreadInfo
->fsHooks
= W32Thread
->fsHooks
;
247 if (0 != Table
->Counts
[HOOKID_TO_INDEX(Hook
->HookId
)])
249 Hook
->Proc
= NULL
; /* chain is in use, just mark it and return */
253 IntFreeHook(Table
, Hook
, WinStaObj
);
257 /* release a hook chain, removing deleted hooks if the use count drops to 0 */
261 IntReleaseHookChain(PHOOKTABLE Table
, int HookId
, PWINSTATION_OBJECT WinStaObj
)
271 /* use count shouldn't already be 0 */
272 ASSERT(0 != Table
->Counts
[HOOKID_TO_INDEX(HookId
)]);
274 if (0 == Table
->Counts
[HOOKID_TO_INDEX(HookId
)])
279 if (0 == --Table
->Counts
[HOOKID_TO_INDEX(HookId
)])
281 Elem
= Table
->Hooks
[HOOKID_TO_INDEX(HookId
)].Flink
;
283 while (Elem
!= &Table
->Hooks
[HOOKID_TO_INDEX(HookId
)])
285 HookObj
= CONTAINING_RECORD(Elem
, HOOK
, Chain
);
288 if (NULL
== HookObj
->Proc
)
290 IntFreeHook(Table
, HookObj
, WinStaObj
);
299 IntCallLowLevelHook(PHOOK Hook
, INT Code
, WPARAM wParam
, LPARAM lParam
)
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
,
316 return NT_SUCCESS(Status
) ? uResult
: 0;
320 Called from inside kernel space.
324 co_HOOK_CallHooks(INT HookId
, INT Code
, WPARAM wParam
, LPARAM lParam
)
326 PHOOK Hook
, SaveHook
;
328 PCLIENTINFO ClientInfo
;
331 PWINSTATION_OBJECT WinStaObj
;
334 ASSERT(WH_MINHOOK
<= HookId
&& HookId
<= WH_MAXHOOK
);
336 pti
= PsGetCurrentThreadWin32Thread();
343 Table
= MsqGetHooks(pti
->MessageQueue
);
346 if (NULL
== Table
|| ! (Hook
= IntGetFirstValidHook(Table
, HookId
)))
348 /* try global table */
350 if (NULL
== Table
|| ! (Hook
= IntGetFirstValidHook(Table
, HookId
)))
352 return 0; /* no hook set */
356 if ((Hook
->Thread
!= PsGetCurrentThread()) && (Hook
->Thread
!= NULL
))
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(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 DPRINT1("HOOK WH_CBT!\n");
791 case HCBT_CREATEWND
: /* Use Ansi. */
792 DPRINT1("HOOK HCBT_CREATEWND\n");
793 /* lResult = co_HOOK_CallHookNext(Hook, Code, wParam, lParam); */
800 DPRINT1("HOOK HCBT_MOVESIZE\n");
806 ProbeForRead((PVOID
)lParam
,
814 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
822 DPRINT1("HOOK HCBT_MOVESIZE read from lParam ERROR!\n");
828 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&rt
);
835 CBTACTIVATESTRUCT CbAs
;
837 DPRINT1("HOOK HCBT_ACTIVATE\n");
842 ProbeForRead((PVOID
)lParam
,
843 sizeof(CBTACTIVATESTRUCT
),
848 sizeof(CBTACTIVATESTRUCT
));
850 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
858 DPRINT1("HOOK HCBT_ACTIVATE read from lParam ERROR!\n");
864 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&CbAs
);
869 /* The rest just use default. */
871 DPRINT1("HOOK HCBT_ %d\n",Code
);
872 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, lParam
);
877 case WH_JOURNALPLAYBACK
:
878 case WH_JOURNALRECORD
:
886 ProbeForRead((PVOID
)lParam
,
890 RtlCopyMemory(&EventMsg
,
894 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
902 DPRINT1("HOOK WH_JOURNAL read from lParam ERROR!\n");
908 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)(lParam
? &EventMsg
: NULL
));
914 ProbeForWrite((PVOID
)lParam
,
918 RtlCopyMemory((PVOID
)lParam
,
922 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
930 DPRINT1("HOOK WH_JOURNAL write to lParam ERROR!\n");
938 lResult
= IntCallDebugHook(Hook
, Code
, wParam
, lParam
);
942 * Default the rest like, WH_FOREGROUNDIDLE, WH_KEYBOARD and WH_SHELL.
944 case WH_FOREGROUNDIDLE
:
947 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, lParam
);
951 DPRINT1("Unsupported HOOK Id -> %d\n",Hook
->HookId
);
960 NtUserCallNextHookEx(int Code
,
965 PHOOK HookObj
, NextObj
;
966 PCLIENTINFO ClientInfo
;
967 PWINSTATION_OBJECT WinStaObj
;
969 DECLARE_RETURN(LRESULT
);
971 DPRINT("Enter NtUserCallNextHookEx\n");
972 UserEnterExclusive();
974 Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
978 if (!NT_SUCCESS(Status
))
980 SetLastNtError(Status
);
984 ObDereferenceObject(WinStaObj
);
986 ClientInfo
= GetWin32ClientInfo();
988 if (!ClientInfo
) RETURN( 0);
990 HookObj
= ClientInfo
->phkCurrent
;
992 if (!HookObj
) RETURN( 0);
994 UserReferenceObject(HookObj
);
996 Ansi
= HookObj
->Ansi
;
998 if (NULL
!= HookObj
->Thread
&& (HookObj
->Thread
!= PsGetCurrentThread()))
1000 DPRINT1("Thread mismatch\n");
1001 UserDereferenceObject(HookObj
);
1002 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1006 NextObj
= IntGetNextHook(HookObj
);
1007 ClientInfo
->phkCurrent
= NextObj
; /* Preset next hook from list. */
1008 UserCallNextHookEx( HookObj
, Code
, wParam
, lParam
, Ansi
);
1009 UserDereferenceObject(HookObj
);
1011 RETURN( (LRESULT
)NextObj
);
1014 DPRINT("Leave NtUserCallNextHookEx, ret=%i\n",_ret_
);
1021 NtUserSetWindowsHookAW(int idHook
,
1025 UNICODE_STRING USModuleName
;
1027 RtlInitUnicodeString(&USModuleName
, NULL
);
1029 return NtUserSetWindowsHookEx(NULL
, &USModuleName
, 0, idHook
, lpfn
, Ansi
);
1034 NtUserSetWindowsHookEx(HINSTANCE Mod
,
1035 PUNICODE_STRING UnsafeModuleName
,
1041 PWINSTATION_OBJECT WinStaObj
;
1042 PCLIENTINFO ClientInfo
;
1046 UNICODE_STRING ModuleName
;
1049 BOOLEAN ThreadReferenced
= FALSE
;
1050 DECLARE_RETURN(HHOOK
);
1052 DPRINT("Enter NtUserSetWindowsHookEx\n");
1053 UserEnterExclusive();
1055 if (HookId
< WH_MINHOOK
|| WH_MAXHOOK
< HookId
)
1057 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1063 SetLastWin32Error(ERROR_INVALID_FILTER_PROC
);
1067 ClientInfo
= GetWin32ClientInfo();
1069 if (ThreadId
) /* thread-local hook */
1071 if (HookId
== WH_JOURNALRECORD
||
1072 HookId
== WH_JOURNALPLAYBACK
||
1073 HookId
== WH_KEYBOARD_LL
||
1074 HookId
== WH_MOUSE_LL
||
1075 HookId
== WH_SYSMSGFILTER
)
1077 /* these can only be global */
1078 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1085 if (!NT_SUCCESS(PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
) ThreadId
, &Thread
)))
1087 DPRINT1("Invalid thread id 0x%x\n", ThreadId
);
1088 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1092 /* Thread was referenced */
1093 ThreadReferenced
= TRUE
;
1094 if (Thread
->ThreadsProcess
!= PsGetCurrentProcess())
1096 ObDereferenceObject(Thread
);
1097 DPRINT1("Can't specify thread belonging to another process\n");
1098 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1102 else /* system-global hook */
1104 if (HookId
== WH_KEYBOARD_LL
|| HookId
== WH_MOUSE_LL
)
1107 Thread
= PsGetCurrentThread();
1109 Status
= ObReferenceObjectByPointer(Thread
,
1114 if (!NT_SUCCESS(Status
))
1116 SetLastNtError(Status
);
1117 RETURN( (HANDLE
) NULL
);
1120 /* Thread was referenced */
1121 ThreadReferenced
= TRUE
;
1123 else if (NULL
== Mod
)
1125 SetLastWin32Error(ERROR_HOOK_NEEDS_HMOD
);
1135 if ((Global
&& (HookId
!= WH_KEYBOARD_LL
&& HookId
!= WH_MOUSE_LL
)) ||
1136 WH_DEBUG
== HookId
||
1137 WH_JOURNALPLAYBACK
== HookId
||
1138 WH_JOURNALRECORD
== HookId
)
1140 #if 0 /* Removed to get winEmbed working again */
1143 DPRINT1("Not implemented: HookId %d Global %s\n", HookId
, Global
? "TRUE" : "FALSE");
1146 /* Dereference thread if needed */
1147 if (ThreadReferenced
) ObDereferenceObject(Thread
);
1148 SetLastWin32Error(ERROR_NOT_SUPPORTED
);
1152 Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
1157 if (!NT_SUCCESS(Status
))
1159 /* Dereference thread if needed */
1160 if (ThreadReferenced
) ObDereferenceObject(Thread
);
1161 SetLastNtError(Status
);
1162 RETURN( (HANDLE
) NULL
);
1165 Hook
= IntAddHook(Thread
, HookId
, Global
, WinStaObj
);
1168 /* Dereference thread if needed */
1169 if (ThreadReferenced
) ObDereferenceObject(Thread
);
1170 ObDereferenceObject(WinStaObj
);
1174 /* Let IntFreeHook now that this thread needs a dereference */
1175 if (ThreadReferenced
)
1177 Hook
->Flags
|= HOOK_THREAD_REFERENCED
;
1182 Status
= MmCopyFromCaller(&ModuleName
, UnsafeModuleName
, sizeof(UNICODE_STRING
));
1183 if (!NT_SUCCESS(Status
))
1185 UserDereferenceObject(Hook
);
1186 IntRemoveHook(Hook
, WinStaObj
, FALSE
);
1187 ObDereferenceObject(WinStaObj
);
1188 SetLastNtError(Status
);
1192 Hook
->ModuleName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1193 ModuleName
.MaximumLength
,
1195 if (NULL
== Hook
->ModuleName
.Buffer
)
1197 UserDereferenceObject(Hook
);
1198 IntRemoveHook(Hook
, WinStaObj
, FALSE
);
1199 ObDereferenceObject(WinStaObj
);
1200 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1204 Hook
->ModuleName
.MaximumLength
= ModuleName
.MaximumLength
;
1205 Status
= MmCopyFromCaller(Hook
->ModuleName
.Buffer
,
1207 ModuleName
.MaximumLength
);
1208 if (!NT_SUCCESS(Status
))
1210 ExFreePoolWithTag(Hook
->ModuleName
.Buffer
, TAG_HOOK
);
1211 UserDereferenceObject(Hook
);
1212 IntRemoveHook(Hook
, WinStaObj
, FALSE
);
1213 ObDereferenceObject(WinStaObj
);
1214 SetLastNtError(Status
);
1218 Hook
->ModuleName
.Length
= ModuleName
.Length
;
1219 /* make proc relative to the module base */
1220 Hook
->Proc
= (void *)((char *)HookProc
- (char *)Mod
);
1223 Hook
->Proc
= HookProc
;
1226 Handle
= Hook
->Self
;
1228 /* Clear the client threads next hook. */
1229 ClientInfo
->phkCurrent
= 0;
1231 UserDereferenceObject(Hook
);
1233 ObDereferenceObject(WinStaObj
);
1238 DPRINT("Leave NtUserSetWindowsHookEx, ret=%i\n",_ret_
);
1246 NtUserUnhookWindowsHookEx(HHOOK Hook
)
1248 PWINSTATION_OBJECT WinStaObj
;
1251 DECLARE_RETURN(BOOL
);
1253 DPRINT("Enter NtUserUnhookWindowsHookEx\n");
1254 UserEnterExclusive();
1256 Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
1261 if (!NT_SUCCESS(Status
))
1263 SetLastNtError(Status
);
1267 /* Status = UserReferenceObjectByHandle(gHandleTable, Hook,
1268 otHookProc, (PVOID *) &HookObj); */
1269 if (!(HookObj
= IntGetHookObject(Hook
)))
1271 DPRINT1("Invalid handle passed to NtUserUnhookWindowsHookEx\n");
1272 ObDereferenceObject(WinStaObj
);
1273 /* SetLastNtError(Status); */
1277 ASSERT(Hook
== HookObj
->Self
);
1279 IntRemoveHook(HookObj
, WinStaObj
, FALSE
);
1281 UserDereferenceObject(HookObj
);
1282 ObDereferenceObject(WinStaObj
);
1287 DPRINT("Leave NtUserUnhookWindowsHookEx, ret=%i\n",_ret_
);