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)
8 * Rafal Harabien (rafalh@reactos.org)
11 * 06-06-2001 CSH Created
12 * NOTE: Most of this code was adapted from Wine,
13 * Copyright (C) 2002 Alexandre Julliard
21 typedef struct _HOOKPACK
26 } HOOKPACK
, *PHOOKPACK
;
28 /* PRIVATE FUNCTIONS *********************************************************/
33 co_IntCallLowLevelHook(PHOOK Hook
,
44 ULONG_PTR uResult
= 0;
47 pti
= Hook
->Thread
->Tcb
.Win32Thread
;
51 pHP
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(HOOKPACK
), TAG_HOOK
);
56 pHP
->pHookStructs
= NULL
;
58 // This prevents stack corruption from the caller.
61 case WH_JOURNALPLAYBACK
:
62 case WH_JOURNALRECORD
:
64 Size
= sizeof(EVENTMSG
);
67 Size
= sizeof(KBDLLHOOKSTRUCT
);
70 Size
= sizeof(MSLLHOOKSTRUCT
);
75 Size
= sizeof(MOUSEHOOKSTRUCT
);
85 pHP
->pHookStructs
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_HOOK
);
86 if (pHP
->pHookStructs
) RtlCopyMemory(pHP
->pHookStructs
, (PVOID
)lParam
, Size
);
89 /* FIXME should get timeout from
90 * HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */
91 Status
= co_MsqSendMessage( pti
->MessageQueue
,
92 IntToPtr(Code
), // hWnd
100 if (!NT_SUCCESS(Status
))
102 DPRINT1("Error Hook Call SendMsg. %d Status: 0x%x\n", Hook
->HookId
, Status
);
103 if (pHP
->pHookStructs
) ExFreePoolWithTag(pHP
->pHookStructs
, TAG_HOOK
);
104 ExFreePoolWithTag(pHP
, TAG_HOOK
);
106 return NT_SUCCESS(Status
) ? uResult
: 0;
111 // Dispatch MsgQueue Hook Call processor!
115 co_CallHook( INT HookId
,
122 PHOOKPACK pHP
= (PHOOKPACK
)lParam
;
125 lParam
= pHP
->lParam
;
129 case WH_JOURNALPLAYBACK
:
130 case WH_JOURNALRECORD
:
135 lParam
= (LPARAM
)pHP
->pHookStructs
;
139 /* The odds are high for this to be a Global call. */
140 Result
= co_IntCallHookProc( HookId
,
148 /* The odds so high, no one is waiting for the results. */
149 if (pHP
->pHookStructs
) ExFreePoolWithTag(pHP
->pHookStructs
, TAG_HOOK
);
150 ExFreePoolWithTag(pHP
, TAG_HOOK
);
157 co_HOOK_CallHookNext( PHOOK Hook
,
162 DPRINT("Calling Next HOOK %d\n", Hook
->HookId
);
164 return co_IntCallHookProc( Hook
->HookId
,
176 co_IntCallDebugHook(PHOOK Hook
,
185 PVOID HooklParam
= NULL
;
192 ProbeForRead((PVOID
)lParam
,
193 sizeof(DEBUGHOOKINFO
),
196 RtlCopyMemory(&Debug
,
198 sizeof(DEBUGHOOKINFO
));
200 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
208 DPRINT1("HOOK WH_DEBUG read from lParam ERROR!\n");
213 return lResult
; /* Need lParam! */
221 case HCBT_CLICKSKIPPED
:
222 Size
= sizeof(MOUSEHOOKSTRUCTEX
);
230 Size
= sizeof(CBTACTIVATESTRUCT
);
233 case HCBT_CREATEWND
: /* Handle Ansi? */
234 Size
= sizeof(CBT_CREATEWND
);
235 /* What shall we do? Size += sizeof(HOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS); same as CREATESTRUCTEX */
239 Size
= sizeof(LPARAM
);
245 Size
= sizeof(MSLLHOOKSTRUCT
);
249 Size
= sizeof(KBDLLHOOKSTRUCT
);
253 case WH_SYSMSGFILTER
:
258 case WH_JOURNALPLAYBACK
:
259 case WH_JOURNALRECORD
:
260 Size
= sizeof(EVENTMSG
);
263 case WH_FOREGROUNDIDLE
:
267 Size
= sizeof(LPARAM
);
270 if (Size
> sizeof(LPARAM
))
271 HooklParam
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_HOOK
);
277 ProbeForRead((PVOID
)Debug
.lParam
,
281 RtlCopyMemory(HooklParam
,
285 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
293 DPRINT1("HOOK WH_DEBUG read from Debug.lParam ERROR!\n");
294 ExFreePool(HooklParam
);
299 if (HooklParam
) Debug
.lParam
= (LPARAM
)HooklParam
;
300 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Debug
);
301 if (HooklParam
) ExFreePoolWithTag(HooklParam
, TAG_HOOK
);
309 co_UserCallNextHookEx(PHOOK Hook
,
318 /* Handle this one first. */
319 if ((Hook
->HookId
== WH_MOUSE
) ||
320 (Hook
->HookId
== WH_CBT
&& Code
== HCBT_CLICKSKIPPED
))
322 MOUSEHOOKSTRUCTEX Mouse
;
327 ProbeForRead((PVOID
)lParam
,
328 sizeof(MOUSEHOOKSTRUCTEX
),
331 RtlCopyMemory(&Mouse
,
333 sizeof(MOUSEHOOKSTRUCTEX
));
335 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
343 DPRINT1("HOOK WH_MOUSE read from lParam ERROR!\n");
349 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Mouse
);
359 MSLLHOOKSTRUCT Mouse
;
365 ProbeForRead((PVOID
)lParam
,
366 sizeof(MSLLHOOKSTRUCT
),
369 RtlCopyMemory(&Mouse
,
371 sizeof(MSLLHOOKSTRUCT
));
373 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
381 DPRINT1("HOOK WH_MOUSE_LL read from lParam ERROR!\n");
387 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Mouse
);
394 KBDLLHOOKSTRUCT Keyboard
;
400 ProbeForRead((PVOID
)lParam
,
401 sizeof(KBDLLHOOKSTRUCT
),
404 RtlCopyMemory(&Keyboard
,
406 sizeof(KBDLLHOOKSTRUCT
));
408 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
416 DPRINT1("HOOK WH_KEYBORD_LL read from lParam ERROR!\n");
422 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Keyboard
);
428 case WH_SYSMSGFILTER
:
437 ProbeForRead((PVOID
)lParam
,
445 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
453 DPRINT1("HOOK WH_XMESSAGEX read from lParam ERROR!\n");
459 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&Msg
);
461 if (lParam
&& (Hook
->HookId
== WH_GETMESSAGE
))
465 ProbeForWrite((PVOID
)lParam
,
469 RtlCopyMemory((PVOID
)lParam
,
473 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
481 DPRINT1("HOOK WH_GETMESSAGE write to lParam ERROR!\n");
489 DPRINT("HOOK WH_CBT!\n");
494 LPCBT_CREATEWNDW pcbtcww
= (LPCBT_CREATEWNDW
)lParam
;
496 DPRINT("HOOK HCBT_CREATEWND\n");
501 ProbeForRead( pcbtcww
,
502 sizeof(CBT_CREATEWNDA
),
504 ProbeForWrite(pcbtcww
->lpcs
,
505 sizeof(CREATESTRUCTA
),
507 ProbeForRead( pcbtcww
->lpcs
->lpszName
,
511 if (!IS_ATOM(pcbtcww
->lpcs
->lpszClass
))
513 ProbeForRead( pcbtcww
->lpcs
->lpszClass
,
520 ProbeForRead( pcbtcww
,
521 sizeof(CBT_CREATEWNDW
),
523 ProbeForWrite(pcbtcww
->lpcs
,
524 sizeof(CREATESTRUCTW
),
526 ProbeForRead( pcbtcww
->lpcs
->lpszName
,
530 if (!IS_ATOM(pcbtcww
->lpcs
->lpszClass
))
532 ProbeForRead( pcbtcww
->lpcs
->lpszClass
,
538 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
546 DPRINT1("HOOK HCBT_CREATEWND write ERROR!\n");
548 /* The next call handles the structures. */
549 if (!BadChk
&& Hook
->Proc
)
551 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, lParam
);
560 DPRINT("HOOK HCBT_MOVESIZE\n");
566 ProbeForRead((PVOID
)lParam
,
574 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
582 DPRINT1("HOOK HCBT_MOVESIZE read from lParam ERROR!\n");
588 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&rt
);
595 CBTACTIVATESTRUCT CbAs
;
597 DPRINT("HOOK HCBT_ACTIVATE\n");
602 ProbeForRead((PVOID
)lParam
,
603 sizeof(CBTACTIVATESTRUCT
),
608 sizeof(CBTACTIVATESTRUCT
));
610 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
618 DPRINT1("HOOK HCBT_ACTIVATE read from lParam ERROR!\n");
624 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)&CbAs
);
629 /* The rest just use default. */
631 DPRINT("HOOK HCBT_ %d\n",Code
);
632 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, lParam
);
637 Note WH_JOURNALPLAYBACK,
638 "To have the system wait before processing the message, the return value
639 must be the amount of time, in clock ticks, that the system should wait."
641 case WH_JOURNALPLAYBACK
:
642 case WH_JOURNALRECORD
:
650 ProbeForRead((PVOID
)lParam
,
654 RtlCopyMemory(&EventMsg
,
658 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
666 DPRINT1("HOOK WH_JOURNAL read from lParam ERROR!\n");
672 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, (LPARAM
)(lParam
? &EventMsg
: NULL
));
678 ProbeForWrite((PVOID
)lParam
,
682 RtlCopyMemory((PVOID
)lParam
,
686 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
694 DPRINT1("HOOK WH_JOURNAL write to lParam ERROR!\n");
702 lResult
= co_IntCallDebugHook(Hook
, Code
, wParam
, lParam
, Ansi
);
706 * Default the rest like, WH_FOREGROUNDIDLE, WH_KEYBOARD and WH_SHELL.
708 case WH_FOREGROUNDIDLE
:
711 lResult
= co_HOOK_CallHookNext(Hook
, Code
, wParam
, lParam
);
715 DPRINT1("Unsupported HOOK Id -> %d\n",Hook
->HookId
);
723 IntGetHookObject(HHOOK hHook
)
729 EngSetLastError(ERROR_INVALID_HOOK_HANDLE
);
733 Hook
= (PHOOK
)UserGetObject(gHandleTable
, hHook
, otHook
);
736 EngSetLastError(ERROR_INVALID_HOOK_HANDLE
);
740 UserReferenceObject(Hook
);
748 IntGetGlobalHookHandles(PDESKTOP pdo
, int HookId
)
750 PLIST_ENTRY pLastHead
, pElem
;
755 pLastHead
= &pdo
->pDeskInfo
->aphkStart
[HOOKID_TO_INDEX(HookId
)];
756 for (pElem
= pLastHead
->Flink
; pElem
!= pLastHead
; pElem
= pElem
->Flink
)
759 pList
= ExAllocatePoolWithTag(PagedPool
, (cHooks
+ 1) * sizeof(HHOOK
), TAG_HOOK
);
762 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
766 for (pElem
= pLastHead
->Flink
; pElem
!= pLastHead
; pElem
= pElem
->Flink
)
768 pHook
= CONTAINING_RECORD(pElem
, HOOK
, Chain
);
769 pList
[i
++] = pHook
->head
.h
;
776 /* find the next hook in the chain */
779 IntGetNextHook(PHOOK Hook
)
781 int HookId
= Hook
->HookId
;
782 PLIST_ENTRY pLastHead
, pElem
;
787 pti
= ((PTHREADINFO
)Hook
->Thread
->Tcb
.Win32Thread
);
788 pLastHead
= &pti
->aphkStart
[HOOKID_TO_INDEX(HookId
)];
792 pti
= PsGetCurrentThreadWin32Thread();
793 pLastHead
= &pti
->rpdesk
->pDeskInfo
->aphkStart
[HOOKID_TO_INDEX(HookId
)];
796 pElem
= Hook
->Chain
.Flink
;
797 if (pElem
!= pLastHead
)
798 return CONTAINING_RECORD(pElem
, HOOK
, Chain
);
802 /* free a hook, removing it from its chain */
806 IntFreeHook(PHOOK Hook
)
808 RemoveEntryList(&Hook
->Chain
);
809 if (Hook
->ModuleName
.Buffer
)
811 ExFreePoolWithTag(Hook
->ModuleName
.Buffer
, TAG_HOOK
);
812 Hook
->ModuleName
.Buffer
= NULL
;
815 UserDeleteObject(UserHMGetHandle(Hook
), otHook
);
818 /* remove a hook, freeing it from the chain */
822 IntRemoveHook(PHOOK Hook
)
828 HookId
= Hook
->HookId
;
830 if (Hook
->Thread
) // Local
832 pti
= ((PTHREADINFO
)Hook
->Thread
->Tcb
.Win32Thread
);
836 if ( IsListEmpty(&pti
->aphkStart
[HOOKID_TO_INDEX(HookId
)]) )
838 pti
->fsHooks
&= ~HOOKID_TO_FLAG(HookId
);
841 GetWin32ClientInfo()->fsHooks
= pti
->fsHooks
;
843 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
853 pdo
= IntGetActiveDesktop();
857 IsListEmpty(&pdo
->pDeskInfo
->aphkStart
[HOOKID_TO_INDEX(HookId
)]) )
859 pdo
->pDeskInfo
->fsHooks
&= ~HOOKID_TO_FLAG(HookId
);
866 HOOK_DestroyThreadHooks(PETHREAD Thread
)
874 pti
= Thread
->Tcb
.Win32Thread
;
875 pdo
= IntGetActiveDesktop();
879 DPRINT1("Kill Thread Hooks pti 0x%x pdo 0x%x\n",pti
,pdo
);
883 // Local Thread cleanup.
886 for (HookId
= WH_MINHOOK
; HookId
<= WH_MAXHOOK
; HookId
++)
888 PLIST_ENTRY pLastHead
= &pti
->aphkStart
[HOOKID_TO_INDEX(HookId
)];
890 pElem
= pLastHead
->Flink
;
891 while (pElem
!= pLastHead
)
893 HookObj
= CONTAINING_RECORD(pElem
, HOOK
, Chain
);
894 pElem
= HookObj
->Chain
.Flink
; // get next element before hook is destroyed
895 IntRemoveHook(HookObj
);
900 // Global search based on Thread and cleanup.
901 if (pdo
->pDeskInfo
->fsHooks
)
903 for (HookId
= WH_MINHOOK
; HookId
<= WH_MAXHOOK
; HookId
++)
905 PLIST_ENTRY pGLE
= &pdo
->pDeskInfo
->aphkStart
[HOOKID_TO_INDEX(HookId
)];
908 while (pElem
!= pGLE
)
910 HookObj
= CONTAINING_RECORD(pElem
, HOOK
, Chain
);
911 pElem
= HookObj
->Chain
.Flink
; // get next element before hook is destroyed
912 if (HookObj
->head
.pti
== pti
)
914 IntRemoveHook(HookObj
);
923 Win32k Kernel Space Hook Caller.
927 co_HOOK_CallHooks( INT HookId
,
932 PHOOK Hook
, SaveHook
;
934 PCLIENTINFO ClientInfo
;
935 PLIST_ENTRY pLastHead
;
937 BOOL Local
= FALSE
, Global
= FALSE
;
939 USER_REFERENCE_ENTRY Ref
;
941 ASSERT(WH_MINHOOK
<= HookId
&& HookId
<= WH_MAXHOOK
);
943 pti
= PsGetCurrentThreadWin32Thread();
944 if (!pti
|| !pti
->rpdesk
|| !pti
->rpdesk
->pDeskInfo
)
946 pdo
= IntGetActiveDesktop();
947 /* If KeyboardThread|MouseThread|(RawInputThread or RIT) aka system threads,
948 pti->fsHooks most likely, is zero. So process KbT & MsT to "send" the message.
950 if ( !pti
|| !pdo
|| (!(HookId
== WH_KEYBOARD_LL
) && !(HookId
== WH_MOUSE_LL
)) )
952 DPRINT("No PDO %d\n", HookId
);
961 if ( pti
->TIF_flags
& (TIF_INCLEANUP
|TIF_DISABLEHOOKS
))
963 DPRINT("Hook Thread dead %d\n", HookId
);
967 if ( ISITHOOKED(HookId
) )
969 DPRINT("Local Hooker %d\n", HookId
);
973 if ( pdo
->pDeskInfo
->fsHooks
& HOOKID_TO_FLAG(HookId
) )
975 DPRINT("Global Hooker %d\n", HookId
);
979 if ( !Local
&& !Global
) goto Exit
; // No work!
983 /* SetWindowHookEx sorts out the Thread issue by placing the Hook to
984 the correct Thread if not NULL.
988 pLastHead
= &pti
->aphkStart
[HOOKID_TO_INDEX(HookId
)];
989 if (IsListEmpty(pLastHead
))
991 DPRINT1("No Local Hook Found!\n");
995 Hook
= CONTAINING_RECORD(pLastHead
->Flink
, HOOK
, Chain
);
996 UserRefObjectCo(Hook
, &Ref
);
998 ClientInfo
= pti
->pClientInfo
;
999 SaveHook
= pti
->sphkCurrent
;
1000 /* Note: Setting pti->sphkCurrent will also lock the next hook to this
1001 * hook ID. So, the CallNextHookEx will only call to that hook ID
1002 * chain anyway. For Thread Hooks....
1005 /* Load it for the next call. */
1006 pti
->sphkCurrent
= Hook
;
1007 Hook
->phkNext
= IntGetNextHook(Hook
);
1012 ClientInfo
->phkCurrent
= Hook
;
1014 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1016 ClientInfo
= NULL
; // Don't bother next run.
1020 Result
= co_IntCallHookProc( HookId
,
1031 ClientInfo
->phkCurrent
= SaveHook
;
1033 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1038 pti
->sphkCurrent
= SaveHook
;
1039 Hook
->phkNext
= NULL
;
1040 UserDerefObjectCo(Hook
);
1045 PTHREADINFO ptiHook
;
1046 HHOOK
*pHookHandles
;
1049 /* Keep hooks in array because hooks can be destroyed in user world */
1050 pHookHandles
= IntGetGlobalHookHandles(pdo
, HookId
);
1054 /* Performance goes down the drain. If more hooks are associated to this
1055 * hook ID, this will have to post to each of the thread message queues
1056 * or make a direct call.
1058 for(i
= 0; pHookHandles
[i
]; ++i
)
1060 Hook
= (PHOOK
)UserGetObject(gHandleTable
, pHookHandles
[i
], otHook
);
1063 DPRINT1("Invalid hook!\n");
1066 UserRefObjectCo(Hook
, &Ref
);
1068 /* Hook->Thread is null, we hax around this with Hook->head.pti. */
1069 ptiHook
= Hook
->head
.pti
;
1071 if ( (pti
->TIF_flags
& TIF_DISABLEHOOKS
) || (ptiHook
->TIF_flags
& TIF_INCLEANUP
))
1073 DPRINT("Next Hook 0x%x, 0x%x\n", ptiHook
->rpdesk
, pdo
);
1077 if (ptiHook
!= pti
)
1080 if ( HookId
== WH_JOURNALPLAYBACK
|| // 1 | 0
1081 HookId
== WH_JOURNALRECORD
|| // 1 | 0
1082 HookId
== WH_KEYBOARD
|| // 1 | 200
1083 HookId
== WH_MOUSE
|| // 1 | 200
1084 HookId
== WH_KEYBOARD_LL
|| // 0 | 300
1085 HookId
== WH_MOUSE_LL
) // 0 | 300
1087 DPRINT("\nGlobal Hook posting to another Thread! %d\n", HookId
);
1088 Result
= co_IntCallLowLevelHook(Hook
, Code
, wParam
, lParam
);
1092 { /* Make the direct call. */
1093 Result
= co_IntCallHookProc( HookId
,
1101 UserDerefObjectCo(Hook
);
1103 ExFreePoolWithTag(pHookHandles
, TAG_HOOK
);
1104 DPRINT("Ret: Global HookId %d Result 0x%x\n", HookId
, Result
);
1112 IntUnhookWindowsHook(int HookId
, HOOKPROC pfnFilterProc
)
1115 PLIST_ENTRY pLastHead
, pElement
;
1116 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1118 if (HookId
< WH_MINHOOK
|| WH_MAXHOOK
< HookId
)
1120 EngSetLastError(ERROR_INVALID_HOOK_FILTER
);
1126 pLastHead
= &pti
->aphkStart
[HOOKID_TO_INDEX(HookId
)];
1128 pElement
= pLastHead
->Flink
;
1129 while (pElement
!= pLastHead
)
1131 Hook
= CONTAINING_RECORD(pElement
, HOOK
, Chain
);
1133 if (Hook
->Proc
== pfnFilterProc
)
1135 if (Hook
->head
.pti
== pti
)
1137 IntRemoveHook(Hook
);
1138 UserDereferenceObject(Hook
);
1143 EngSetLastError(ERROR_ACCESS_DENIED
);
1148 pElement
= Hook
->Chain
.Flink
;
1155 * Support for compatibility only? Global hooks are processed in kernel space.
1156 * This is very thread specific! Never seeing applications with more than one
1157 * hook per thread installed. Most of the applications are Global hookers and
1158 * associated with just one hook Id. Maybe it's for diagnostic testing or a
1159 * throw back to 3.11?
1163 NtUserCallNextHookEx( int Code
,
1169 PHOOK HookObj
, NextObj
;
1170 PCLIENTINFO ClientInfo
;
1171 LRESULT lResult
= 0;
1172 DECLARE_RETURN(LRESULT
);
1174 DPRINT("Enter NtUserCallNextHookEx\n");
1175 UserEnterExclusive();
1177 pti
= GetW32ThreadInfo();
1179 HookObj
= pti
->sphkCurrent
;
1181 if (!HookObj
) RETURN( 0);
1183 NextObj
= HookObj
->phkNext
;
1185 pti
->sphkCurrent
= NextObj
;
1186 ClientInfo
= pti
->pClientInfo
;
1189 ClientInfo
->phkCurrent
= NextObj
;
1191 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1197 /* Now in List run down. */
1198 if (ClientInfo
&& NextObj
)
1200 NextObj
->phkNext
= IntGetNextHook(NextObj
);
1201 lResult
= co_UserCallNextHookEx( NextObj
, Code
, wParam
, lParam
, NextObj
->Ansi
);
1206 DPRINT("Leave NtUserCallNextHookEx, ret=%i\n",_ret_
);
1213 NtUserSetWindowsHookAW( int idHook
,
1218 UNICODE_STRING USModuleName
;
1220 RtlInitUnicodeString(&USModuleName
, NULL
);
1221 ThreadId
= PtrToUint(NtCurrentTeb()->ClientId
.UniqueThread
);
1223 return NtUserSetWindowsHookEx( NULL
,
1233 NtUserSetWindowsHookEx( HINSTANCE Mod
,
1234 PUNICODE_STRING UnsafeModuleName
,
1240 PWINSTATION_OBJECT WinStaObj
;
1242 UNICODE_STRING ModuleName
;
1245 PETHREAD Thread
= NULL
;
1246 PTHREADINFO pti
, ptiHook
= NULL
;
1247 DECLARE_RETURN(HHOOK
);
1249 DPRINT("Enter NtUserSetWindowsHookEx\n");
1250 UserEnterExclusive();
1252 pti
= PsGetCurrentThreadWin32Thread();
1254 if (HookId
< WH_MINHOOK
|| WH_MAXHOOK
< HookId
)
1256 EngSetLastError(ERROR_INVALID_HOOK_FILTER
);
1262 EngSetLastError(ERROR_INVALID_FILTER_PROC
);
1266 if (ThreadId
) /* thread-local hook */
1268 if ( HookId
== WH_JOURNALRECORD
||
1269 HookId
== WH_JOURNALPLAYBACK
||
1270 HookId
== WH_KEYBOARD_LL
||
1271 HookId
== WH_MOUSE_LL
||
1272 HookId
== WH_SYSMSGFILTER
)
1274 DPRINT1("Local hook installing Global HookId: %d\n",HookId
);
1275 /* these can only be global */
1276 EngSetLastError(ERROR_GLOBAL_ONLY_HOOK
);
1280 if (!NT_SUCCESS(PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
) ThreadId
, &Thread
)))
1282 DPRINT1("Invalid thread id 0x%x\n", ThreadId
);
1283 EngSetLastError(ERROR_INVALID_PARAMETER
);
1287 ptiHook
= Thread
->Tcb
.Win32Thread
;
1289 ObDereferenceObject(Thread
);
1291 if ( ptiHook
->rpdesk
!= pti
->rpdesk
) // gptiCurrent->rpdesk)
1293 DPRINT1("Local hook wrong desktop HookId: %d\n",HookId
);
1294 EngSetLastError(ERROR_ACCESS_DENIED
);
1298 if (Thread
->ThreadsProcess
!= PsGetCurrentProcess())
1301 (HookId
== WH_GETMESSAGE
||
1302 HookId
== WH_CALLWNDPROC
||
1304 HookId
== WH_HARDWARE
||
1305 HookId
== WH_DEBUG
||
1306 HookId
== WH_SHELL
||
1307 HookId
== WH_FOREGROUNDIDLE
||
1308 HookId
== WH_CALLWNDPROCRET
) )
1310 DPRINT1("Local hook needs hMod HookId: %d\n",HookId
);
1311 EngSetLastError(ERROR_HOOK_NEEDS_HMOD
);
1315 if ( (ptiHook
->TIF_flags
& (TIF_CSRSSTHREAD
|TIF_SYSTEMTHREAD
)) &&
1316 (HookId
== WH_GETMESSAGE
||
1317 HookId
== WH_CALLWNDPROC
||
1319 HookId
== WH_HARDWARE
||
1320 HookId
== WH_DEBUG
||
1321 HookId
== WH_SHELL
||
1322 HookId
== WH_FOREGROUNDIDLE
||
1323 HookId
== WH_CALLWNDPROCRET
) )
1325 EngSetLastError(ERROR_HOOK_TYPE_NOT_ALLOWED
);
1330 else /* system-global hook */
1332 ptiHook
= pti
; // gptiCurrent;
1334 (HookId
== WH_GETMESSAGE
||
1335 HookId
== WH_CALLWNDPROC
||
1337 HookId
== WH_SYSMSGFILTER
||
1338 HookId
== WH_HARDWARE
||
1339 HookId
== WH_DEBUG
||
1340 HookId
== WH_SHELL
||
1341 HookId
== WH_FOREGROUNDIDLE
||
1342 HookId
== WH_CALLWNDPROCRET
) )
1344 DPRINT1("Global hook needs hMod HookId: %d\n",HookId
);
1345 EngSetLastError(ERROR_HOOK_NEEDS_HMOD
);
1350 Status
= IntValidateWindowStationHandle( PsGetCurrentProcess()->Win32WindowStation
,
1355 if (!NT_SUCCESS(Status
))
1357 SetLastNtError(Status
);
1360 ObDereferenceObject(WinStaObj
);
1362 Hook
= UserCreateObject(gHandleTable
, NULL
, &Handle
, otHook
, sizeof(HOOK
));
1369 Hook
->ihmod
= (INT
)Mod
; // Module Index from atom table, Do this for now.
1370 Hook
->Thread
= Thread
; /* Set Thread, Null is Global. */
1371 Hook
->HookId
= HookId
;
1372 Hook
->rpdesk
= ptiHook
->rpdesk
;
1373 Hook
->phkNext
= NULL
; /* Dont use as a chain! Use link lists for chaining. */
1374 Hook
->Proc
= HookProc
;
1377 DPRINT("Set Hook Desk 0x%x DeskInfo 0x%x Handle Desk 0x%x\n", ptiHook
->rpdesk
, ptiHook
->pDeskInfo
,Hook
->head
.rpdesk
);
1379 if (ThreadId
) /* thread-local hook */
1381 InsertHeadList(&ptiHook
->aphkStart
[HOOKID_TO_INDEX(HookId
)], &Hook
->Chain
);
1382 ptiHook
->sphkCurrent
= NULL
;
1383 Hook
->ptiHooked
= ptiHook
;
1384 ptiHook
->fsHooks
|= HOOKID_TO_FLAG(HookId
);
1386 if (ptiHook
->pClientInfo
)
1388 if ( ptiHook
->ppi
== pti
->ppi
) /* gptiCurrent->ppi) */
1392 ptiHook
->pClientInfo
->fsHooks
= ptiHook
->fsHooks
;
1393 ptiHook
->pClientInfo
->phkCurrent
= NULL
;
1395 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1397 DPRINT1("Problem writing to Local ClientInfo!\n");
1403 KeAttachProcess(&ptiHook
->ppi
->peProcess
->Pcb
);
1406 ptiHook
->pClientInfo
->fsHooks
= ptiHook
->fsHooks
;
1407 ptiHook
->pClientInfo
->phkCurrent
= NULL
;
1409 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1411 DPRINT1("Problem writing to Remote ClientInfo!\n");
1420 InsertHeadList(&ptiHook
->rpdesk
->pDeskInfo
->aphkStart
[HOOKID_TO_INDEX(HookId
)], &Hook
->Chain
);
1421 Hook
->ptiHooked
= NULL
;
1422 //gptiCurrent->pDeskInfo->fsHooks |= HOOKID_TO_FLAG(HookId);
1423 ptiHook
->rpdesk
->pDeskInfo
->fsHooks
|= HOOKID_TO_FLAG(HookId
);
1424 ptiHook
->sphkCurrent
= NULL
;
1425 ptiHook
->pClientInfo
->phkCurrent
= NULL
;
1428 RtlInitUnicodeString(&Hook
->ModuleName
, NULL
);
1432 Status
= MmCopyFromCaller(&ModuleName
,
1434 sizeof(UNICODE_STRING
));
1435 if (!NT_SUCCESS(Status
))
1437 IntRemoveHook(Hook
);
1438 SetLastNtError(Status
);
1442 Hook
->ModuleName
.Buffer
= ExAllocatePoolWithTag( PagedPool
,
1443 ModuleName
.MaximumLength
,
1445 if (NULL
== Hook
->ModuleName
.Buffer
)
1447 IntRemoveHook(Hook
);
1448 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1452 Hook
->ModuleName
.MaximumLength
= ModuleName
.MaximumLength
;
1453 Status
= MmCopyFromCaller( Hook
->ModuleName
.Buffer
,
1455 ModuleName
.MaximumLength
);
1456 if (!NT_SUCCESS(Status
))
1458 ExFreePoolWithTag(Hook
->ModuleName
.Buffer
, TAG_HOOK
);
1459 Hook
->ModuleName
.Buffer
= NULL
;
1460 IntRemoveHook(Hook
);
1461 SetLastNtError(Status
);
1465 Hook
->ModuleName
.Length
= ModuleName
.Length
;
1466 /* make proc relative to the module base */
1467 Hook
->offPfn
= (ULONG_PTR
)((char *)HookProc
- (char *)Mod
);
1472 DPRINT("Installing: HookId %d Global %s\n", HookId
, !ThreadId
? "TRUE" : "FALSE");
1476 DPRINT("Leave NtUserSetWindowsHookEx, ret=%i\n",_ret_
);
1483 NtUserUnhookWindowsHookEx(HHOOK Hook
)
1486 DECLARE_RETURN(BOOL
);
1488 DPRINT("Enter NtUserUnhookWindowsHookEx\n");
1489 UserEnterExclusive();
1491 if (!(HookObj
= IntGetHookObject(Hook
)))
1493 DPRINT1("Invalid handle passed to NtUserUnhookWindowsHookEx\n");
1494 /* SetLastNtError(Status); */
1498 ASSERT(Hook
== UserHMGetHandle(HookObj
));
1500 IntRemoveHook(HookObj
);
1502 UserDereferenceObject(HookObj
);
1507 DPRINT("Leave NtUserUnhookWindowsHookEx, ret=%i\n",_ret_
);