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
25 } HOOKPACK
, *PHOOKPACK
;
27 /* PRIVATE FUNCTIONS *********************************************************/
32 IntCallLowLevelHook( PHOOK Hook
,
41 ULONG_PTR uResult
= 0;
44 pti
= Hook
->Thread
->Tcb
.Win32Thread
;
48 pHP
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(HOOKPACK
), TAG_HOOK
);
53 pHP
->pHookStructs
= NULL
;
56 // Once the rest is enabled again, This prevents stack corruption from the caller.
63 Size
= sizeof(CBT_CREATEWNDW
);
69 Size
= sizeof(CBTACTIVATESTRUCT
);
71 case HCBT_CLICKSKIPPED
:
72 Size
= sizeof(MOUSEHOOKSTRUCT
);
77 Size
= sizeof(KBDLLHOOKSTRUCT
);
80 Size
= sizeof(MSLLHOOKSTRUCT
);
83 Size
= sizeof(MOUSEHOOKSTRUCT
);
86 Size
= sizeof(CWPSTRUCT
);
88 case WH_CALLWNDPROCRET
:
89 Size
= sizeof(CWPRETSTRUCT
);
100 pHP
->pHookStructs
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_HOOK
);
101 if (pHP
->pHookStructs
) RtlCopyMemory(pHP
->pHookStructs
, (PVOID
)lParam
, Size
);
104 /* FIXME should get timeout from
105 * HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */
106 Status
= co_MsqSendMessage( pti
->MessageQueue
,
107 IntToPtr(Code
), // hWnd
115 if (!NT_SUCCESS(Status
))
117 DPRINT1("Error Hook Call SendMsg. %d Status: 0x%x\n", Hook
->HookId
, Status
);
118 if (pHP
->pHookStructs
) ExFreePoolWithTag(pHP
->pHookStructs
, TAG_HOOK
);
119 ExFreePoolWithTag(pHP
, TAG_HOOK
);
121 return NT_SUCCESS(Status
) ? uResult
: 0;
126 // Dispatch MsgQueue Hook Call processor!
130 co_CallHook( INT HookId
,
137 PHOOKPACK pHP
= (PHOOKPACK
)lParam
;
140 lParam
= pHP
->lParam
;
150 case HCBT_CLICKSKIPPED
:
151 lParam
= (LPARAM
)pHP
->pHookStructs
;
159 case WH_CALLWNDPROCRET
:
161 case WH_SYSMSGFILTER
:
163 lParam
= (LPARAM
)pHP
->pHookStructs
;
167 /* The odds are high for this to be a Global call. */
168 Result
= co_IntCallHookProc( HookId
,
176 /* The odds so high, no one is waiting for the results. */
177 if (pHP
->pHookStructs
) ExFreePoolWithTag(pHP
->pHookStructs
, TAG_HOOK
);
178 ExFreePoolWithTag(pHP
, TAG_HOOK
);
185 co_HOOK_CallHookNext( PHOOK Hook
,
190 if ( (Hook
->Thread
!= PsGetCurrentThread()) && (Hook
->Thread
!= NULL
) )
192 DPRINT1("Calling Next HOOK from another Thread. %d\n", Hook
->HookId
);
193 return IntCallLowLevelHook(Hook
, Code
, wParam
, lParam
);
196 DPRINT("Calling Next HOOK %d\n", Hook
->HookId
);
198 return co_IntCallHookProc( Hook
->HookId
,
209 IntCallDebugHook( PHOOK Hook
,
218 PVOID HooklParam
= NULL
;
225 ProbeForRead((PVOID
)lParam
,
226 sizeof(DEBUGHOOKINFO
),
229 RtlCopyMemory(&Debug
,
231 sizeof(DEBUGHOOKINFO
));
233 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
241 DPRINT1("HOOK WH_DEBUG read from lParam ERROR!\n");
246 return lResult
; /* Need lParam! */
254 case HCBT_CLICKSKIPPED
:
255 Size
= sizeof(MOUSEHOOKSTRUCTEX
);
263 Size
= sizeof(CBTACTIVATESTRUCT
);
266 case HCBT_CREATEWND
: /* Handle Ansi? */
267 Size
= sizeof(CBT_CREATEWND
);
268 /* What shall we do? Size += sizeof(HOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS); same as CREATESTRUCTEX */
272 Size
= sizeof(LPARAM
);
278 Size
= sizeof(MSLLHOOKSTRUCT
);
282 Size
= sizeof(KBDLLHOOKSTRUCT
);
286 case WH_SYSMSGFILTER
:
291 case WH_JOURNALPLAYBACK
:
292 case WH_JOURNALRECORD
:
293 Size
= sizeof(EVENTMSG
);
296 case WH_FOREGROUNDIDLE
:
300 Size
= sizeof(LPARAM
);
303 if (Size
> sizeof(LPARAM
))
304 HooklParam
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_HOOK
);
310 ProbeForRead((PVOID
)Debug
.lParam
,
314 RtlCopyMemory(HooklParam
,
318 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
326 DPRINT1("HOOK WH_DEBUG read from Debug.lParam ERROR!\n");
327 ExFreePool(HooklParam
);
332 if (HooklParam
) Debug
.lParam
= (LPARAM
)HooklParam
;
333 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Debug
);
334 if (HooklParam
) ExFreePoolWithTag(HooklParam
, TAG_HOOK
);
341 UserCallNextHookEx( PHOOK Hook
,
350 /* Handle this one first. */
351 if ((Hook
->HookId
== WH_MOUSE
) ||
352 (Hook
->HookId
== WH_CBT
&& Code
== HCBT_CLICKSKIPPED
))
354 MOUSEHOOKSTRUCTEX Mouse
;
359 ProbeForRead((PVOID
)lParam
,
360 sizeof(MOUSEHOOKSTRUCTEX
),
363 RtlCopyMemory(&Mouse
,
365 sizeof(MOUSEHOOKSTRUCTEX
));
367 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
375 DPRINT1("HOOK WH_MOUSE read from lParam ERROR!\n");
381 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Mouse
);
391 MSLLHOOKSTRUCT Mouse
;
397 ProbeForRead((PVOID
)lParam
,
398 sizeof(MSLLHOOKSTRUCT
),
401 RtlCopyMemory(&Mouse
,
403 sizeof(MSLLHOOKSTRUCT
));
405 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
413 DPRINT1("HOOK WH_MOUSE_LL read from lParam ERROR!\n");
419 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Mouse
);
426 KBDLLHOOKSTRUCT Keyboard
;
432 ProbeForRead((PVOID
)lParam
,
433 sizeof(KBDLLHOOKSTRUCT
),
436 RtlCopyMemory(&Keyboard
,
438 sizeof(KBDLLHOOKSTRUCT
));
440 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
448 DPRINT1("HOOK WH_KEYBORD_LL read from lParam ERROR!\n");
454 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Keyboard
);
460 case WH_SYSMSGFILTER
:
469 ProbeForRead((PVOID
)lParam
,
477 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
485 DPRINT1("HOOK WH_XMESSAGEX read from lParam ERROR!\n");
491 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Msg
);
493 if (lParam
&& (Hook
->HookId
== WH_GETMESSAGE
))
497 ProbeForWrite((PVOID
)lParam
,
501 RtlCopyMemory((PVOID
)lParam
,
505 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
513 DPRINT1("HOOK WH_GETMESSAGE write to lParam ERROR!\n");
521 DPRINT("HOOK WH_CBT!\n");
526 LPCBT_CREATEWNDW pcbtcww
= (LPCBT_CREATEWNDW
)lParam
;
528 DPRINT("HOOK HCBT_CREATEWND\n");
533 ProbeForRead( pcbtcww
,
534 sizeof(CBT_CREATEWNDA
),
536 ProbeForWrite(pcbtcww
->lpcs
,
537 sizeof(CREATESTRUCTA
),
539 ProbeForRead( pcbtcww
->lpcs
->lpszName
,
543 if (!IS_ATOM(pcbtcww
->lpcs
->lpszClass
))
545 ProbeForRead( pcbtcww
->lpcs
->lpszClass
,
552 ProbeForRead( pcbtcww
,
553 sizeof(CBT_CREATEWNDW
),
555 ProbeForWrite(pcbtcww
->lpcs
,
556 sizeof(CREATESTRUCTW
),
558 ProbeForRead( pcbtcww
->lpcs
->lpszName
,
562 if (!IS_ATOM(pcbtcww
->lpcs
->lpszClass
))
564 ProbeForRead( pcbtcww
->lpcs
->lpszClass
,
570 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
578 DPRINT1("HOOK HCBT_CREATEWND write ERROR!\n");
580 /* The next call handles the structures. */
581 if (!BadChk
&& Hook
->Proc
)
583 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, lParam
);
592 DPRINT("HOOK HCBT_MOVESIZE\n");
598 ProbeForRead((PVOID
)lParam
,
606 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
614 DPRINT1("HOOK HCBT_MOVESIZE read from lParam ERROR!\n");
620 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&rt
);
627 CBTACTIVATESTRUCT CbAs
;
629 DPRINT("HOOK HCBT_ACTIVATE\n");
634 ProbeForRead((PVOID
)lParam
,
635 sizeof(CBTACTIVATESTRUCT
),
640 sizeof(CBTACTIVATESTRUCT
));
642 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
650 DPRINT1("HOOK HCBT_ACTIVATE read from lParam ERROR!\n");
656 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&CbAs
);
661 /* The rest just use default. */
663 DPRINT("HOOK HCBT_ %d\n",Code
);
664 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, lParam
);
669 Note WH_JOURNALPLAYBACK,
670 "To have the system wait before processing the message, the return value
671 must be the amount of time, in clock ticks, that the system should wait."
673 case WH_JOURNALPLAYBACK
:
674 case WH_JOURNALRECORD
:
682 ProbeForRead((PVOID
)lParam
,
686 RtlCopyMemory(&EventMsg
,
690 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
698 DPRINT1("HOOK WH_JOURNAL read from lParam ERROR!\n");
704 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)(lParam
? &EventMsg
: NULL
));
710 ProbeForWrite((PVOID
)lParam
,
714 RtlCopyMemory((PVOID
)lParam
,
718 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
726 DPRINT1("HOOK WH_JOURNAL write to lParam ERROR!\n");
734 lResult
= IntCallDebugHook(Hook
, Code
, wParam
, lParam
, Ansi
);
738 * Default the rest like, WH_FOREGROUNDIDLE, WH_KEYBOARD and WH_SHELL.
740 case WH_FOREGROUNDIDLE
:
743 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, lParam
);
747 DPRINT1("Unsupported HOOK Id -> %d\n",Hook
->HookId
);
755 IntGetHookObject(HHOOK hHook
)
761 SetLastWin32Error(ERROR_INVALID_HOOK_HANDLE
);
765 Hook
= (PHOOK
)UserGetObject(gHandleTable
, hHook
, otHook
);
768 SetLastWin32Error(ERROR_INVALID_HOOK_HANDLE
);
772 UserReferenceObject(Hook
);
777 /* get the first hook in the chain */
781 IntGetFirstHook(PLIST_ENTRY Table
)
783 PLIST_ENTRY Elem
= Table
->Flink
;
785 if (IsListEmpty(Table
)) return NULL
;
787 return Elem
== Table
? NULL
: CONTAINING_RECORD(Elem
, HOOK
, Chain
);
793 IntGetNextGlobalHook(PHOOK Hook
, PDESKTOP pdo
)
795 int HookId
= Hook
->HookId
;
798 Elem
= Hook
->Chain
.Flink
;
799 if (Elem
!= &pdo
->pDeskInfo
->aphkStart
[HOOKID_TO_INDEX(HookId
)])
800 return CONTAINING_RECORD(Elem
, HOOK
, Chain
);
804 /* find the next hook in the chain */
807 IntGetNextHook(PHOOK Hook
)
809 int HookId
= Hook
->HookId
;
815 pti
= ((PTHREADINFO
)Hook
->Thread
->Tcb
.Win32Thread
);
817 Elem
= Hook
->Chain
.Flink
;
818 if (Elem
!= &pti
->aphkStart
[HOOKID_TO_INDEX(HookId
)])
819 return CONTAINING_RECORD(Elem
, HOOK
, Chain
);
823 pti
= PsGetCurrentThreadWin32Thread();
824 return IntGetNextGlobalHook(Hook
, pti
->rpdesk
);
829 /* free a hook, removing it from its chain */
833 IntFreeHook(PHOOK Hook
)
835 RemoveEntryList(&Hook
->Chain
);
836 if (Hook
->ModuleName
.Buffer
)
838 ExFreePoolWithTag(Hook
->ModuleName
.Buffer
, TAG_HOOK
);
839 Hook
->ModuleName
.Buffer
= NULL
;
842 UserDeleteObject(UserHMGetHandle(Hook
), otHook
);
845 /* remove a hook, freeing it from the chain */
849 IntRemoveHook(PHOOK Hook
)
855 HookId
= Hook
->HookId
;
857 if (Hook
->Thread
) // Local
859 pti
= ((PTHREADINFO
)Hook
->Thread
->Tcb
.Win32Thread
);
863 if ( IsListEmpty(&pti
->aphkStart
[HOOKID_TO_INDEX(HookId
)]) )
865 pti
->fsHooks
&= ~HOOKID_TO_FLAG(HookId
);
868 GetWin32ClientInfo()->fsHooks
= pti
->fsHooks
;
870 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
881 pdo
= IntGetActiveDesktop();
885 IsListEmpty(&pdo
->pDeskInfo
->aphkStart
[HOOKID_TO_INDEX(HookId
)]) )
887 pdo
->pDeskInfo
->fsHooks
&= ~HOOKID_TO_FLAG(HookId
);
896 HOOK_DestroyThreadHooks(PETHREAD Thread
)
904 pti
= Thread
->Tcb
.Win32Thread
;
905 pdo
= IntGetActiveDesktop();
909 DPRINT1("Kill Thread Hooks pti 0x%x pdo 0x%x\n",pti
,pdo
);
912 ObReferenceObject(Thread
);
914 // Local Thread cleanup.
917 for (HookId
= WH_MINHOOK
; HookId
<= WH_MAXHOOK
; HookId
++)
919 PLIST_ENTRY pLLE
= &pti
->aphkStart
[HOOKID_TO_INDEX(HookId
)];
921 if (IsListEmpty(pLLE
)) continue;
924 HookObj
= CONTAINING_RECORD(pElem
, HOOK
, Chain
);
928 if (IntRemoveHook(HookObj
)) break;
929 pElem
= HookObj
->Chain
.Flink
;
930 HookObj
= CONTAINING_RECORD(pElem
, HOOK
, Chain
);
932 while (pElem
!= pLLE
);
936 // Global search based on Thread and cleanup.
937 if (pdo
->pDeskInfo
->fsHooks
)
939 for (HookId
= WH_MINHOOK
; HookId
<= WH_MAXHOOK
; HookId
++)
941 PLIST_ENTRY pGLE
= &pdo
->pDeskInfo
->aphkStart
[HOOKID_TO_INDEX(HookId
)];
943 if (IsListEmpty(pGLE
)) continue;
946 HookObj
= CONTAINING_RECORD(pElem
, HOOK
, Chain
);
950 if (HookObj
->head
.pti
== pti
)
952 if (IntRemoveHook(HookObj
)) break;
954 pElem
= HookObj
->Chain
.Flink
;
955 HookObj
= CONTAINING_RECORD(pElem
, HOOK
, Chain
);
957 while (pElem
!= pGLE
);
960 ObDereferenceObject(Thread
);
965 Win32k Kernel Space Hook Caller.
969 co_HOOK_CallHooks( INT HookId
,
974 PHOOK Hook
, SaveHook
;
976 PCLIENTINFO ClientInfo
;
977 PLIST_ENTRY pLLE
, pGLE
;
979 BOOL Local
= FALSE
, Global
= FALSE
;
982 ASSERT(WH_MINHOOK
<= HookId
&& HookId
<= WH_MAXHOOK
);
984 pti
= PsGetCurrentThreadWin32Thread();
985 if (!pti
|| !pti
->rpdesk
|| !pti
->rpdesk
->pDeskInfo
)
987 pdo
= IntGetActiveDesktop();
988 /* If KeyboardThread|MouseThread|(RawInputThread or RIT) aka system threads,
989 pti->fsHooks most likely, is zero. So process KbT & MsT to "send" the message.
991 if ( !pti
|| !pdo
|| (!(HookId
== WH_KEYBOARD_LL
) && !(HookId
== WH_MOUSE_LL
)) )
999 if ( pti
->TIF_flags
& (TIF_INCLEANUP
|TIF_DISABLEHOOKS
))
1002 if ( ISITHOOKED(HookId
) )
1004 DPRINT("Local Hooker %d\n", HookId
);
1008 if ( pdo
->pDeskInfo
->fsHooks
& HOOKID_TO_FLAG(HookId
) )
1010 DPRINT("Global Hooker %d\n", HookId
);
1014 if ( !Local
&& !Global
) goto Exit
; // No work!
1018 /* SetWindowHookEx sorts out the Thread issue by placing the Hook to
1019 the correct Thread if not NULL.
1023 pLLE
= &pti
->aphkStart
[HOOKID_TO_INDEX(HookId
)];
1024 Hook
= IntGetFirstHook(pLLE
);
1027 DPRINT1("No Local Hook Found!\n");
1030 ObReferenceObject(Hook
->Thread
);
1032 ClientInfo
= pti
->pClientInfo
;
1033 SaveHook
= pti
->sphkCurrent
;
1035 /* Load it for the next call. */
1036 pti
->sphkCurrent
= Hook
;
1037 Hook
->phkNext
= IntGetNextHook(Hook
);
1042 ClientInfo
->phkCurrent
= Hook
;
1044 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1046 ClientInfo
= NULL
; // Don't bother next run.
1050 Result
= co_IntCallHookProc( HookId
,
1061 ClientInfo
->phkCurrent
= SaveHook
;
1063 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1068 pti
->sphkCurrent
= SaveHook
;
1069 Hook
->phkNext
= NULL
;
1070 ObDereferenceObject(Hook
->Thread
);
1075 PTHREADINFO ptiHook
;
1077 pGLE
= &pdo
->pDeskInfo
->aphkStart
[HOOKID_TO_INDEX(HookId
)];
1078 Hook
= IntGetFirstHook(pGLE
);
1081 DPRINT1("No Global Hook Found!\n");
1084 /* Performance goes down the drain. If more hooks are associated to this
1085 * hook ID, this will have to post to each of the thread message queues
1086 * or make a direct call.
1090 /* Hook->Thread is null, we hax around this with Hook->head.pti. */
1091 ptiHook
= Hook
->head
.pti
;
1093 /* "Global hook monitors messages for all threads in the same desktop
1094 * as the calling thread."
1096 if ( ptiHook
->TIF_flags
& (TIF_INCLEANUP
|TIF_DISABLEHOOKS
) ||
1097 ptiHook
->rpdesk
!= pdo
)
1099 DPRINT("Next Hook 0x%x, 0x%x\n",ptiHook
->rpdesk
,pdo
);
1100 Hook
= IntGetNextGlobalHook(Hook
, pdo
);
1104 // Lockup the thread while this links through user world.
1105 ObReferenceObject(ptiHook
->pEThread
);
1106 if (ptiHook
!= pti
)
1108 /* This fixed the ros regtest. Wine does this too. Need more time
1109 to investigate this. MSDN "Hooks Overview" can't be wrong?
1111 if (HookId
== WH_KEYBOARD_LL
|| HookId
== WH_MOUSE_LL
)
1113 DPRINT("\nGlobal Hook posting to another Thread! %d\n",HookId
);
1114 Result
= IntCallLowLevelHook(Hook
, Code
, wParam
, lParam
);
1118 { /* Make the direct call. */
1119 DPRINT("\nLocal Hook calling to Thread! %d\n",HookId
);
1120 Result
= co_IntCallHookProc( HookId
,
1128 ObDereferenceObject(ptiHook
->pEThread
);
1129 Hook
= IntGetNextGlobalHook(Hook
, pdo
);
1132 DPRINT("Ret: Global HookId %d Result 0x%x\n", HookId
,Result
);
1140 IntUnhookWindowsHook(int HookId
, HOOKPROC pfnFilterProc
)
1143 PLIST_ENTRY pLLE
, pLE
;
1144 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1146 if (HookId
< WH_MINHOOK
|| WH_MAXHOOK
< HookId
)
1148 SetLastWin32Error(ERROR_INVALID_HOOK_FILTER
);
1154 pLLE
= &pti
->aphkStart
[HOOKID_TO_INDEX(HookId
)];
1156 if (IsListEmpty(pLLE
)) return FALSE
;
1159 Hook
= CONTAINING_RECORD(pLE
, HOOK
, Chain
);
1163 if (Hook
->Proc
== pfnFilterProc
)
1165 if (Hook
->head
.pti
== pti
)
1167 IntRemoveHook(Hook
);
1168 UserDereferenceObject(Hook
);
1173 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1177 pLE
= Hook
->Chain
.Flink
;
1178 Hook
= CONTAINING_RECORD(pLE
, HOOK
, Chain
);
1180 while (pLE
!= pLLE
);
1186 * Support for compatibility only? Global hooks are processed in kernel space.
1187 * This is very thread specific! Never seeing applications with more than one
1188 * hook per thread installed. Most of the applications are Global hookers and
1189 * associated with just one hook Id. Maybe it's for diagnostic testing or a
1190 * throw back to 3.11?
1194 NtUserCallNextHookEx( int Code
,
1200 PHOOK HookObj
, NextObj
;
1201 PCLIENTINFO ClientInfo
;
1202 LRESULT lResult
= 0;
1203 DECLARE_RETURN(LRESULT
);
1205 DPRINT("Enter NtUserCallNextHookEx\n");
1206 UserEnterExclusive();
1208 pti
= GetW32ThreadInfo();
1210 HookObj
= pti
->sphkCurrent
;
1212 if (!HookObj
) RETURN( 0);
1214 NextObj
= HookObj
->phkNext
;
1216 pti
->sphkCurrent
= NextObj
;
1217 ClientInfo
= pti
->pClientInfo
;
1220 ClientInfo
->phkCurrent
= NextObj
;
1222 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1228 /* Now in List run down. */
1229 if (ClientInfo
&& NextObj
)
1231 NextObj
->phkNext
= IntGetNextHook(NextObj
);
1232 lResult
= UserCallNextHookEx( NextObj
, Code
, wParam
, lParam
, NextObj
->Ansi
);
1237 DPRINT("Leave NtUserCallNextHookEx, ret=%i\n",_ret_
);
1244 NtUserSetWindowsHookAW( int idHook
,
1249 UNICODE_STRING USModuleName
;
1251 RtlInitUnicodeString(&USModuleName
, NULL
);
1252 ThreadId
= PtrToUint(NtCurrentTeb()->ClientId
.UniqueThread
);
1254 return NtUserSetWindowsHookEx( NULL
,
1264 NtUserSetWindowsHookEx( HINSTANCE Mod
,
1265 PUNICODE_STRING UnsafeModuleName
,
1271 PWINSTATION_OBJECT WinStaObj
;
1273 UNICODE_STRING ModuleName
;
1276 PETHREAD Thread
= NULL
;
1277 PTHREADINFO ptiCurrent
, pti
= NULL
;
1279 DECLARE_RETURN(HHOOK
);
1281 DPRINT("Enter NtUserSetWindowsHookEx\n");
1282 UserEnterExclusive();
1284 ptiCurrent
= GetW32ThreadInfo();
1286 if (HookId
< WH_MINHOOK
|| WH_MAXHOOK
< HookId
)
1288 SetLastWin32Error(ERROR_INVALID_HOOK_FILTER
);
1294 SetLastWin32Error(ERROR_INVALID_FILTER_PROC
);
1298 if (ThreadId
) /* thread-local hook */
1300 if ( HookId
== WH_JOURNALRECORD
||
1301 HookId
== WH_JOURNALPLAYBACK
||
1302 HookId
== WH_KEYBOARD_LL
||
1303 HookId
== WH_MOUSE_LL
||
1304 HookId
== WH_SYSMSGFILTER
)
1306 DPRINT1("Local hook installing Global HookId: %d\n",HookId
);
1307 /* these can only be global */
1308 SetLastWin32Error(ERROR_GLOBAL_ONLY_HOOK
);
1312 if (!NT_SUCCESS(PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
) ThreadId
, &Thread
)))
1314 DPRINT1("Invalid thread id 0x%x\n", ThreadId
);
1315 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1319 pti
= Thread
->Tcb
.Win32Thread
;
1321 ObDereferenceObject(Thread
);
1323 if ( pti
->rpdesk
!= ptiCurrent
->rpdesk
) // gptiCurrent->rpdesk)
1325 DPRINT1("Local hook wrong desktop HookId: %d\n",HookId
);
1326 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1330 if (Thread
->ThreadsProcess
!= PsGetCurrentProcess())
1333 (HookId
== WH_GETMESSAGE
||
1334 HookId
== WH_CALLWNDPROC
||
1336 HookId
== WH_HARDWARE
||
1337 HookId
== WH_DEBUG
||
1338 HookId
== WH_SHELL
||
1339 HookId
== WH_FOREGROUNDIDLE
||
1340 HookId
== WH_CALLWNDPROCRET
) )
1342 DPRINT1("Local hook needs hMod HookId: %d\n",HookId
);
1343 SetLastWin32Error(ERROR_HOOK_NEEDS_HMOD
);
1347 if ( (pti
->TIF_flags
& (TIF_CSRSSTHREAD
|TIF_SYSTEMTHREAD
)) &&
1348 (HookId
== WH_GETMESSAGE
||
1349 HookId
== WH_CALLWNDPROC
||
1351 HookId
== WH_HARDWARE
||
1352 HookId
== WH_DEBUG
||
1353 HookId
== WH_SHELL
||
1354 HookId
== WH_FOREGROUNDIDLE
||
1355 HookId
== WH_CALLWNDPROCRET
) )
1357 SetLastWin32Error(ERROR_HOOK_TYPE_NOT_ALLOWED
);
1362 else /* system-global hook */
1364 pti
= ptiCurrent
; // gptiCurrent;
1366 (HookId
== WH_GETMESSAGE
||
1367 HookId
== WH_CALLWNDPROC
||
1369 HookId
== WH_SYSMSGFILTER
||
1370 HookId
== WH_HARDWARE
||
1371 HookId
== WH_DEBUG
||
1372 HookId
== WH_SHELL
||
1373 HookId
== WH_FOREGROUNDIDLE
||
1374 HookId
== WH_CALLWNDPROCRET
) )
1376 DPRINT1("Global hook needs hMod HookId: %d\n",HookId
);
1377 SetLastWin32Error(ERROR_HOOK_NEEDS_HMOD
);
1382 Status
= IntValidateWindowStationHandle( PsGetCurrentProcess()->Win32WindowStation
,
1387 if (!NT_SUCCESS(Status
))
1389 SetLastNtError(Status
);
1392 ObDereferenceObject(WinStaObj
);
1394 Hook
= UserCreateObject(gHandleTable
, NULL
, &Handle
, otHook
, sizeof(HOOK
));
1401 Hook
->ihmod
= (INT
)Mod
; // Module Index from atom table, Do this for now.
1402 Hook
->Thread
= Thread
; /* Set Thread, Null is Global. */
1403 Hook
->HookId
= HookId
;
1404 Hook
->rpdesk
= pti
->rpdesk
;
1405 Hook
->phkNext
= NULL
; /* Dont use as a chain! Use link lists for chaining. */
1406 Hook
->Proc
= HookProc
;
1409 DPRINT("Set Hook Desk 0x%x DeskInfo 0x%x Handle Desk 0x%x\n",pti
->rpdesk
, pti
->pDeskInfo
,Hook
->head
.rpdesk
);
1411 if (ThreadId
) /* thread-local hook */
1413 InsertHeadList(&pti
->aphkStart
[HOOKID_TO_INDEX(HookId
)], &Hook
->Chain
);
1414 pti
->sphkCurrent
= NULL
;
1415 Hook
->ptiHooked
= pti
;
1416 pti
->fsHooks
|= HOOKID_TO_FLAG(HookId
);
1418 if (pti
->pClientInfo
)
1420 if ( pti
->ppi
== ptiCurrent
->ppi
) /* gptiCurrent->ppi) */
1424 pti
->pClientInfo
->fsHooks
= pti
->fsHooks
;
1425 pti
->pClientInfo
->phkCurrent
= 0;
1427 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1434 DPRINT1("Problem writing to Local ClientInfo!\n");
1439 KeAttachProcess(&pti
->ppi
->peProcess
->Pcb
);
1442 pti
->pClientInfo
->fsHooks
= pti
->fsHooks
;
1443 pti
->pClientInfo
->phkCurrent
= 0;
1445 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1453 DPRINT1("Problem writing to Remote ClientInfo!\n");
1460 InsertHeadList(&pti
->rpdesk
->pDeskInfo
->aphkStart
[HOOKID_TO_INDEX(HookId
)], &Hook
->Chain
);
1461 Hook
->ptiHooked
= NULL
;
1462 //gptiCurrent->pDeskInfo->fsHooks |= HOOKID_TO_FLAG(HookId);
1463 pti
->rpdesk
->pDeskInfo
->fsHooks
|= HOOKID_TO_FLAG(HookId
);
1466 RtlInitUnicodeString(&Hook
->ModuleName
, NULL
);
1470 Status
= MmCopyFromCaller(&ModuleName
,
1472 sizeof(UNICODE_STRING
));
1473 if (!NT_SUCCESS(Status
))
1475 IntRemoveHook(Hook
);
1476 SetLastNtError(Status
);
1480 Hook
->ModuleName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
1481 ModuleName
.MaximumLength
,
1483 if (NULL
== Hook
->ModuleName
.Buffer
)
1485 IntRemoveHook(Hook
);
1486 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1490 Hook
->ModuleName
.MaximumLength
= ModuleName
.MaximumLength
;
1491 Status
= MmCopyFromCaller( Hook
->ModuleName
.Buffer
,
1493 ModuleName
.MaximumLength
);
1494 if (!NT_SUCCESS(Status
))
1496 ExFreePoolWithTag(Hook
->ModuleName
.Buffer
, TAG_HOOK
);
1497 Hook
->ModuleName
.Buffer
= NULL
;
1498 IntRemoveHook(Hook
);
1499 SetLastNtError(Status
);
1503 Hook
->ModuleName
.Length
= ModuleName
.Length
;
1504 /* make proc relative to the module base */
1505 Hook
->offPfn
= (ULONG_PTR
)((char *)HookProc
- (char *)Mod
);
1510 DPRINT("Installing: HookId %d Global %s\n", HookId
, !ThreadId
? "TRUE" : "FALSE");
1514 DPRINT("Leave NtUserSetWindowsHookEx, ret=%i\n",_ret_
);
1521 NtUserUnhookWindowsHookEx(HHOOK Hook
)
1524 DECLARE_RETURN(BOOL
);
1526 DPRINT("Enter NtUserUnhookWindowsHookEx\n");
1527 UserEnterExclusive();
1529 if (!(HookObj
= IntGetHookObject(Hook
)))
1531 DPRINT1("Invalid handle passed to NtUserUnhookWindowsHookEx\n");
1532 /* SetLastNtError(Status); */
1536 ASSERT(Hook
== UserHMGetHandle(HookObj
));
1538 IntRemoveHook(HookObj
);
1540 UserDereferenceObject(HookObj
);
1545 DPRINT("Leave NtUserUnhookWindowsHookEx, ret=%i\n",_ret_
);