2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Window hooks
5 * FILE: subsystems/win32/win32k/ntuser/hook.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * James Tabor (james.tabor@rectos.org)
10 * 06-06-2001 CSH Created
11 * NOTE: Most of this code was adapted from Wine,
12 * Copyright (C) 2002 Alexandre Julliard
20 typedef struct _HOOKPACK
24 } HOOKPACK
, *PHOOKPACK
;
26 /* PRIVATE FUNCTIONS *********************************************************/
31 IntCallLowLevelHook( PHOOK Hook
,
39 ULONG_PTR uResult
= 0;
42 pti
= Hook
->Thread
->Tcb
.Win32Thread
;
46 pHP
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(HOOKPACK
), TAG_HOOK
);
52 /* FIXME should get timeout from
53 * HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */
54 Status
= co_MsqSendMessage( pti
->MessageQueue
,
55 IntToPtr(Code
), // hWnd
63 if (!NT_SUCCESS(Status
))
65 DPRINT1("Error Hook Call SendMsg. %d Status: 0x%x\n", Hook
->HookId
, Status
);
66 ExFreePoolWithTag(pHP
, TAG_HOOK
);
68 return NT_SUCCESS(Status
) ? uResult
: 0;
74 co_HOOK_CallHookNext( PHOOK Hook
,
79 if ( (Hook
->Thread
!= PsGetCurrentThread()) && (Hook
->Thread
!= NULL
) )
81 DPRINT1("Calling Next HOOK from another Thread. %d\n", Hook
->HookId
);
82 return IntCallLowLevelHook(Hook
, Code
, wParam
, lParam
);
85 DPRINT("Calling Next HOOK %d\n", Hook
->HookId
);
87 return co_IntCallHookProc( Hook
->HookId
,
97 // Dispatch MsgQueue Hook Call processor!
101 co_CallHook( INT HookId
,
108 PHOOKPACK pHP
= (PHOOKPACK
)lParam
;
111 /* The odds are high for this to be a Global call. */
112 Result
= co_IntCallHookProc( HookId
,
120 ExFreePoolWithTag(pHP
, TAG_HOOK
);
126 IntCallDebugHook( PHOOK Hook
,
135 PVOID HooklParam
= NULL
;
142 ProbeForRead((PVOID
)lParam
,
143 sizeof(DEBUGHOOKINFO
),
146 RtlCopyMemory(&Debug
,
148 sizeof(DEBUGHOOKINFO
));
150 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
158 DPRINT1("HOOK WH_DEBUG read from lParam ERROR!\n");
163 return lResult
; /* Need lParam! */
171 case HCBT_CLICKSKIPPED
:
172 Size
= sizeof(MOUSEHOOKSTRUCTEX
);
180 Size
= sizeof(CBTACTIVATESTRUCT
);
183 case HCBT_CREATEWND
: /* Handle Ansi? */
184 Size
= sizeof(CBT_CREATEWND
);
185 /* What shall we do? Size += sizeof(HOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS); same as CREATESTRUCTEX */
189 Size
= sizeof(LPARAM
);
195 Size
= sizeof(MSLLHOOKSTRUCT
);
199 Size
= sizeof(KBDLLHOOKSTRUCT
);
203 case WH_SYSMSGFILTER
:
208 case WH_JOURNALPLAYBACK
:
209 case WH_JOURNALRECORD
:
210 Size
= sizeof(EVENTMSG
);
213 case WH_FOREGROUNDIDLE
:
217 Size
= sizeof(LPARAM
);
220 if (Size
> sizeof(LPARAM
))
221 HooklParam
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_HOOK
);
227 ProbeForRead((PVOID
)Debug
.lParam
,
231 RtlCopyMemory(HooklParam
,
235 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
243 DPRINT1("HOOK WH_DEBUG read from Debug.lParam ERROR!\n");
244 ExFreePool(HooklParam
);
249 if (HooklParam
) Debug
.lParam
= (LPARAM
)HooklParam
;
250 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Debug
);
251 if (HooklParam
) ExFreePoolWithTag(HooklParam
, TAG_HOOK
);
258 UserCallNextHookEx( PHOOK Hook
,
267 /* Handle this one first. */
268 if ((Hook
->HookId
== WH_MOUSE
) ||
269 (Hook
->HookId
== WH_CBT
&& Code
== HCBT_CLICKSKIPPED
))
271 MOUSEHOOKSTRUCTEX Mouse
;
276 ProbeForRead((PVOID
)lParam
,
277 sizeof(MOUSEHOOKSTRUCTEX
),
280 RtlCopyMemory(&Mouse
,
282 sizeof(MOUSEHOOKSTRUCTEX
));
284 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
292 DPRINT1("HOOK WH_MOUSE read from lParam ERROR!\n");
298 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Mouse
);
308 MSLLHOOKSTRUCT Mouse
;
314 ProbeForRead((PVOID
)lParam
,
315 sizeof(MSLLHOOKSTRUCT
),
318 RtlCopyMemory(&Mouse
,
320 sizeof(MSLLHOOKSTRUCT
));
322 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
330 DPRINT1("HOOK WH_MOUSE_LL read from lParam ERROR!\n");
336 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Mouse
);
343 KBDLLHOOKSTRUCT Keyboard
;
349 ProbeForRead((PVOID
)lParam
,
350 sizeof(KBDLLHOOKSTRUCT
),
353 RtlCopyMemory(&Keyboard
,
355 sizeof(KBDLLHOOKSTRUCT
));
357 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
365 DPRINT1("HOOK WH_KEYBORD_LL read from lParam ERROR!\n");
371 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Keyboard
);
377 case WH_SYSMSGFILTER
:
386 ProbeForRead((PVOID
)lParam
,
394 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
402 DPRINT1("HOOK WH_XMESSAGEX read from lParam ERROR!\n");
408 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Msg
);
410 if (lParam
&& (Hook
->HookId
== WH_GETMESSAGE
))
414 ProbeForWrite((PVOID
)lParam
,
418 RtlCopyMemory((PVOID
)lParam
,
422 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
430 DPRINT1("HOOK WH_GETMESSAGE write to lParam ERROR!\n");
438 DPRINT("HOOK WH_CBT!\n");
443 LPCBT_CREATEWNDW pcbtcww
= (LPCBT_CREATEWNDW
)lParam
;
445 DPRINT("HOOK HCBT_CREATEWND\n");
450 ProbeForRead( pcbtcww
,
451 sizeof(CBT_CREATEWNDA
),
453 ProbeForWrite(pcbtcww
->lpcs
,
454 sizeof(CREATESTRUCTA
),
456 ProbeForRead( pcbtcww
->lpcs
->lpszName
,
460 if (!IS_ATOM(pcbtcww
->lpcs
->lpszClass
))
462 ProbeForRead( pcbtcww
->lpcs
->lpszClass
,
469 ProbeForRead( pcbtcww
,
470 sizeof(CBT_CREATEWNDW
),
472 ProbeForWrite(pcbtcww
->lpcs
,
473 sizeof(CREATESTRUCTW
),
475 ProbeForRead( pcbtcww
->lpcs
->lpszName
,
479 if (!IS_ATOM(pcbtcww
->lpcs
->lpszClass
))
481 ProbeForRead( pcbtcww
->lpcs
->lpszClass
,
487 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
495 DPRINT1("HOOK HCBT_CREATEWND write ERROR!\n");
497 /* The next call handles the structures. */
498 if (!BadChk
&& Hook
->Proc
)
500 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, lParam
);
509 DPRINT("HOOK HCBT_MOVESIZE\n");
515 ProbeForRead((PVOID
)lParam
,
523 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
531 DPRINT1("HOOK HCBT_MOVESIZE read from lParam ERROR!\n");
537 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&rt
);
544 CBTACTIVATESTRUCT CbAs
;
546 DPRINT("HOOK HCBT_ACTIVATE\n");
551 ProbeForRead((PVOID
)lParam
,
552 sizeof(CBTACTIVATESTRUCT
),
557 sizeof(CBTACTIVATESTRUCT
));
559 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
567 DPRINT1("HOOK HCBT_ACTIVATE read from lParam ERROR!\n");
573 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&CbAs
);
578 /* The rest just use default. */
580 DPRINT("HOOK HCBT_ %d\n",Code
);
581 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, lParam
);
586 Note WH_JOURNALPLAYBACK,
587 "To have the system wait before processing the message, the return value
588 must be the amount of time, in clock ticks, that the system should wait."
590 case WH_JOURNALPLAYBACK
:
591 case WH_JOURNALRECORD
:
599 ProbeForRead((PVOID
)lParam
,
603 RtlCopyMemory(&EventMsg
,
607 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
615 DPRINT1("HOOK WH_JOURNAL read from lParam ERROR!\n");
621 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)(lParam
? &EventMsg
: NULL
));
627 ProbeForWrite((PVOID
)lParam
,
631 RtlCopyMemory((PVOID
)lParam
,
635 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
643 DPRINT1("HOOK WH_JOURNAL write to lParam ERROR!\n");
651 lResult
= IntCallDebugHook(Hook
, Code
, wParam
, lParam
, Ansi
);
655 * Default the rest like, WH_FOREGROUNDIDLE, WH_KEYBOARD and WH_SHELL.
657 case WH_FOREGROUNDIDLE
:
660 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, lParam
);
664 DPRINT1("Unsupported HOOK Id -> %d\n",Hook
->HookId
);
672 IntGetHookObject(HHOOK hHook
)
678 SetLastWin32Error(ERROR_INVALID_HOOK_HANDLE
);
682 Hook
= (PHOOK
)UserGetObject(gHandleTable
, hHook
, otHook
);
685 SetLastWin32Error(ERROR_INVALID_HOOK_HANDLE
);
689 UserReferenceObject(Hook
);
694 /* get the first hook in the chain */
698 IntGetFirstHook(PLIST_ENTRY Table
)
700 PLIST_ENTRY Elem
= Table
->Flink
;
702 if (IsListEmpty(Table
)) return NULL
;
704 return Elem
== Table
? NULL
: CONTAINING_RECORD(Elem
, HOOK
, Chain
);
707 /* find the next hook in the chain */
710 IntGetNextHook(PHOOK Hook
)
712 int HookId
= Hook
->HookId
;
718 pti
= ((PTHREADINFO
)Hook
->Thread
->Tcb
.Win32Thread
);
720 Elem
= Hook
->Chain
.Flink
;
721 if (Elem
!= &pti
->aphkStart
[HOOKID_TO_INDEX(HookId
)])
722 return CONTAINING_RECORD(Elem
, HOOK
, Chain
);
726 pti
= PsGetCurrentThreadWin32Thread();
728 Elem
= Hook
->Chain
.Flink
;
729 if (Elem
!= &pti
->rpdesk
->pDeskInfo
->aphkStart
[HOOKID_TO_INDEX(HookId
)])
730 return CONTAINING_RECORD(Elem
, HOOK
, Chain
);
735 /* free a hook, removing it from its chain */
739 IntFreeHook(PHOOK Hook
)
741 RemoveEntryList(&Hook
->Chain
);
742 if (Hook
->ModuleName
.Buffer
)
744 ExFreePoolWithTag(Hook
->ModuleName
.Buffer
, TAG_HOOK
);
745 Hook
->ModuleName
.Buffer
= NULL
;
748 UserDeleteObject(UserHMGetHandle(Hook
), otHook
);
751 /* remove a hook, freeing it from the chain */
755 IntRemoveHook(PHOOK Hook
)
760 HookId
= Hook
->HookId
;
762 if (Hook
->Thread
) // Local
764 pti
= ((PTHREADINFO
)Hook
->Thread
->Tcb
.Win32Thread
);
768 if ( IsListEmpty(&pti
->aphkStart
[HOOKID_TO_INDEX(HookId
)]) )
770 pti
->fsHooks
&= ~HOOKID_TO_FLAG(HookId
);
773 GetWin32ClientInfo()->fsHooks
= pti
->fsHooks
;
775 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
786 pti
= PsGetCurrentThreadWin32Thread();
789 pti
->rpdesk
->pDeskInfo
&&
790 IsListEmpty(&pti
->rpdesk
->pDeskInfo
->aphkStart
[HOOKID_TO_INDEX(HookId
)]) )
792 pti
->rpdesk
->pDeskInfo
->fsHooks
&= ~HOOKID_TO_FLAG(HookId
);
801 HOOK_DestroyThreadHooks(PETHREAD Thread
)
808 pti
= Thread
->Tcb
.Win32Thread
;
809 if (!pti
|| !pti
->pDeskInfo
) return;
811 // Local Thread cleanup.
814 for (HookId
= WH_MINHOOK
; HookId
<= WH_MAXHOOK
; HookId
++)
816 PLIST_ENTRY pLLE
= &pti
->aphkStart
[HOOKID_TO_INDEX(HookId
)];
818 if (IsListEmpty(pLLE
)) continue;
821 HookObj
= CONTAINING_RECORD(pElem
, HOOK
, Chain
);
825 if (IntRemoveHook(HookObj
)) break;
826 pElem
= HookObj
->Chain
.Flink
;
827 HookObj
= CONTAINING_RECORD(pElem
, HOOK
, Chain
);
829 while (pElem
!= pLLE
);
833 // Global search based on Thread and cleanup.
834 if (pti
->rpdesk
->pDeskInfo
->fsHooks
)
836 for (HookId
= WH_MINHOOK
; HookId
<= WH_MAXHOOK
; HookId
++)
838 PLIST_ENTRY pGLE
= &pti
->pDeskInfo
->aphkStart
[HOOKID_TO_INDEX(HookId
)];
840 if (IsListEmpty(pGLE
)) continue;
843 HookObj
= CONTAINING_RECORD(pElem
, HOOK
, Chain
);
847 if (HookObj
->head
.pti
== pti
)
849 if (IntRemoveHook(HookObj
)) break;
851 pElem
= HookObj
->Chain
.Flink
;
852 HookObj
= CONTAINING_RECORD(pElem
, HOOK
, Chain
);
854 while (pElem
!= pGLE
);
861 Win32k Kernel Space Hook Caller.
865 co_HOOK_CallHooks( INT HookId
,
870 PHOOK Hook
, SaveHook
;
872 PCLIENTINFO ClientInfo
;
873 PLIST_ENTRY pLLE
, pGLE
;
874 BOOL Local
= FALSE
, Global
= FALSE
;
877 ASSERT(WH_MINHOOK
<= HookId
&& HookId
<= WH_MAXHOOK
);
879 pti
= PsGetCurrentThreadWin32Thread();
880 if (!pti
|| !pti
->rpdesk
|| !pti
->rpdesk
->pDeskInfo
)
881 goto Exit
; // Must have a desktop running for hooks.
883 if ( pti
->TIF_flags
& TIF_INCLEANUP
)
886 if ( ISITHOOKED(HookId
) )
888 DPRINT("Local Hooker %d\n", HookId
);
892 if ( pti
->rpdesk
->pDeskInfo
->fsHooks
& HOOKID_TO_FLAG(HookId
) )
894 DPRINT("Global Hooker %d\n", HookId
);
898 if ( !Local
&& !Global
) goto Exit
; // No work!
900 pLLE
= &pti
->aphkStart
[HOOKID_TO_INDEX(HookId
)];
901 pGLE
= &pti
->rpdesk
->pDeskInfo
->aphkStart
[HOOKID_TO_INDEX(HookId
)];
904 /* SetWindowHookEx sorts out the Thread issue by placing the Hook to
905 the correct Thread if not NULL.
909 Hook
= IntGetFirstHook(pLLE
);
912 DPRINT1("No Local Hook Found!\n");
915 ObReferenceObject(Hook
->Thread
);
917 ClientInfo
= pti
->pClientInfo
;
918 SaveHook
= pti
->sphkCurrent
;
920 /* Load it for the next call. */
921 pti
->sphkCurrent
= Hook
;
922 Hook
->phkNext
= IntGetNextHook(Hook
);
927 ClientInfo
->phkCurrent
= Hook
;
929 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
931 ClientInfo
= NULL
; // Don't bother next run.
935 Result
= co_IntCallHookProc( HookId
,
946 ClientInfo
->phkCurrent
= SaveHook
;
948 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
953 pti
->sphkCurrent
= SaveHook
;
954 Hook
->phkNext
= NULL
;
955 ObDereferenceObject(Hook
->Thread
);
962 Hook
= IntGetFirstHook(pGLE
);
965 DPRINT1("No Global Hook Found!\n");
968 /* Performance goes down the drain. If more hooks are associated to this
969 * hook ID, this will have to post to each of the thread message queues
970 * or make a direct call.
974 /* Hook->Thread is null, we hax around this with Hook->head.pti. */
975 ptiHook
= Hook
->head
.pti
;
977 /* "Global hook monitors messages for all threads in the same desktop
978 * as the calling thread."
980 if ( ptiHook
->TIF_flags
& TIF_INCLEANUP
||
981 ptiHook
->rpdesk
!= pti
->rpdesk
)
983 Hook
= IntGetNextHook(Hook
);
987 // Lockup the thread while this links through user world.
988 ObReferenceObject(ptiHook
->pEThread
);
991 DPRINT("\nGlobal Hook posting to another Thread! %d\n",HookId
);
992 Result
= IntCallLowLevelHook(Hook
, Code
, wParam
, lParam
);
995 { /* Make the direct call. */
996 DPRINT("\nLocal Hook calling to Thread! %d\n",HookId
);
997 Result
= co_IntCallHookProc( HookId
,
1005 ObDereferenceObject(ptiHook
->pEThread
);
1006 Hook
= IntGetNextHook(Hook
);
1009 DPRINT("Ret: Global HookId %d Result 0x%x\n", HookId
,Result
);
1017 IntUnhookWindowsHook(int HookId
, HOOKPROC pfnFilterProc
)
1020 PLIST_ENTRY pLLE
, pLE
;
1021 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1023 if (HookId
< WH_MINHOOK
|| WH_MAXHOOK
< HookId
)
1025 SetLastWin32Error(ERROR_INVALID_HOOK_FILTER
);
1031 pLLE
= &pti
->aphkStart
[HOOKID_TO_INDEX(HookId
)];
1033 if (IsListEmpty(pLLE
)) return FALSE
;
1036 Hook
= CONTAINING_RECORD(pLE
, HOOK
, Chain
);
1040 if (Hook
->Proc
== pfnFilterProc
)
1042 if (Hook
->head
.pti
== pti
)
1044 IntRemoveHook(Hook
);
1045 UserDereferenceObject(Hook
);
1050 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1054 pLE
= Hook
->Chain
.Flink
;
1055 Hook
= CONTAINING_RECORD(pLE
, HOOK
, Chain
);
1057 while (pLE
!= pLLE
);
1063 * Support for compatibility only? Global hooks are processed in kernel space.
1064 * This is very thread specific! Never seeing applications with more than one
1065 * hook per thread installed. Most of the applications are Global hookers and
1066 * associated with just one hook Id. Maybe it's for diagnostic testing or a
1067 * throw back to 3.11?
1071 NtUserCallNextHookEx( int Code
,
1077 PHOOK HookObj
, NextObj
;
1078 PCLIENTINFO ClientInfo
;
1079 LRESULT lResult
= 0;
1080 DECLARE_RETURN(LRESULT
);
1082 DPRINT("Enter NtUserCallNextHookEx\n");
1083 UserEnterExclusive();
1085 pti
= GetW32ThreadInfo();
1087 HookObj
= pti
->sphkCurrent
;
1089 if (!HookObj
) RETURN( 0);
1091 NextObj
= HookObj
->phkNext
;
1093 pti
->sphkCurrent
= NextObj
;
1094 ClientInfo
= pti
->pClientInfo
;
1097 ClientInfo
->phkCurrent
= NextObj
;
1099 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1105 /* Now in List run down. */
1106 if (ClientInfo
&& NextObj
)
1108 NextObj
->phkNext
= IntGetNextHook(NextObj
);
1109 lResult
= UserCallNextHookEx( NextObj
, Code
, wParam
, lParam
, NextObj
->Ansi
);
1114 DPRINT("Leave NtUserCallNextHookEx, ret=%i\n",_ret_
);
1121 NtUserSetWindowsHookAW( int idHook
,
1126 UNICODE_STRING USModuleName
;
1128 RtlInitUnicodeString(&USModuleName
, NULL
);
1129 ThreadId
= PtrToUint(NtCurrentTeb()->ClientId
.UniqueThread
);
1131 return NtUserSetWindowsHookEx( NULL
,
1141 NtUserSetWindowsHookEx( HINSTANCE Mod
,
1142 PUNICODE_STRING UnsafeModuleName
,
1148 PWINSTATION_OBJECT WinStaObj
;
1150 UNICODE_STRING ModuleName
;
1153 PETHREAD Thread
= NULL
;
1154 PTHREADINFO ptiCurrent
, pti
= NULL
;
1156 DECLARE_RETURN(HHOOK
);
1158 DPRINT("Enter NtUserSetWindowsHookEx\n");
1159 UserEnterExclusive();
1161 ptiCurrent
= GetW32ThreadInfo();
1163 if (HookId
< WH_MINHOOK
|| WH_MAXHOOK
< HookId
)
1165 SetLastWin32Error(ERROR_INVALID_HOOK_FILTER
);
1171 SetLastWin32Error(ERROR_INVALID_FILTER_PROC
);
1175 if (ThreadId
) /* thread-local hook */
1177 if ( HookId
== WH_JOURNALRECORD
||
1178 HookId
== WH_JOURNALPLAYBACK
||
1179 HookId
== WH_KEYBOARD_LL
||
1180 HookId
== WH_MOUSE_LL
||
1181 HookId
== WH_SYSMSGFILTER
)
1183 DPRINT1("Local hook installing Global HookId: %d\n",HookId
);
1184 /* these can only be global */
1185 SetLastWin32Error(ERROR_GLOBAL_ONLY_HOOK
);
1189 if (!NT_SUCCESS(PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
) ThreadId
, &Thread
)))
1191 DPRINT1("Invalid thread id 0x%x\n", ThreadId
);
1192 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1196 pti
= Thread
->Tcb
.Win32Thread
;
1198 ObDereferenceObject(Thread
);
1200 if ( pti
->rpdesk
!= ptiCurrent
->rpdesk
) // gptiCurrent->rpdesk)
1202 DPRINT1("Local hook wrong desktop HookId: %d\n",HookId
);
1203 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1207 if (Thread
->ThreadsProcess
!= PsGetCurrentProcess())
1210 (HookId
== WH_GETMESSAGE
||
1211 HookId
== WH_CALLWNDPROC
||
1213 HookId
== WH_HARDWARE
||
1214 HookId
== WH_DEBUG
||
1215 HookId
== WH_SHELL
||
1216 HookId
== WH_FOREGROUNDIDLE
||
1217 HookId
== WH_CALLWNDPROCRET
) )
1219 DPRINT1("Local hook needs hMod HookId: %d\n",HookId
);
1220 SetLastWin32Error(ERROR_HOOK_NEEDS_HMOD
);
1224 if ( (pti
->TIF_flags
& (TIF_CSRSSTHREAD
|TIF_SYSTEMTHREAD
)) &&
1225 (HookId
== WH_GETMESSAGE
||
1226 HookId
== WH_CALLWNDPROC
||
1228 HookId
== WH_HARDWARE
||
1229 HookId
== WH_DEBUG
||
1230 HookId
== WH_SHELL
||
1231 HookId
== WH_FOREGROUNDIDLE
||
1232 HookId
== WH_CALLWNDPROCRET
) )
1234 SetLastWin32Error(ERROR_HOOK_TYPE_NOT_ALLOWED
);
1239 else /* system-global hook */
1241 pti
= ptiCurrent
; // gptiCurrent;
1243 (HookId
== WH_GETMESSAGE
||
1244 HookId
== WH_CALLWNDPROC
||
1246 HookId
== WH_SYSMSGFILTER
||
1247 HookId
== WH_HARDWARE
||
1248 HookId
== WH_DEBUG
||
1249 HookId
== WH_SHELL
||
1250 HookId
== WH_FOREGROUNDIDLE
||
1251 HookId
== WH_CALLWNDPROCRET
) )
1253 DPRINT1("Global hook needs hMod HookId: %d\n",HookId
);
1254 SetLastWin32Error(ERROR_HOOK_NEEDS_HMOD
);
1259 Status
= IntValidateWindowStationHandle( PsGetCurrentProcess()->Win32WindowStation
,
1264 if (!NT_SUCCESS(Status
))
1266 SetLastNtError(Status
);
1269 ObDereferenceObject(WinStaObj
);
1271 Hook
= UserCreateObject(gHandleTable
, NULL
, &Handle
, otHook
, sizeof(HOOK
));
1278 Hook
->ihmod
= (INT
)Mod
; // Module Index from atom table, Do this for now.
1279 Hook
->Thread
= Thread
; /* Set Thread, Null is Global. */
1280 Hook
->HookId
= HookId
;
1281 Hook
->rpdesk
= pti
->rpdesk
;
1282 Hook
->phkNext
= NULL
; /* Dont use as a chain! Use link lists for chaining. */
1283 Hook
->Proc
= HookProc
;
1286 if (ThreadId
) /* thread-local hook */
1288 InsertHeadList(&pti
->aphkStart
[HOOKID_TO_INDEX(HookId
)], &Hook
->Chain
);
1289 pti
->sphkCurrent
= NULL
;
1290 Hook
->ptiHooked
= pti
;
1291 pti
->fsHooks
|= HOOKID_TO_FLAG(HookId
);
1293 if (pti
->pClientInfo
)
1295 if ( pti
->ppi
== ptiCurrent
->ppi
) /* gptiCurrent->ppi) */
1299 pti
->pClientInfo
->fsHooks
= pti
->fsHooks
;
1300 pti
->pClientInfo
->phkCurrent
= 0;
1302 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1309 DPRINT1("Problem writing to Local ClientInfo!\n");
1314 KeAttachProcess(&pti
->ppi
->peProcess
->Pcb
);
1317 pti
->pClientInfo
->fsHooks
= pti
->fsHooks
;
1318 pti
->pClientInfo
->phkCurrent
= 0;
1320 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1328 DPRINT1("Problem writing to Remote ClientInfo!\n");
1335 InsertHeadList(&pti
->pDeskInfo
->aphkStart
[HOOKID_TO_INDEX(HookId
)], &Hook
->Chain
);
1336 Hook
->ptiHooked
= NULL
;
1337 //gptiCurrent->pDeskInfo->fsHooks |= HOOKID_TO_FLAG(HookId);
1338 pti
->pDeskInfo
->fsHooks
|= HOOKID_TO_FLAG(HookId
);
1341 RtlInitUnicodeString(&Hook
->ModuleName
, NULL
);
1345 Status
= MmCopyFromCaller(&ModuleName
,
1347 sizeof(UNICODE_STRING
));
1348 if (!NT_SUCCESS(Status
))
1350 IntRemoveHook(Hook
);
1351 SetLastNtError(Status
);
1355 Hook
->ModuleName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
1356 ModuleName
.MaximumLength
,
1358 if (NULL
== Hook
->ModuleName
.Buffer
)
1360 IntRemoveHook(Hook
);
1361 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1365 Hook
->ModuleName
.MaximumLength
= ModuleName
.MaximumLength
;
1366 Status
= MmCopyFromCaller( Hook
->ModuleName
.Buffer
,
1368 ModuleName
.MaximumLength
);
1369 if (!NT_SUCCESS(Status
))
1371 ExFreePoolWithTag(Hook
->ModuleName
.Buffer
, TAG_HOOK
);
1372 Hook
->ModuleName
.Buffer
= NULL
;
1373 IntRemoveHook(Hook
);
1374 SetLastNtError(Status
);
1378 Hook
->ModuleName
.Length
= ModuleName
.Length
;
1379 /* make proc relative to the module base */
1380 Hook
->offPfn
= (ULONG_PTR
)((char *)HookProc
- (char *)Mod
);
1385 DPRINT1("Installing: HookId %d Global %s\n", HookId
, !ThreadId
? "TRUE" : "FALSE");
1389 DPRINT("Leave NtUserSetWindowsHookEx, ret=%i\n",_ret_
);
1396 NtUserUnhookWindowsHookEx(HHOOK Hook
)
1399 DECLARE_RETURN(BOOL
);
1401 DPRINT("Enter NtUserUnhookWindowsHookEx\n");
1402 UserEnterExclusive();
1404 if (!(HookObj
= IntGetHookObject(Hook
)))
1406 DPRINT1("Invalid handle passed to NtUserUnhookWindowsHookEx\n");
1407 /* SetLastNtError(Status); */
1411 ASSERT(Hook
== UserHMGetHandle(HookObj
));
1413 IntRemoveHook(HookObj
);
1415 UserDereferenceObject(HookObj
);
1420 DPRINT("Leave NtUserUnhookWindowsHookEx, ret=%i\n",_ret_
);