* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PURPOSE: Window hooks
- * FILE: subsystem/win32/win32k/ntuser/hook.c
+ * FILE: subsystems/win32/win32k/ntuser/hook.c
* PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * James Tabor (james.tabor@rectos.org)
+ *
* REVISION HISTORY:
* 06-06-2001 CSH Created
* NOTE: Most of this code was adapted from Wine,
* Copyright (C) 2002 Alexandre Julliard
*/
-#include <w32k.h>
+#include <win32k.h>
#define NDEBUG
#include <debug.h>
-static PHOOKTABLE GlobalHooks;
-
-
-/* PRIVATE FUNCTIONS *********************************************************/
-
-
-/* create a new hook table */
-static
-PHOOKTABLE
-IntAllocHookTable(void)
-{
- PHOOKTABLE Table;
- UINT i;
-
- Table = ExAllocatePoolWithTag(PagedPool, sizeof(HOOKTABLE), TAG_HOOK);
- if (NULL != Table)
- {
- for (i = 0; i < NB_HOOKS; i++)
- {
- InitializeListHead(&Table->Hooks[i]);
- Table->Counts[i] = 0;
- }
- }
-
- return Table;
-}
-
-
-PHOOK
-FASTCALL
-IntGetHookObject(HHOOK hHook)
-{
- PHOOK Hook;
-
- if (!hHook)
- {
- SetLastWin32Error(ERROR_INVALID_HOOK_HANDLE);
- return NULL;
- }
-
- Hook = (PHOOK)UserGetObject(gHandleTable, hHook, otHook);
- if (!Hook)
- {
- SetLastWin32Error(ERROR_INVALID_HOOK_HANDLE);
- return NULL;
- }
-
- ASSERT(Hook->head.cLockObj >= 0);
-
- Hook->head.cLockObj++;
-
- return Hook;
-}
-
-
-
-/* create a new hook and add it to the specified table */
-static
-PHOOK
-IntAddHook(PETHREAD Thread, int HookId, BOOLEAN Global, PWINSTATION_OBJECT WinStaObj)
-{
- PTHREADINFO W32Thread;
- PHOOK Hook;
- PHOOKTABLE Table = Global ? GlobalHooks : MsqGetHooks(((PTHREADINFO)Thread->Tcb.Win32Thread)->MessageQueue);
- HANDLE Handle;
-
- if (NULL == Table)
- {
- Table = IntAllocHookTable();
- if (NULL == Table)
- {
- return NULL;
- }
- if (Global)
- {
- GlobalHooks = Table;
- }
- else
- {
- MsqSetHooks(((PTHREADINFO)Thread->Tcb.Win32Thread)->MessageQueue, Table);
- }
- }
-
- Hook = UserCreateObject(gHandleTable, NULL, &Handle, otHook, sizeof(HOOK));
- if (NULL == Hook)
- {
- return NULL;
- }
-
- Hook->Thread = Thread;
- Hook->HookId = HookId;
-
- if (Thread)
- {
- W32Thread = ((PTHREADINFO)Thread->Tcb.Win32Thread);
- ASSERT(W32Thread != NULL);
- W32Thread->fsHooks |= HOOKID_TO_FLAG(HookId);
-
- if (W32Thread->pClientInfo)
- W32Thread->pClientInfo->fsHooks = W32Thread->fsHooks;
-
- if (W32Thread->pDeskInfo) // Do this for now.
- W32Thread->pDeskInfo->fsHooks= W32Thread->fsHooks;
-
- Hook->head.pti = W32Thread;
- Hook->head.rpdesk = W32Thread->rpdesk;
- }
-
- RtlInitUnicodeString(&Hook->ModuleName, NULL);
-
- InsertHeadList(&Table->Hooks[HOOKID_TO_INDEX(HookId)], &Hook->Chain);
-
- return Hook;
-}
-
-/* get the hook table that a given hook belongs to */
-static
-PHOOKTABLE
-FASTCALL
-IntGetTable(PHOOK Hook)
-{
- if (NULL == Hook->Thread || WH_KEYBOARD_LL == Hook->HookId ||
- WH_MOUSE_LL == Hook->HookId)
- {
- return GlobalHooks;
- }
-
- return MsqGetHooks(((PTHREADINFO)Hook->Thread->Tcb.Win32Thread)->MessageQueue);
-}
-
-/* get the first hook in the chain */
-static
-PHOOK
-FASTCALL
-IntGetFirstHook(PHOOKTABLE Table, int HookId)
-{
- PLIST_ENTRY Elem = Table->Hooks[HOOKID_TO_INDEX(HookId)].Flink;
-
- return Elem == &Table->Hooks[HOOKID_TO_INDEX(HookId)]
- ? NULL : CONTAINING_RECORD(Elem, HOOK, Chain);
-}
-
-/* find the first non-deleted hook in the chain */
-static
-PHOOK
-FASTCALL
-IntGetFirstValidHook(PHOOKTABLE Table, int HookId)
-{
- PHOOK Hook;
- PLIST_ENTRY Elem;
-
- Hook = IntGetFirstHook(Table, HookId);
-
- while (NULL != Hook && NULL == Hook->Proc)
- {
- Elem = Hook->Chain.Flink;
- Hook = (Elem == &Table->Hooks[HOOKID_TO_INDEX(HookId)]
- ? NULL : CONTAINING_RECORD(Elem, HOOK, Chain));
- }
-
- return Hook;
-}
-
-/* find the next hook in the chain, skipping the deleted ones */
-PHOOK
-FASTCALL
-IntGetNextHook(PHOOK Hook)
+typedef struct _HOOKPACK
{
- PHOOKTABLE Table = IntGetTable(Hook);
- int HookId = Hook->HookId;
- PLIST_ENTRY Elem;
-
- Elem = Hook->Chain.Flink;
- while (Elem != &Table->Hooks[HOOKID_TO_INDEX(HookId)])
- {
- Hook = CONTAINING_RECORD(Elem, HOOK, Chain);
- if (NULL != Hook->Proc)
- {
- return Hook;
- }
- }
-
- if (NULL != GlobalHooks && Table != GlobalHooks) /* now search through the global table */
- {
- return IntGetFirstValidHook(GlobalHooks, HookId);
- }
+ PHOOK pHk;
+ LPARAM lParam;
+ PVOID pHookStructs;
+} HOOKPACK, *PHOOKPACK;
- return NULL;
-}
+/* PRIVATE FUNCTIONS *********************************************************/
-/* free a hook, removing it from its chain */
static
-VOID
+LRESULT
FASTCALL
-IntFreeHook(PHOOKTABLE Table, PHOOK Hook, PWINSTATION_OBJECT WinStaObj)
-{
- RemoveEntryList(&Hook->Chain);
- RtlFreeUnicodeString(&Hook->ModuleName);
-
- /* Dereference thread if required */
- if (Hook->Flags & HOOK_THREAD_REFERENCED)
- {
- ObDereferenceObject(Hook->Thread);
- }
-
- /* Close handle */
- UserDeleteObject(UserHMGetHandle(Hook), otHook);
-}
-
-/* remove a hook, freeing it if the chain is not in use */
-static
-VOID
-IntRemoveHook(PHOOK Hook, PWINSTATION_OBJECT WinStaObj, BOOL TableAlreadyLocked)
+IntCallLowLevelHook( PHOOK Hook,
+ INT Code,
+ WPARAM wParam,
+ LPARAM lParam)
{
- PTHREADINFO W32Thread;
- PHOOKTABLE Table = IntGetTable(Hook);
-
- ASSERT(NULL != Table); // At this point this should not be null!
-
- W32Thread = ((PTHREADINFO)Hook->Thread->Tcb.Win32Thread);
- ASSERT(W32Thread != NULL);
- W32Thread->fsHooks &= ~HOOKID_TO_FLAG(Hook->HookId);
-
- GetWin32ClientInfo()->fsHooks = W32Thread->fsHooks;
-
- if (W32Thread->pDeskInfo) // Do this for now.
- W32Thread->pDeskInfo->fsHooks= W32Thread->fsHooks;
-
- if (0 != Table->Counts[HOOKID_TO_INDEX(Hook->HookId)])
- {
- Hook->Proc = NULL; /* chain is in use, just mark it and return */
- }
+ NTSTATUS Status;
+ PTHREADINFO pti;
+ PHOOKPACK pHP;
+ INT Size;
+ UINT uTimeout = 300;
+ BOOL Block = FALSE;
+ ULONG_PTR uResult = 0;
+
+ if (Hook->Thread)
+ pti = Hook->Thread->Tcb.Win32Thread;
else
- {
- IntFreeHook(Table, Hook, WinStaObj);
- }
-}
-
-/* release a hook chain, removing deleted hooks if the use count drops to 0 */
-static
-VOID
-FASTCALL
-IntReleaseHookChain(PHOOKTABLE Table, int HookId, PWINSTATION_OBJECT WinStaObj)
-{
- PLIST_ENTRY Elem;
- PHOOK HookObj;
+ pti = Hook->head.pti;
- if (NULL == Table)
- {
- return;
- }
+ pHP = ExAllocatePoolWithTag(NonPagedPool, sizeof(HOOKPACK), TAG_HOOK);
+ if (!pHP) return 0;
- /* use count shouldn't already be 0 */
- ASSERT(0 != Table->Counts[HOOKID_TO_INDEX(HookId)]);
+ pHP->pHk = Hook;
+ pHP->lParam = lParam;
+ pHP->pHookStructs = NULL;
+ Size = 0;
- if (0 == Table->Counts[HOOKID_TO_INDEX(HookId)])
+// This prevents stack corruption from the caller.
+ switch(Hook->HookId)
{
- return;
+ case WH_JOURNALPLAYBACK:
+ case WH_JOURNALRECORD:
+ uTimeout = 0;
+ Size = sizeof(EVENTMSG);
+ break;
+ case WH_KEYBOARD_LL:
+ Size = sizeof(KBDLLHOOKSTRUCT);
+ break;
+ case WH_MOUSE_LL:
+ Size = sizeof(MSLLHOOKSTRUCT);
+ break;
+ case WH_MOUSE:
+ uTimeout = 200;
+ Block = TRUE;
+ Size = sizeof(MOUSEHOOKSTRUCT);
+ break;
+ case WH_KEYBOARD:
+ uTimeout = 200;
+ Block = TRUE;
+ Size = sizeof(KBDLLHOOKSTRUCT);
+ break;
}
- if (0 == --Table->Counts[HOOKID_TO_INDEX(HookId)])
+ if (Size)
{
- Elem = Table->Hooks[HOOKID_TO_INDEX(HookId)].Flink;
-
- while (Elem != &Table->Hooks[HOOKID_TO_INDEX(HookId)])
- {
- HookObj = CONTAINING_RECORD(Elem, HOOK, Chain);
- Elem = Elem->Flink;
-
- if (NULL == HookObj->Proc)
- {
- IntFreeHook(Table, HookObj, WinStaObj);
- }
- }
+ pHP->pHookStructs = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_HOOK);
+ if (pHP->pHookStructs) RtlCopyMemory(pHP->pHookStructs, (PVOID)lParam, Size);
}
-}
-
-static
-LRESULT
-FASTCALL
-IntCallLowLevelHook(PHOOK Hook, INT Code, WPARAM wParam, LPARAM lParam)
-{
- NTSTATUS Status;
- ULONG_PTR uResult;
/* FIXME should get timeout from
* HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */
- Status = co_MsqSendMessage(((PTHREADINFO)Hook->Thread->Tcb.Win32Thread)->MessageQueue,
- IntToPtr(Code),
- Hook->HookId,
+ Status = co_MsqSendMessage( pti->MessageQueue,
+ IntToPtr(Code), // hWnd
+ Hook->HookId, // Msg
wParam,
- lParam,
- 5000,
- TRUE,
+ (LPARAM)pHP,
+ uTimeout,
+ Block,
MSQ_ISHOOK,
- &uResult);
-
+ &uResult);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Error Hook Call SendMsg. %d Status: 0x%x\n", Hook->HookId, Status);
+ if (pHP->pHookStructs) ExFreePoolWithTag(pHP->pHookStructs, TAG_HOOK);
+ ExFreePoolWithTag(pHP, TAG_HOOK);
+ }
return NT_SUCCESS(Status) ? uResult : 0;
}
-/*
- Called from inside kernel space.
- */
+
+//
+// Dispatch MsgQueue Hook Call processor!
+//
LRESULT
FASTCALL
-co_HOOK_CallHooks(INT HookId, INT Code, WPARAM wParam, LPARAM lParam)
+co_CallHook( INT HookId,
+ INT Code,
+ WPARAM wParam,
+ LPARAM lParam)
{
- PHOOK Hook, SaveHook;
- PTHREADINFO pti;
- PCLIENTINFO ClientInfo;
- PHOOKTABLE Table;
LRESULT Result;
- PWINSTATION_OBJECT WinStaObj;
- NTSTATUS Status;
+ PHOOK phk;
+ PHOOKPACK pHP = (PHOOKPACK)lParam;
- ASSERT(WH_MINHOOK <= HookId && HookId <= WH_MAXHOOK);
+ phk = pHP->pHk;
+ lParam = pHP->lParam;
- pti = PsGetCurrentThreadWin32Thread();
- if (!pti)
- {
- Table = NULL;
- }
- else
- {
- Table = MsqGetHooks(pti->MessageQueue);
- }
-
- if (NULL == Table || ! (Hook = IntGetFirstValidHook(Table, HookId)))
- {
- /* try global table */
- Table = GlobalHooks;
- if (NULL == Table || ! (Hook = IntGetFirstValidHook(Table, HookId)))
- {
- return 0; /* no hook set */
- }
- }
-
- if ((Hook->Thread != PsGetCurrentThread()) && (Hook->Thread != NULL))
- {
- DPRINT1("\nHook found by Id and posted to Thread! %d\n",HookId );
- /* Post it in message queue. */
- return IntCallLowLevelHook(Hook, Code, wParam, lParam);
- }
-
- Table->Counts[HOOKID_TO_INDEX(HookId)]++;
- if (Table != GlobalHooks && GlobalHooks != NULL)
+ switch(HookId)
{
- GlobalHooks->Counts[HOOKID_TO_INDEX(HookId)]++;
- }
-
- ClientInfo = GetWin32ClientInfo();
- SaveHook = ClientInfo->phkCurrent;
- ClientInfo->phkCurrent = Hook; /* Load the call. */
-
- Result = co_IntCallHookProc(HookId,
- Code,
- wParam,
- lParam,
- Hook->Proc,
- Hook->Ansi,
- &Hook->ModuleName);
-
- ClientInfo->phkCurrent = SaveHook;
-
- Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
- KernelMode,
- 0,
- &WinStaObj);
-
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("Invalid window station????\n");
- }
- else
- {
- IntReleaseHookChain(MsqGetHooks(pti->MessageQueue), HookId, WinStaObj);
- IntReleaseHookChain(GlobalHooks, HookId, WinStaObj);
- ObDereferenceObject(WinStaObj);
+ case WH_JOURNALPLAYBACK:
+ case WH_JOURNALRECORD:
+ case WH_KEYBOARD:
+ case WH_KEYBOARD_LL:
+ case WH_MOUSE_LL:
+ case WH_MOUSE:
+ lParam = (LPARAM)pHP->pHookStructs;
+ break;
}
+ /* The odds are high for this to be a Global call. */
+ Result = co_IntCallHookProc( HookId,
+ Code,
+ wParam,
+ lParam,
+ phk->Proc,
+ phk->Ansi,
+ &phk->ModuleName);
+
+ /* The odds so high, no one is waiting for the results. */
+ if (pHP->pHookStructs) ExFreePoolWithTag(pHP->pHookStructs, TAG_HOOK);
+ ExFreePoolWithTag(pHP, TAG_HOOK);
return Result;
}
-VOID
-FASTCALL
-HOOK_DestroyThreadHooks(PETHREAD Thread)
-{
- int HookId;
- PLIST_ENTRY Elem;
- PHOOK HookObj;
- PWINSTATION_OBJECT WinStaObj;
- NTSTATUS Status;
-
- if (NULL != GlobalHooks)
- {
- Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
- KernelMode,
- 0,
- &WinStaObj);
-
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("Invalid window station????\n");
- return;
- }
-
- for (HookId = WH_MINHOOK; HookId <= WH_MAXHOOK; HookId++)
- {
- /* only low-level keyboard/mouse global hooks can be owned by a thread */
- switch(HookId)
- {
- case WH_KEYBOARD_LL:
- case WH_MOUSE_LL:
- Elem = GlobalHooks->Hooks[HOOKID_TO_INDEX(HookId)].Flink;
-
- while (Elem != &GlobalHooks->Hooks[HOOKID_TO_INDEX(HookId)])
- {
- HookObj = CONTAINING_RECORD(Elem, HOOK, Chain);
- Elem = Elem->Flink;
-
- if (HookObj->Thread == Thread)
- {
- IntRemoveHook(HookObj, WinStaObj, TRUE);
- }
- }
- break;
- }
- }
- }
-}
-
static
LRESULT
FASTCALL
-co_HOOK_CallHookNext(PHOOK Hook, INT Code, WPARAM wParam, LPARAM lParam)
+co_HOOK_CallHookNext( PHOOK Hook,
+ INT Code,
+ WPARAM wParam,
+ LPARAM lParam)
{
- if ((Hook->Thread != PsGetCurrentThread()) && (Hook->Thread != NULL))
- {
- DPRINT1("CALLING HOOK from another Thread. %d\n", Hook->HookId);
- return IntCallLowLevelHook(Hook, Code, wParam, lParam);
- }
-
- DPRINT("CALLING HOOK %d\n", Hook->HookId);
-
- return co_IntCallHookProc(Hook->HookId,
- Code,
- wParam,
- lParam,
- Hook->Proc,
- Hook->Ansi,
+ DPRINT("Calling Next HOOK %d\n", Hook->HookId);
+
+ return co_IntCallHookProc( Hook->HookId,
+ Code,
+ wParam,
+ lParam,
+ Hook->Proc,
+ Hook->Ansi,
&Hook->ModuleName);
}
-
LRESULT
FASTCALL
-IntCallDebugHook(PHOOK Hook,
- int Code,
- WPARAM wParam,
- LPARAM lParam)
+IntCallDebugHook( PHOOK Hook,
+ int Code,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL Ansi)
{
LRESULT lResult = 0;
ULONG Size;
return lResult;
}
-/*
- Called from user space via CallNextHook.
- */
LRESULT
FASTCALL
-UserCallNextHookEx(PHOOK Hook,
- int Code,
- WPARAM wParam,
- LPARAM lParam,
- BOOL Ansi)
+UserCallNextHookEx( PHOOK Hook,
+ int Code,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL Ansi)
{
LRESULT lResult = 0;
BOOL BadChk = FALSE;
break;
}
break;
-
+/*
+ Note WH_JOURNALPLAYBACK,
+ "To have the system wait before processing the message, the return value
+ must be the amount of time, in clock ticks, that the system should wait."
+ */
case WH_JOURNALPLAYBACK:
case WH_JOURNALRECORD:
{
}
case WH_DEBUG:
- lResult = IntCallDebugHook(Hook, Code, wParam, lParam);
+ lResult = IntCallDebugHook(Hook, Code, wParam, lParam, Ansi);
break;
/*
DPRINT1("Unsupported HOOK Id -> %d\n",Hook->HookId);
break;
}
-
return lResult;
}
+PHOOK
+FASTCALL
+IntGetHookObject(HHOOK hHook)
+{
+ PHOOK Hook;
+
+ if (!hHook)
+ {
+ SetLastWin32Error(ERROR_INVALID_HOOK_HANDLE);
+ return NULL;
+ }
+
+ Hook = (PHOOK)UserGetObject(gHandleTable, hHook, otHook);
+ if (!Hook)
+ {
+ SetLastWin32Error(ERROR_INVALID_HOOK_HANDLE);
+ return NULL;
+ }
+
+ UserReferenceObject(Hook);
+
+ return Hook;
+}
+
+/* get the first hook in the chain */
+static
+PHOOK
+FASTCALL
+IntGetFirstHook(PLIST_ENTRY Table)
+{
+ PLIST_ENTRY Elem = Table->Flink;
+
+ if (IsListEmpty(Table)) return NULL;
+
+ return Elem == Table ? NULL : CONTAINING_RECORD(Elem, HOOK, Chain);
+}
+
+static
+PHOOK
+FASTCALL
+IntGetNextGlobalHook(PHOOK Hook, PDESKTOP pdo)
+{
+ int HookId = Hook->HookId;
+ PLIST_ENTRY Elem;
+
+ Elem = Hook->Chain.Flink;
+ if (Elem != &pdo->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)])
+ return CONTAINING_RECORD(Elem, HOOK, Chain);
+ return NULL;
+}
+
+/* find the next hook in the chain */
+PHOOK
+FASTCALL
+IntGetNextHook(PHOOK Hook)
+{
+ int HookId = Hook->HookId;
+ PLIST_ENTRY Elem;
+ PTHREADINFO pti;
+
+ if (Hook->Thread)
+ {
+ pti = ((PTHREADINFO)Hook->Thread->Tcb.Win32Thread);
+
+ Elem = Hook->Chain.Flink;
+ if (Elem != &pti->aphkStart[HOOKID_TO_INDEX(HookId)])
+ return CONTAINING_RECORD(Elem, HOOK, Chain);
+ }
+ else
+ {
+ pti = PsGetCurrentThreadWin32Thread();
+ return IntGetNextGlobalHook(Hook, pti->rpdesk);
+ }
+ return NULL;
+}
+
+/* free a hook, removing it from its chain */
+static
+VOID
+FASTCALL
+IntFreeHook(PHOOK Hook)
+{
+ RemoveEntryList(&Hook->Chain);
+ if (Hook->ModuleName.Buffer)
+ {
+ ExFreePoolWithTag(Hook->ModuleName.Buffer, TAG_HOOK);
+ Hook->ModuleName.Buffer = NULL;
+ }
+ /* Close handle */
+ UserDeleteObject(UserHMGetHandle(Hook), otHook);
+}
+
+/* remove a hook, freeing it from the chain */
+static
+BOOL
+FASTCALL
+IntRemoveHook(PHOOK Hook)
+{
+ INT HookId;
+ PTHREADINFO pti;
+ PDESKTOP pdo;
+
+ HookId = Hook->HookId;
+
+ if (Hook->Thread) // Local
+ {
+ pti = ((PTHREADINFO)Hook->Thread->Tcb.Win32Thread);
+
+ IntFreeHook( Hook);
+
+ if ( IsListEmpty(&pti->aphkStart[HOOKID_TO_INDEX(HookId)]) )
+ {
+ pti->fsHooks &= ~HOOKID_TO_FLAG(HookId);
+ _SEH2_TRY
+ {
+ GetWin32ClientInfo()->fsHooks = pti->fsHooks;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+ _SEH2_END;
+ return TRUE;
+ }
+ }
+ else // Global
+ {
+ IntFreeHook( Hook);
+
+ pdo = IntGetActiveDesktop();
+
+ if ( pdo &&
+ pdo->pDeskInfo &&
+ IsListEmpty(&pdo->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)]) )
+ {
+ pdo->pDeskInfo->fsHooks &= ~HOOKID_TO_FLAG(HookId);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+VOID
+FASTCALL
+HOOK_DestroyThreadHooks(PETHREAD Thread)
+{
+ PTHREADINFO pti;
+ PDESKTOP pdo;
+ int HookId;
+ PHOOK HookObj;
+ PLIST_ENTRY pElem;
+
+ pti = Thread->Tcb.Win32Thread;
+ pdo = IntGetActiveDesktop();
+
+ if (!pti || !pdo)
+ {
+ DPRINT1("Kill Thread Hooks pti 0x%x pdo 0x%x\n",pti,pdo);
+ return;
+ }
+ ObReferenceObject(Thread);
+
+// Local Thread cleanup.
+ if (pti->fsHooks)
+ {
+ for (HookId = WH_MINHOOK; HookId <= WH_MAXHOOK; HookId++)
+ {
+ PLIST_ENTRY pLLE = &pti->aphkStart[HOOKID_TO_INDEX(HookId)];
+
+ if (IsListEmpty(pLLE)) continue;
+
+ pElem = pLLE->Flink;
+ HookObj = CONTAINING_RECORD(pElem, HOOK, Chain);
+ do
+ {
+ if (!HookObj) break;
+ if (IntRemoveHook(HookObj)) break;
+ pElem = HookObj->Chain.Flink;
+ HookObj = CONTAINING_RECORD(pElem, HOOK, Chain);
+ }
+ while (pElem != pLLE);
+ }
+ pti->fsHooks = 0;
+ }
+// Global search based on Thread and cleanup.
+ if (pdo->pDeskInfo->fsHooks)
+ {
+ for (HookId = WH_MINHOOK; HookId <= WH_MAXHOOK; HookId++)
+ {
+ PLIST_ENTRY pGLE = &pdo->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)];
+
+ if (IsListEmpty(pGLE)) continue;
+
+ pElem = pGLE->Flink;
+ HookObj = CONTAINING_RECORD(pElem, HOOK, Chain);
+ do
+ {
+ if (!HookObj) break;
+ if (HookObj->head.pti == pti)
+ {
+ if (IntRemoveHook(HookObj)) break;
+ }
+ pElem = HookObj->Chain.Flink;
+ HookObj = CONTAINING_RECORD(pElem, HOOK, Chain);
+ }
+ while (pElem != pGLE);
+ }
+ }
+ ObDereferenceObject(Thread);
+ return;
+}
+
+/*
+ Win32k Kernel Space Hook Caller.
+ */
LRESULT
-APIENTRY
-NtUserCallNextHookEx(int Code,
- WPARAM wParam,
- LPARAM lParam,
- BOOL Ansi)
+FASTCALL
+co_HOOK_CallHooks( INT HookId,
+ INT Code,
+ WPARAM wParam,
+ LPARAM lParam)
{
- PHOOK HookObj, NextObj;
+ PHOOK Hook, SaveHook;
+ PTHREADINFO pti;
PCLIENTINFO ClientInfo;
- PWINSTATION_OBJECT WinStaObj;
- NTSTATUS Status;
- DECLARE_RETURN(LRESULT);
+ PLIST_ENTRY pLLE, pGLE;
+ PDESKTOP pdo;
+ BOOL Local = FALSE, Global = FALSE;
+ LRESULT Result = 0;
- DPRINT("Enter NtUserCallNextHookEx\n");
- UserEnterExclusive();
+ ASSERT(WH_MINHOOK <= HookId && HookId <= WH_MAXHOOK);
- Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
- KernelMode,
- 0,
- &WinStaObj);
- if (!NT_SUCCESS(Status))
+ pti = PsGetCurrentThreadWin32Thread();
+ if (!pti || !pti->rpdesk || !pti->rpdesk->pDeskInfo)
+ {
+ pdo = IntGetActiveDesktop();
+ /* If KeyboardThread|MouseThread|(RawInputThread or RIT) aka system threads,
+ pti->fsHooks most likely, is zero. So process KbT & MsT to "send" the message.
+ */
+ if ( !pti || !pdo || (!(HookId == WH_KEYBOARD_LL) && !(HookId == WH_MOUSE_LL)) )
+ {
+ DPRINT("No PDO %d\n", HookId);
+ goto Exit;
+ }
+ }
+ else
{
- SetLastNtError(Status);
- RETURN( 0);
+ pdo = pti->rpdesk;
}
- ObDereferenceObject(WinStaObj);
+ if ( pti->TIF_flags & (TIF_INCLEANUP|TIF_DISABLEHOOKS))
+ {
+ DPRINT("Hook Thread dead %d\n", HookId);
+ goto Exit;
+ }
- ClientInfo = GetWin32ClientInfo();
+ if ( ISITHOOKED(HookId) )
+ {
+ DPRINT("Local Hooker %d\n", HookId);
+ Local = TRUE;
+ }
- if (!ClientInfo) RETURN( 0);
+ if ( pdo->pDeskInfo->fsHooks & HOOKID_TO_FLAG(HookId) )
+ {
+ DPRINT("Global Hooker %d\n", HookId);
+ Global = TRUE;
+ }
- HookObj = ClientInfo->phkCurrent;
+ if ( !Local && !Global ) goto Exit; // No work!
- if (!HookObj) RETURN( 0);
+ Hook = NULL;
+
+ /* SetWindowHookEx sorts out the Thread issue by placing the Hook to
+ the correct Thread if not NULL.
+ */
+ if ( Local )
+ {
+ pLLE = &pti->aphkStart[HOOKID_TO_INDEX(HookId)];
+ Hook = IntGetFirstHook(pLLE);
+ if (!Hook)
+ {
+ DPRINT1("No Local Hook Found!\n");
+ goto Exit;
+ }
+ ObReferenceObject(Hook->Thread);
+
+ ClientInfo = pti->pClientInfo;
+ SaveHook = pti->sphkCurrent;
+
+ /* Load it for the next call. */
+ pti->sphkCurrent = Hook;
+ Hook->phkNext = IntGetNextHook(Hook);
+ if (ClientInfo)
+ {
+ _SEH2_TRY
+ {
+ ClientInfo->phkCurrent = Hook;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ClientInfo = NULL; // Don't bother next run.
+ }
+ _SEH2_END;
+ }
+ Result = co_IntCallHookProc( HookId,
+ Code,
+ wParam,
+ lParam,
+ Hook->Proc,
+ Hook->Ansi,
+ &Hook->ModuleName);
+ if (ClientInfo)
+ {
+ _SEH2_TRY
+ {
+ ClientInfo->phkCurrent = SaveHook;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+ _SEH2_END;
+ }
+ pti->sphkCurrent = SaveHook;
+ Hook->phkNext = NULL;
+ ObDereferenceObject(Hook->Thread);
+ }
+
+ if ( Global )
+ {
+ PTHREADINFO ptiHook;
+
+ pGLE = &pdo->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)];
+ Hook = IntGetFirstHook(pGLE);
+ if (!Hook)
+ {
+ DPRINT1("No Global Hook Found!\n");
+ goto Exit;
+ }
+ /* Performance goes down the drain. If more hooks are associated to this
+ * hook ID, this will have to post to each of the thread message queues
+ * or make a direct call.
+ */
+ do
+ {
+ /* Hook->Thread is null, we hax around this with Hook->head.pti. */
+ ptiHook = Hook->head.pti;
+
+ /* "Global hook monitors messages for all threads in the same desktop
+ * as the calling thread."
+ */
+ if ( ptiHook->TIF_flags & (TIF_INCLEANUP|TIF_DISABLEHOOKS) ||
+ ptiHook->rpdesk != pdo)
+ {
+ DPRINT("Next Hook 0x%x, 0x%x\n",ptiHook->rpdesk,pdo);
+ Hook = IntGetNextGlobalHook(Hook, pdo);
+ if (!Hook) break;
+ continue;
+ }
+ // Lockup the thread while this links through user world.
+ ObReferenceObject(ptiHook->pEThread);
+ if (ptiHook != pti )
+ { // Block | TimeOut
+ if ( HookId == WH_JOURNALPLAYBACK || // 1 | 0
+ HookId == WH_JOURNALRECORD || // 1 | 0
+ HookId == WH_KEYBOARD || // 1 | 200
+ HookId == WH_MOUSE || // 1 | 200
+ HookId == WH_KEYBOARD_LL || // 0 | 300
+ HookId == WH_MOUSE_LL ) // 0 | 300
+ {
+ DPRINT("\nGlobal Hook posting to another Thread! %d\n",HookId );
+ Result = IntCallLowLevelHook(Hook, Code, wParam, lParam);
+ }
+ }
+ else
+ { /* Make the direct call. */
+ DPRINT("\nLocal Hook calling to Thread! %d\n",HookId );
+ Result = co_IntCallHookProc( HookId,
+ Code,
+ wParam,
+ lParam,
+ Hook->Proc,
+ Hook->Ansi,
+ &Hook->ModuleName);
+ }
+ ObDereferenceObject(ptiHook->pEThread);
+ Hook = IntGetNextGlobalHook(Hook, pdo);
+ }
+ while ( Hook );
+ DPRINT("Ret: Global HookId %d Result 0x%x\n", HookId,Result);
+ }
+Exit:
+ return Result;
+}
- UserReferenceObject(HookObj);
+BOOL
+FASTCALL
+IntUnhookWindowsHook(int HookId, HOOKPROC pfnFilterProc)
+{
+ PHOOK Hook;
+ PLIST_ENTRY pLLE, pLE;
+ PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
- Ansi = HookObj->Ansi;
+ if (HookId < WH_MINHOOK || WH_MAXHOOK < HookId )
+ {
+ SetLastWin32Error(ERROR_INVALID_HOOK_FILTER);
+ return FALSE;
+ }
- if (NULL != HookObj->Thread && (HookObj->Thread != PsGetCurrentThread()))
+ if (pti->fsHooks)
{
- DPRINT1("Thread mismatch\n");
- UserDereferenceObject(HookObj);
- SetLastWin32Error(ERROR_INVALID_HANDLE);
- RETURN( 0);
+ pLLE = &pti->aphkStart[HOOKID_TO_INDEX(HookId)];
+
+ if (IsListEmpty(pLLE)) return FALSE;
+
+ pLE = pLLE->Flink;
+ Hook = CONTAINING_RECORD(pLE, HOOK, Chain);
+ do
+ {
+ if (!Hook) break;
+ if (Hook->Proc == pfnFilterProc)
+ {
+ if (Hook->head.pti == pti)
+ {
+ IntRemoveHook(Hook);
+ UserDereferenceObject(Hook);
+ return TRUE;
+ }
+ else
+ {
+ SetLastWin32Error(ERROR_ACCESS_DENIED);
+ return FALSE;
+ }
+ }
+ pLE = Hook->Chain.Flink;
+ Hook = CONTAINING_RECORD(pLE, HOOK, Chain);
+ }
+ while (pLE != pLLE);
}
-
- NextObj = IntGetNextHook(HookObj);
- ClientInfo->phkCurrent = NextObj; /* Preset next hook from list. */
- UserCallNextHookEx( HookObj, Code, wParam, lParam, Ansi);
- UserDereferenceObject(HookObj);
+ return FALSE;
+}
+
+/*
+ * Support for compatibility only? Global hooks are processed in kernel space.
+ * This is very thread specific! Never seeing applications with more than one
+ * hook per thread installed. Most of the applications are Global hookers and
+ * associated with just one hook Id. Maybe it's for diagnostic testing or a
+ * throw back to 3.11?
+ */
+LRESULT
+APIENTRY
+NtUserCallNextHookEx( int Code,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL Ansi)
+{
+ PTHREADINFO pti;
+ PHOOK HookObj, NextObj;
+ PCLIENTINFO ClientInfo;
+ LRESULT lResult = 0;
+ DECLARE_RETURN(LRESULT);
+
+ DPRINT("Enter NtUserCallNextHookEx\n");
+ UserEnterExclusive();
+
+ pti = GetW32ThreadInfo();
+
+ HookObj = pti->sphkCurrent;
+
+ if (!HookObj) RETURN( 0);
+
+ NextObj = HookObj->phkNext;
- RETURN( (LRESULT)NextObj);
+ pti->sphkCurrent = NextObj;
+ ClientInfo = pti->pClientInfo;
+ _SEH2_TRY
+ {
+ ClientInfo->phkCurrent = NextObj;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ClientInfo = NULL;
+ }
+ _SEH2_END;
+
+ /* Now in List run down. */
+ if (ClientInfo && NextObj)
+ {
+ NextObj->phkNext = IntGetNextHook(NextObj);
+ lResult = UserCallNextHookEx( NextObj, Code, wParam, lParam, NextObj->Ansi);
+ }
+ RETURN( lResult);
CLEANUP:
DPRINT("Leave NtUserCallNextHookEx, ret=%i\n",_ret_);
HHOOK
APIENTRY
-NtUserSetWindowsHookAW(int idHook,
- HOOKPROC lpfn,
- BOOL Ansi)
+NtUserSetWindowsHookAW( int idHook,
+ HOOKPROC lpfn,
+ BOOL Ansi)
{
+ DWORD ThreadId;
UNICODE_STRING USModuleName;
RtlInitUnicodeString(&USModuleName, NULL);
-
- return NtUserSetWindowsHookEx(NULL, &USModuleName, 0, idHook, lpfn, Ansi);
+ ThreadId = PtrToUint(NtCurrentTeb()->ClientId.UniqueThread);
+
+ return NtUserSetWindowsHookEx( NULL,
+ &USModuleName,
+ ThreadId,
+ idHook,
+ lpfn,
+ Ansi);
}
HHOOK
APIENTRY
-NtUserSetWindowsHookEx(HINSTANCE Mod,
- PUNICODE_STRING UnsafeModuleName,
- DWORD ThreadId,
- int HookId,
- HOOKPROC HookProc,
- BOOL Ansi)
+NtUserSetWindowsHookEx( HINSTANCE Mod,
+ PUNICODE_STRING UnsafeModuleName,
+ DWORD ThreadId,
+ int HookId,
+ HOOKPROC HookProc,
+ BOOL Ansi)
{
PWINSTATION_OBJECT WinStaObj;
- PCLIENTINFO ClientInfo;
- BOOLEAN Global;
- PETHREAD Thread;
PHOOK Hook;
UNICODE_STRING ModuleName;
NTSTATUS Status;
HHOOK Handle;
- BOOLEAN ThreadReferenced = FALSE;
+ PETHREAD Thread = NULL;
+ PTHREADINFO ptiCurrent, pti = NULL;
+ BOOL Hit = FALSE;
DECLARE_RETURN(HHOOK);
DPRINT("Enter NtUserSetWindowsHookEx\n");
UserEnterExclusive();
+ ptiCurrent = PsGetCurrentThreadWin32Thread();
+
if (HookId < WH_MINHOOK || WH_MAXHOOK < HookId )
{
- SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ SetLastWin32Error(ERROR_INVALID_HOOK_FILTER);
RETURN( NULL);
}
RETURN( NULL);
}
- ClientInfo = GetWin32ClientInfo();
-
if (ThreadId) /* thread-local hook */
{
- if (HookId == WH_JOURNALRECORD ||
+ if ( HookId == WH_JOURNALRECORD ||
HookId == WH_JOURNALPLAYBACK ||
HookId == WH_KEYBOARD_LL ||
HookId == WH_MOUSE_LL ||
HookId == WH_SYSMSGFILTER)
- {
- /* these can only be global */
- SetLastWin32Error(ERROR_INVALID_PARAMETER);
- RETURN( NULL);
- }
-
- Mod = NULL;
- Global = FALSE;
-
- if (!NT_SUCCESS(PsLookupThreadByThreadId((HANDLE)(DWORD_PTR) ThreadId, &Thread)))
- {
- DPRINT1("Invalid thread id 0x%x\n", ThreadId);
- SetLastWin32Error(ERROR_INVALID_PARAMETER);
- RETURN( NULL);
- }
-
- /* Thread was referenced */
- ThreadReferenced = TRUE;
- if (Thread->ThreadsProcess != PsGetCurrentProcess())
- {
- ObDereferenceObject(Thread);
- DPRINT1("Can't specify thread belonging to another process\n");
- SetLastWin32Error(ERROR_INVALID_PARAMETER);
- RETURN( NULL);
- }
+ {
+ DPRINT1("Local hook installing Global HookId: %d\n",HookId);
+ /* these can only be global */
+ SetLastWin32Error(ERROR_GLOBAL_ONLY_HOOK);
+ RETURN( NULL);
+ }
+
+ if (!NT_SUCCESS(PsLookupThreadByThreadId((HANDLE)(DWORD_PTR) ThreadId, &Thread)))
+ {
+ DPRINT1("Invalid thread id 0x%x\n", ThreadId);
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ RETURN( NULL);
+ }
+
+ pti = Thread->Tcb.Win32Thread;
+
+ ObDereferenceObject(Thread);
+
+ if ( pti->rpdesk != ptiCurrent->rpdesk) // gptiCurrent->rpdesk)
+ {
+ DPRINT1("Local hook wrong desktop HookId: %d\n",HookId);
+ SetLastWin32Error(ERROR_ACCESS_DENIED);
+ RETURN( NULL);
+ }
+
+ if (Thread->ThreadsProcess != PsGetCurrentProcess())
+ {
+ if ( !Mod &&
+ (HookId == WH_GETMESSAGE ||
+ HookId == WH_CALLWNDPROC ||
+ HookId == WH_CBT ||
+ HookId == WH_HARDWARE ||
+ HookId == WH_DEBUG ||
+ HookId == WH_SHELL ||
+ HookId == WH_FOREGROUNDIDLE ||
+ HookId == WH_CALLWNDPROCRET) )
+ {
+ DPRINT1("Local hook needs hMod HookId: %d\n",HookId);
+ SetLastWin32Error(ERROR_HOOK_NEEDS_HMOD);
+ RETURN( NULL);
+ }
+
+ if ( (pti->TIF_flags & (TIF_CSRSSTHREAD|TIF_SYSTEMTHREAD)) &&
+ (HookId == WH_GETMESSAGE ||
+ HookId == WH_CALLWNDPROC ||
+ HookId == WH_CBT ||
+ HookId == WH_HARDWARE ||
+ HookId == WH_DEBUG ||
+ HookId == WH_SHELL ||
+ HookId == WH_FOREGROUNDIDLE ||
+ HookId == WH_CALLWNDPROCRET) )
+ {
+ SetLastWin32Error(ERROR_HOOK_TYPE_NOT_ALLOWED);
+ RETURN( NULL);
+ }
+ }
}
else /* system-global hook */
- {
- if (HookId == WH_KEYBOARD_LL || HookId == WH_MOUSE_LL)
- {
- Mod = NULL;
- Thread = PsGetCurrentThread();
-
- Status = ObReferenceObjectByPointer(Thread,
- THREAD_ALL_ACCESS,
- PsThreadType,
- KernelMode);
-
- if (!NT_SUCCESS(Status))
- {
- SetLastNtError(Status);
- RETURN( (HANDLE) NULL);
- }
-
- /* Thread was referenced */
- ThreadReferenced = TRUE;
- }
- else if (NULL == Mod)
- {
- SetLastWin32Error(ERROR_HOOK_NEEDS_HMOD);
- RETURN( NULL);
- }
- else
- {
- Thread = NULL;
- }
- Global = TRUE;
- }
-
- if ((Global && (HookId != WH_KEYBOARD_LL && HookId != WH_MOUSE_LL)) ||
- WH_DEBUG == HookId ||
- WH_JOURNALPLAYBACK == HookId ||
- WH_JOURNALRECORD == HookId)
- {
-#if 0 /* Removed to get winEmbed working again */
- UNIMPLEMENTED
-#else
- DPRINT1("Not implemented: HookId %d Global %s\n", HookId, Global ? "TRUE" : "FALSE");
-#endif
-
- /* Dereference thread if needed */
- if (ThreadReferenced) ObDereferenceObject(Thread);
- SetLastWin32Error(ERROR_NOT_SUPPORTED);
- RETURN( NULL);
+ {
+ pti = ptiCurrent; // gptiCurrent;
+ if ( !Mod &&
+ (HookId == WH_GETMESSAGE ||
+ HookId == WH_CALLWNDPROC ||
+ HookId == WH_CBT ||
+ HookId == WH_SYSMSGFILTER ||
+ HookId == WH_HARDWARE ||
+ HookId == WH_DEBUG ||
+ HookId == WH_SHELL ||
+ HookId == WH_FOREGROUNDIDLE ||
+ HookId == WH_CALLWNDPROCRET) )
+ {
+ DPRINT1("Global hook needs hMod HookId: %d\n",HookId);
+ SetLastWin32Error(ERROR_HOOK_NEEDS_HMOD);
+ RETURN( NULL);
+ }
}
- Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
- KernelMode,
- 0,
+ Status = IntValidateWindowStationHandle( PsGetCurrentProcess()->Win32WindowStation,
+ KernelMode,
+ 0,
&WinStaObj);
if (!NT_SUCCESS(Status))
{
- /* Dereference thread if needed */
- if (ThreadReferenced) ObDereferenceObject(Thread);
- SetLastNtError(Status);
- RETURN( (HANDLE) NULL);
+ SetLastNtError(Status);
+ RETURN( NULL);
}
+ ObDereferenceObject(WinStaObj);
- Hook = IntAddHook(Thread, HookId, Global, WinStaObj);
- if (NULL == Hook)
+ Hook = UserCreateObject(gHandleTable, NULL, &Handle, otHook, sizeof(HOOK));
+
+ if (!Hook)
{
- /* Dereference thread if needed */
- if (ThreadReferenced) ObDereferenceObject(Thread);
- ObDereferenceObject(WinStaObj);
- RETURN( NULL);
+ RETURN( NULL);
}
- /* Let IntFreeHook now that this thread needs a dereference */
- if (ThreadReferenced)
+ Hook->ihmod = (INT)Mod; // Module Index from atom table, Do this for now.
+ Hook->Thread = Thread; /* Set Thread, Null is Global. */
+ Hook->HookId = HookId;
+ Hook->rpdesk = pti->rpdesk;
+ Hook->phkNext = NULL; /* Dont use as a chain! Use link lists for chaining. */
+ Hook->Proc = HookProc;
+ Hook->Ansi = Ansi;
+
+ DPRINT("Set Hook Desk 0x%x DeskInfo 0x%x Handle Desk 0x%x\n",pti->rpdesk, pti->pDeskInfo,Hook->head.rpdesk);
+
+ if (ThreadId) /* thread-local hook */
{
- Hook->Flags |= HOOK_THREAD_REFERENCED;
+ InsertHeadList(&pti->aphkStart[HOOKID_TO_INDEX(HookId)], &Hook->Chain);
+ pti->sphkCurrent = NULL;
+ Hook->ptiHooked = pti;
+ pti->fsHooks |= HOOKID_TO_FLAG(HookId);
+
+ if (pti->pClientInfo)
+ {
+ if ( pti->ppi == ptiCurrent->ppi) /* gptiCurrent->ppi) */
+ {
+ _SEH2_TRY
+ {
+ pti->pClientInfo->fsHooks = pti->fsHooks;
+ pti->pClientInfo->phkCurrent = NULL;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Hit = TRUE;
+ }
+ _SEH2_END;
+ if (Hit)
+ {
+ DPRINT1("Problem writing to Local ClientInfo!\n");
+ }
+ }
+ else
+ {
+ KeAttachProcess(&pti->ppi->peProcess->Pcb);
+ _SEH2_TRY
+ {
+ pti->pClientInfo->fsHooks = pti->fsHooks;
+ pti->pClientInfo->phkCurrent = NULL;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Hit = TRUE;
+ }
+ _SEH2_END;
+ KeDetachProcess();
+ if (Hit)
+ {
+ DPRINT1("Problem writing to Remote ClientInfo!\n");
+ }
+ }
+ }
}
-
- if (NULL != Mod)
+ else
{
- Status = MmCopyFromCaller(&ModuleName, UnsafeModuleName, sizeof(UNICODE_STRING));
- if (!NT_SUCCESS(Status))
- {
- UserDereferenceObject(Hook);
- IntRemoveHook(Hook, WinStaObj, FALSE);
- ObDereferenceObject(WinStaObj);
- SetLastNtError(Status);
- RETURN( NULL);
- }
+ InsertHeadList(&pti->rpdesk->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)], &Hook->Chain);
+ Hook->ptiHooked = NULL;
+ //gptiCurrent->pDeskInfo->fsHooks |= HOOKID_TO_FLAG(HookId);
+ pti->rpdesk->pDeskInfo->fsHooks |= HOOKID_TO_FLAG(HookId);
+ pti->sphkCurrent = NULL;
+ pti->pClientInfo->phkCurrent = NULL;
+ }
- Hook->ModuleName.Buffer = ExAllocatePoolWithTag(PagedPool,
+ RtlInitUnicodeString(&Hook->ModuleName, NULL);
+
+ if (Mod)
+ {
+ Status = MmCopyFromCaller(&ModuleName,
+ UnsafeModuleName,
+ sizeof(UNICODE_STRING));
+ if (!NT_SUCCESS(Status))
+ {
+ IntRemoveHook(Hook);
+ SetLastNtError(Status);
+ RETURN( NULL);
+ }
+
+ Hook->ModuleName.Buffer = ExAllocatePoolWithTag( PagedPool,
ModuleName.MaximumLength,
TAG_HOOK);
- if (NULL == Hook->ModuleName.Buffer)
- {
- UserDereferenceObject(Hook);
- IntRemoveHook(Hook, WinStaObj, FALSE);
- ObDereferenceObject(WinStaObj);
- SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
- RETURN( NULL);
- }
-
- Hook->ModuleName.MaximumLength = ModuleName.MaximumLength;
- Status = MmCopyFromCaller(Hook->ModuleName.Buffer,
+ if (NULL == Hook->ModuleName.Buffer)
+ {
+ IntRemoveHook(Hook);
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ RETURN( NULL);
+ }
+
+ Hook->ModuleName.MaximumLength = ModuleName.MaximumLength;
+ Status = MmCopyFromCaller( Hook->ModuleName.Buffer,
ModuleName.Buffer,
ModuleName.MaximumLength);
- if (!NT_SUCCESS(Status))
- {
- ExFreePoolWithTag(Hook->ModuleName.Buffer, TAG_HOOK);
- UserDereferenceObject(Hook);
- IntRemoveHook(Hook, WinStaObj, FALSE);
- ObDereferenceObject(WinStaObj);
- SetLastNtError(Status);
- RETURN( NULL);
- }
-
- Hook->ModuleName.Length = ModuleName.Length;
- /* make proc relative to the module base */
- Hook->Proc = (void *)((char *)HookProc - (char *)Mod);
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePoolWithTag(Hook->ModuleName.Buffer, TAG_HOOK);
+ Hook->ModuleName.Buffer = NULL;
+ IntRemoveHook(Hook);
+ SetLastNtError(Status);
+ RETURN( NULL);
+ }
+
+ Hook->ModuleName.Length = ModuleName.Length;
+ /* make proc relative to the module base */
+ Hook->offPfn = (ULONG_PTR)((char *)HookProc - (char *)Mod);
}
else
- Hook->Proc = HookProc;
-
- Hook->Ansi = Ansi;
- Handle = UserHMGetHandle(Hook);
-
- /* Clear the client threads next hook. */
- ClientInfo->phkCurrent = 0;
-
- UserDereferenceObject(Hook);
-
- ObDereferenceObject(WinStaObj);
+ Hook->offPfn = 0;
+ DPRINT("Installing: HookId %d Global %s\n", HookId, !ThreadId ? "TRUE" : "FALSE");
RETURN( Handle);
CLEANUP:
END_CLEANUP;
}
-
BOOL
APIENTRY
NtUserUnhookWindowsHookEx(HHOOK Hook)
{
- PWINSTATION_OBJECT WinStaObj;
PHOOK HookObj;
- NTSTATUS Status;
DECLARE_RETURN(BOOL);
DPRINT("Enter NtUserUnhookWindowsHookEx\n");
UserEnterExclusive();
- Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
- KernelMode,
- 0,
- &WinStaObj);
-
- if (!NT_SUCCESS(Status))
- {
- SetLastNtError(Status);
- RETURN( FALSE);
- }
-
- /* Status = UserReferenceObjectByHandle(gHandleTable, Hook,
- otHookProc, (PVOID *) &HookObj); */
if (!(HookObj = IntGetHookObject(Hook)))
{
DPRINT1("Invalid handle passed to NtUserUnhookWindowsHookEx\n");
- ObDereferenceObject(WinStaObj);
/* SetLastNtError(Status); */
RETURN( FALSE);
}
ASSERT(Hook == UserHMGetHandle(HookObj));
- IntRemoveHook(HookObj, WinStaObj, FALSE);
+ IntRemoveHook(HookObj);
UserDereferenceObject(HookObj);
- ObDereferenceObject(WinStaObj);
RETURN( TRUE);