2001-06-12 17:51:51 +00:00
|
|
|
/*
|
2003-05-18 17:16:18 +00:00
|
|
|
* ReactOS W32 Subsystem
|
|
|
|
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
2005-01-06 13:58:04 +00:00
|
|
|
/* $Id$
|
2003-05-18 17:16:18 +00:00
|
|
|
*
|
2001-06-12 17:51:51 +00:00
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS kernel
|
|
|
|
* PURPOSE: Window hooks
|
|
|
|
* FILE: subsys/win32k/ntuser/hook.c
|
|
|
|
* PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
|
|
|
* REVISION HISTORY:
|
|
|
|
* 06-06-2001 CSH Created
|
2003-12-12 14:22:37 +00:00
|
|
|
* NOTE: Most of this code was adapted from Wine,
|
|
|
|
* Copyright (C) 2002 Alexandre Julliard
|
2001-06-12 17:51:51 +00:00
|
|
|
*/
|
2003-12-12 14:22:37 +00:00
|
|
|
|
2004-05-10 17:07:20 +00:00
|
|
|
#include <w32k.h>
|
2001-06-12 17:51:51 +00:00
|
|
|
|
|
|
|
#define NDEBUG
|
2003-12-12 14:22:37 +00:00
|
|
|
#include <win32k/debug1.h>
|
2001-06-12 17:51:51 +00:00
|
|
|
|
2003-12-12 14:22:37 +00:00
|
|
|
#define HOOKID_TO_INDEX(HookId) (HookId - WH_MINHOOK)
|
|
|
|
|
|
|
|
STATIC PHOOKTABLE GlobalHooks;
|
|
|
|
|
|
|
|
/* create a new hook table */
|
|
|
|
STATIC FASTCALL PHOOKTABLE
|
|
|
|
IntAllocHookTable(void)
|
|
|
|
{
|
|
|
|
PHOOKTABLE Table;
|
|
|
|
UINT i;
|
|
|
|
|
|
|
|
Table = ExAllocatePoolWithTag(PagedPool, sizeof(HOOKTABLE), TAG_HOOK);
|
|
|
|
if (NULL != Table)
|
|
|
|
{
|
|
|
|
ExInitializeFastMutex(&Table->Lock);
|
|
|
|
for (i = 0; i < NB_HOOKS; i++)
|
|
|
|
{
|
|
|
|
InitializeListHead(&Table->Hooks[i]);
|
|
|
|
Table->Counts[i] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Table;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* create a new hook and add it to the specified table */
|
|
|
|
STATIC FASTCALL PHOOK
|
|
|
|
IntAddHook(PETHREAD Thread, int HookId, BOOLEAN Global, PWINSTATION_OBJECT WinStaObj)
|
|
|
|
{
|
|
|
|
PHOOK Hook;
|
2004-09-28 15:02:31 +00:00
|
|
|
PHOOKTABLE Table = Global ? GlobalHooks : MsqGetHooks(Thread->Tcb.Win32Thread->MessageQueue);
|
2003-12-12 14:22:37 +00:00
|
|
|
HANDLE Handle;
|
|
|
|
|
|
|
|
if (NULL == Table)
|
|
|
|
{
|
|
|
|
Table = IntAllocHookTable();
|
|
|
|
if (NULL == Table)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (Global)
|
|
|
|
{
|
|
|
|
GlobalHooks = Table;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-09-28 15:02:31 +00:00
|
|
|
MsqSetHooks(Thread->Tcb.Win32Thread->MessageQueue, Table);
|
2003-12-12 14:22:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Hook = ObmCreateObject(WinStaObj->HandleTable, &Handle,
|
|
|
|
otHookProc, sizeof(HOOK));
|
|
|
|
if (NULL == Hook)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Hook->Self = Handle;
|
|
|
|
Hook->Thread = Thread;
|
|
|
|
Hook->HookId = HookId;
|
|
|
|
RtlInitUnicodeString(&Hook->ModuleName, NULL);
|
|
|
|
|
2004-02-24 13:27:03 +00:00
|
|
|
IntLockHookTable(Table);
|
2003-12-12 14:22:37 +00:00
|
|
|
InsertHeadList(&Table->Hooks[HOOKID_TO_INDEX(HookId)], &Hook->Chain);
|
2004-02-24 13:27:03 +00:00
|
|
|
IntUnLockHookTable(Table);
|
2003-12-12 14:22:37 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2004-09-28 15:02:31 +00:00
|
|
|
return MsqGetHooks(Hook->Thread->Tcb.Win32Thread->MessageQueue);
|
2003-12-12 14:22:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
2004-02-24 13:27:03 +00:00
|
|
|
IntLockHookTable(Table);
|
2003-12-12 14:22:37 +00:00
|
|
|
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));
|
|
|
|
}
|
2004-02-24 13:27:03 +00:00
|
|
|
IntUnLockHookTable(Table);
|
2005-05-08 02:11:54 +00:00
|
|
|
|
2003-12-12 14:22:37 +00:00
|
|
|
return Hook;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find the next hook in the chain, skipping the deleted ones */
|
|
|
|
STATIC PHOOK FASTCALL
|
|
|
|
IntGetNextHook(PHOOK Hook)
|
|
|
|
{
|
|
|
|
PHOOKTABLE Table = IntGetTable(Hook);
|
|
|
|
int HookId = Hook->HookId;
|
|
|
|
PLIST_ENTRY Elem;
|
|
|
|
|
2004-02-24 13:27:03 +00:00
|
|
|
IntLockHookTable(Table);
|
2003-12-12 14:22:37 +00:00
|
|
|
Elem = Hook->Chain.Flink;
|
|
|
|
while (Elem != &Table->Hooks[HOOKID_TO_INDEX(HookId)])
|
|
|
|
{
|
|
|
|
Hook = CONTAINING_RECORD(Elem, HOOK, Chain);
|
|
|
|
if (NULL != Hook->Proc)
|
|
|
|
{
|
2004-02-24 13:27:03 +00:00
|
|
|
IntUnLockHookTable(Table);
|
2003-12-12 14:22:37 +00:00
|
|
|
return Hook;
|
|
|
|
}
|
|
|
|
}
|
2004-02-24 13:27:03 +00:00
|
|
|
IntUnLockHookTable(Table);
|
2003-12-12 14:22:37 +00:00
|
|
|
|
|
|
|
if (NULL != GlobalHooks && Table != GlobalHooks) /* now search through the global table */
|
|
|
|
{
|
|
|
|
return IntGetFirstValidHook(GlobalHooks, HookId);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free a hook, removing it from its chain */
|
|
|
|
STATIC VOID FASTCALL
|
|
|
|
IntFreeHook(PHOOKTABLE Table, PHOOK Hook, PWINSTATION_OBJECT WinStaObj)
|
|
|
|
{
|
|
|
|
RemoveEntryList(&Hook->Chain);
|
|
|
|
RtlFreeUnicodeString(&Hook->ModuleName);
|
2005-05-08 02:11:54 +00:00
|
|
|
|
2004-04-07 00:58:05 +00:00
|
|
|
/* Dereference thread if required */
|
|
|
|
if(Hook->Flags & HOOK_THREAD_REFERENCED)
|
|
|
|
ObDereferenceObject(Hook->Thread);
|
2005-05-08 02:11:54 +00:00
|
|
|
|
2004-04-07 00:58:05 +00:00
|
|
|
/* Close handle */
|
2003-12-12 14:22:37 +00:00
|
|
|
ObmCloseHandle(WinStaObj->HandleTable, Hook->Self);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remove a hook, freeing it if the chain is not in use */
|
|
|
|
STATIC FASTCALL VOID
|
|
|
|
IntRemoveHook(PHOOK Hook, PWINSTATION_OBJECT WinStaObj)
|
|
|
|
{
|
|
|
|
PHOOKTABLE Table = IntGetTable(Hook);
|
|
|
|
|
|
|
|
ASSERT(NULL != Table);
|
|
|
|
if (NULL == Table)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-02-24 13:27:03 +00:00
|
|
|
IntLockHookTable(Table);
|
2003-12-12 14:22:37 +00:00
|
|
|
if (0 != Table->Counts[HOOKID_TO_INDEX(Hook->HookId)])
|
|
|
|
{
|
|
|
|
Hook->Proc = NULL; /* chain is in use, just mark it and return */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
IntFreeHook(Table, Hook, WinStaObj);
|
|
|
|
}
|
2004-02-24 13:27:03 +00:00
|
|
|
IntUnLockHookTable(Table);
|
2003-12-12 14:22:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
if (NULL == Table)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-02-24 13:27:03 +00:00
|
|
|
IntLockHookTable(Table);
|
2003-12-12 14:22:37 +00:00
|
|
|
/* use count shouldn't already be 0 */
|
|
|
|
ASSERT(0 != Table->Counts[HOOKID_TO_INDEX(HookId)]);
|
|
|
|
if (0 == Table->Counts[HOOKID_TO_INDEX(HookId)])
|
|
|
|
{
|
2004-02-24 13:27:03 +00:00
|
|
|
IntUnLockHookTable(Table);
|
2003-12-12 14:22:37 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (0 == --Table->Counts[HOOKID_TO_INDEX(HookId)])
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-02-24 13:27:03 +00:00
|
|
|
IntUnLockHookTable(Table);
|
2003-12-12 14:22:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
LRESULT FASTCALL
|
|
|
|
HOOK_CallHooks(INT HookId, INT Code, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
PHOOK Hook;
|
|
|
|
PHOOKTABLE Table = MsqGetHooks(PsGetWin32Thread()->MessageQueue);
|
|
|
|
LRESULT Result;
|
|
|
|
PWINSTATION_OBJECT WinStaObj;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
ASSERT(WH_MINHOOK <= HookId && HookId <= WH_MAXHOOK);
|
|
|
|
|
|
|
|
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())
|
|
|
|
{
|
|
|
|
DPRINT1("Calling hooks in other threads not implemented yet");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-02-24 13:27:03 +00:00
|
|
|
IntLockHookTable(Table);
|
2003-12-12 14:22:37 +00:00
|
|
|
Table->Counts[HOOKID_TO_INDEX(HookId)]++;
|
2004-02-24 13:27:03 +00:00
|
|
|
IntUnLockHookTable(Table);
|
2003-12-12 14:22:37 +00:00
|
|
|
if (Table != GlobalHooks && GlobalHooks != NULL)
|
|
|
|
{
|
2004-02-24 13:27:03 +00:00
|
|
|
IntLockHookTable(GlobalHooks);
|
2003-12-12 14:22:37 +00:00
|
|
|
GlobalHooks->Counts[HOOKID_TO_INDEX(HookId)]++;
|
2004-02-24 13:27:03 +00:00
|
|
|
IntUnLockHookTable(GlobalHooks);
|
2003-12-12 14:22:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Result = IntCallHookProc(HookId, Code, wParam, lParam, Hook->Proc,
|
|
|
|
Hook->Ansi, &Hook->ModuleName);
|
|
|
|
|
2004-11-20 16:46:06 +00:00
|
|
|
Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
|
2003-12-12 14:22:37 +00:00
|
|
|
KernelMode,
|
|
|
|
0,
|
|
|
|
&WinStaObj);
|
2005-05-08 02:11:54 +00:00
|
|
|
|
2003-12-12 14:22:37 +00:00
|
|
|
if(! NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Invalid window station????\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
IntReleaseHookChain(MsqGetHooks(PsGetWin32Thread()->MessageQueue), HookId, WinStaObj);
|
|
|
|
IntReleaseHookChain(GlobalHooks, HookId, WinStaObj);
|
|
|
|
ObDereferenceObject(WinStaObj);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID FASTCALL
|
|
|
|
HOOK_DestroyThreadHooks(PETHREAD Thread)
|
|
|
|
{
|
|
|
|
int HookId;
|
|
|
|
PLIST_ENTRY Elem;
|
|
|
|
PHOOK HookObj;
|
|
|
|
PWINSTATION_OBJECT WinStaObj;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
if (NULL != GlobalHooks)
|
|
|
|
{
|
2004-11-20 16:46:06 +00:00
|
|
|
Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
|
2003-12-12 14:22:37 +00:00
|
|
|
KernelMode,
|
|
|
|
0,
|
|
|
|
&WinStaObj);
|
2004-11-20 16:46:06 +00:00
|
|
|
|
2003-12-12 14:22:37 +00:00
|
|
|
if(! NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Invalid window station????\n");
|
|
|
|
return;
|
|
|
|
}
|
2004-02-24 13:27:03 +00:00
|
|
|
IntLockHookTable(GlobalHooks);
|
2003-12-12 14:22:37 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2004-02-24 13:27:03 +00:00
|
|
|
IntUnLockHookTable(GlobalHooks);
|
2003-12-12 14:22:37 +00:00
|
|
|
ObDereferenceObject(WinStaObj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LRESULT
|
2001-06-12 17:51:51 +00:00
|
|
|
STDCALL
|
|
|
|
NtUserCallNextHookEx(
|
2003-12-12 14:22:37 +00:00
|
|
|
HHOOK Hook,
|
|
|
|
int Code,
|
|
|
|
WPARAM wParam,
|
|
|
|
LPARAM lParam)
|
2001-06-12 17:51:51 +00:00
|
|
|
{
|
2003-12-12 14:22:37 +00:00
|
|
|
PHOOK HookObj, NextObj;
|
|
|
|
PWINSTATION_OBJECT WinStaObj;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
2004-11-20 16:46:06 +00:00
|
|
|
Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
|
2003-12-12 14:22:37 +00:00
|
|
|
KernelMode,
|
|
|
|
0,
|
|
|
|
&WinStaObj);
|
2004-11-20 16:46:06 +00:00
|
|
|
|
2003-12-12 14:22:37 +00:00
|
|
|
if(! NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
SetLastNtError(Status);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = ObmReferenceObjectByHandle(WinStaObj->HandleTable, Hook,
|
|
|
|
otHookProc, (PVOID *) &HookObj);
|
|
|
|
ObDereferenceObject(WinStaObj);
|
|
|
|
if (! NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Invalid handle passed to NtUserCallNextHookEx\n");
|
|
|
|
SetLastNtError(Status);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ASSERT(Hook == HookObj->Self);
|
|
|
|
|
|
|
|
if (NULL != HookObj->Thread && (HookObj->Thread != PsGetCurrentThread()))
|
|
|
|
{
|
|
|
|
DPRINT1("Thread mismatch\n");
|
|
|
|
ObmDereferenceObject(HookObj);
|
|
|
|
SetLastWin32Error(ERROR_INVALID_HANDLE);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
NextObj = IntGetNextHook(HookObj);
|
|
|
|
ObmDereferenceObject(HookObj);
|
|
|
|
if (NULL != NextObj)
|
|
|
|
{
|
|
|
|
DPRINT1("Calling next hook not implemented\n");
|
|
|
|
UNIMPLEMENTED
|
|
|
|
SetLastWin32Error(ERROR_NOT_SUPPORTED);
|
|
|
|
return 0;
|
|
|
|
}
|
2001-06-12 17:51:51 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
|
|
STDCALL
|
|
|
|
NtUserSetWindowsHookAW(
|
|
|
|
DWORD Unknown0,
|
|
|
|
DWORD Unknown1,
|
|
|
|
DWORD Unknown2)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-12-12 14:22:37 +00:00
|
|
|
HHOOK
|
2001-06-12 17:51:51 +00:00
|
|
|
STDCALL
|
|
|
|
NtUserSetWindowsHookEx(
|
2003-12-12 14:22:37 +00:00
|
|
|
HINSTANCE Mod,
|
|
|
|
PUNICODE_STRING UnsafeModuleName,
|
|
|
|
DWORD ThreadId,
|
|
|
|
int HookId,
|
|
|
|
HOOKPROC HookProc,
|
|
|
|
BOOL Ansi)
|
2001-06-12 17:51:51 +00:00
|
|
|
{
|
2003-12-12 14:22:37 +00:00
|
|
|
PWINSTATION_OBJECT WinStaObj;
|
2004-04-07 00:58:05 +00:00
|
|
|
BOOLEAN Global, ReleaseThread;
|
2003-12-12 14:22:37 +00:00
|
|
|
PETHREAD Thread;
|
|
|
|
PHOOK Hook;
|
|
|
|
UNICODE_STRING ModuleName;
|
|
|
|
NTSTATUS Status;
|
|
|
|
HHOOK Handle;
|
2001-06-12 17:51:51 +00:00
|
|
|
|
2003-12-12 14:22:37 +00:00
|
|
|
if (HookId < WH_MINHOOK || WH_MAXHOOK < HookId || NULL == HookProc)
|
|
|
|
{
|
|
|
|
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ThreadId) /* thread-local hook */
|
|
|
|
{
|
|
|
|
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;
|
2005-02-17 16:41:28 +00:00
|
|
|
if (! NT_SUCCESS(PsLookupThreadByThreadId((HANDLE) ThreadId, &Thread)))
|
2003-12-12 14:22:37 +00:00
|
|
|
{
|
|
|
|
DPRINT1("Invalid thread id 0x%x\n", ThreadId);
|
|
|
|
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (Thread->ThreadsProcess != PsGetCurrentProcess())
|
|
|
|
{
|
2004-04-07 00:58:05 +00:00
|
|
|
ObDereferenceObject(Thread);
|
2003-12-12 14:22:37 +00:00
|
|
|
DPRINT1("Can't specify thread belonging to another process\n");
|
|
|
|
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
|
|
|
return NULL;
|
|
|
|
}
|
2004-04-07 00:58:05 +00:00
|
|
|
ReleaseThread = TRUE;
|
2003-12-12 14:22:37 +00:00
|
|
|
}
|
|
|
|
else /* system-global hook */
|
|
|
|
{
|
2004-04-07 00:58:05 +00:00
|
|
|
ReleaseThread = FALSE;
|
2003-12-12 14:22:37 +00:00
|
|
|
if (HookId == WH_KEYBOARD_LL || HookId == WH_MOUSE_LL)
|
|
|
|
{
|
|
|
|
Mod = NULL;
|
|
|
|
Thread = PsGetCurrentThread();
|
|
|
|
}
|
|
|
|
else if (NULL == Mod)
|
|
|
|
{
|
|
|
|
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Thread = NULL;
|
|
|
|
}
|
|
|
|
Global = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We only (partially) support local WH_CBT hooks for now */
|
|
|
|
if (WH_CBT != HookId || Global)
|
|
|
|
{
|
2003-12-14 22:34:47 +00:00
|
|
|
#if 0 /* Removed to get winEmbed working again */
|
2003-12-12 14:22:37 +00:00
|
|
|
UNIMPLEMENTED
|
2003-12-14 22:34:47 +00:00
|
|
|
#else
|
|
|
|
DPRINT1("Not implemented: HookId %d Global %s\n", HookId, Global ? "TRUE" : "FALSE");
|
|
|
|
#endif
|
2004-04-07 00:58:05 +00:00
|
|
|
if(ReleaseThread)
|
|
|
|
ObDereferenceObject(Thread);
|
2003-12-12 14:22:37 +00:00
|
|
|
SetLastWin32Error(ERROR_NOT_SUPPORTED);
|
|
|
|
return NULL;
|
|
|
|
}
|
2005-05-08 02:11:54 +00:00
|
|
|
|
2004-11-20 16:46:06 +00:00
|
|
|
Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
|
2003-12-12 14:22:37 +00:00
|
|
|
KernelMode,
|
|
|
|
0,
|
|
|
|
&WinStaObj);
|
2005-05-08 02:11:54 +00:00
|
|
|
|
2003-12-12 14:22:37 +00:00
|
|
|
if(! NT_SUCCESS(Status))
|
|
|
|
{
|
2004-04-07 00:58:05 +00:00
|
|
|
if(ReleaseThread && Thread)
|
|
|
|
ObDereferenceObject(Thread);
|
2003-12-12 14:22:37 +00:00
|
|
|
SetLastNtError(Status);
|
|
|
|
return (HANDLE) NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Hook = IntAddHook(Thread, HookId, Global, WinStaObj);
|
|
|
|
if (NULL == Hook)
|
|
|
|
{
|
2004-04-07 00:58:05 +00:00
|
|
|
if(ReleaseThread)
|
|
|
|
ObDereferenceObject(Thread);
|
2003-12-12 14:22:37 +00:00
|
|
|
ObDereferenceObject(WinStaObj);
|
|
|
|
return NULL;
|
|
|
|
}
|
2005-05-08 02:11:54 +00:00
|
|
|
|
2004-04-07 00:58:05 +00:00
|
|
|
if(ReleaseThread)
|
|
|
|
Hook->Flags |= HOOK_THREAD_REFERENCED;
|
2005-05-08 02:11:54 +00:00
|
|
|
|
2003-12-12 14:22:37 +00:00
|
|
|
if (NULL != Mod)
|
|
|
|
{
|
|
|
|
Status = MmCopyFromCaller(&ModuleName, UnsafeModuleName, sizeof(UNICODE_STRING));
|
|
|
|
if (! NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
ObmDereferenceObject(Hook);
|
|
|
|
IntRemoveHook(Hook, WinStaObj);
|
2004-04-07 00:58:05 +00:00
|
|
|
if(ReleaseThread)
|
|
|
|
ObDereferenceObject(Thread);
|
2003-12-12 14:22:37 +00:00
|
|
|
ObDereferenceObject(WinStaObj);
|
|
|
|
SetLastNtError(Status);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
Hook->ModuleName.Buffer = ExAllocatePoolWithTag(PagedPool,
|
|
|
|
ModuleName.MaximumLength,
|
|
|
|
TAG_HOOK);
|
|
|
|
if (NULL == Hook->ModuleName.Buffer)
|
|
|
|
{
|
|
|
|
ObmDereferenceObject(Hook);
|
|
|
|
IntRemoveHook(Hook, WinStaObj);
|
2004-04-07 00:58:05 +00:00
|
|
|
if(ReleaseThread)
|
|
|
|
ObDereferenceObject(Thread);
|
2003-12-12 14:22:37 +00:00
|
|
|
ObDereferenceObject(WinStaObj);
|
|
|
|
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))
|
|
|
|
{
|
|
|
|
ObmDereferenceObject(Hook);
|
|
|
|
IntRemoveHook(Hook, WinStaObj);
|
2004-04-07 00:58:05 +00:00
|
|
|
if(ReleaseThread)
|
|
|
|
ObDereferenceObject(Thread);
|
2003-12-12 14:22:37 +00:00
|
|
|
ObDereferenceObject(WinStaObj);
|
|
|
|
SetLastNtError(Status);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
Hook->ModuleName.Length = ModuleName.Length;
|
|
|
|
}
|
|
|
|
|
|
|
|
Hook->Proc = HookProc;
|
|
|
|
Hook->Ansi = Ansi;
|
|
|
|
Handle = Hook->Self;
|
|
|
|
|
|
|
|
ObmDereferenceObject(Hook);
|
|
|
|
ObDereferenceObject(WinStaObj);
|
|
|
|
|
|
|
|
return Handle;
|
2001-06-12 17:51:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
|
|
STDCALL
|
|
|
|
NtUserSetWinEventHook(
|
|
|
|
DWORD Unknown0,
|
|
|
|
DWORD Unknown1,
|
|
|
|
DWORD Unknown2,
|
|
|
|
DWORD Unknown3,
|
|
|
|
DWORD Unknown4,
|
|
|
|
DWORD Unknown5,
|
|
|
|
DWORD Unknown6,
|
|
|
|
DWORD Unknown7)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-12-12 14:22:37 +00:00
|
|
|
BOOL
|
2001-06-12 17:51:51 +00:00
|
|
|
STDCALL
|
|
|
|
NtUserUnhookWindowsHookEx(
|
2003-12-12 14:22:37 +00:00
|
|
|
HHOOK Hook)
|
2001-06-12 17:51:51 +00:00
|
|
|
{
|
2003-12-12 14:22:37 +00:00
|
|
|
PWINSTATION_OBJECT WinStaObj;
|
|
|
|
PHOOK HookObj;
|
|
|
|
NTSTATUS Status;
|
2001-06-12 17:51:51 +00:00
|
|
|
|
2004-11-20 16:46:06 +00:00
|
|
|
Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
|
2003-12-12 14:22:37 +00:00
|
|
|
KernelMode,
|
|
|
|
0,
|
|
|
|
&WinStaObj);
|
2005-05-08 02:11:54 +00:00
|
|
|
|
2003-12-12 14:22:37 +00:00
|
|
|
if(! NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
SetLastNtError(Status);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = ObmReferenceObjectByHandle(WinStaObj->HandleTable, Hook,
|
|
|
|
otHookProc, (PVOID *) &HookObj);
|
|
|
|
if (! NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Invalid handle passed to NtUserUnhookWindowsHookEx\n");
|
|
|
|
ObDereferenceObject(WinStaObj);
|
|
|
|
SetLastNtError(Status);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
ASSERT(Hook == HookObj->Self);
|
|
|
|
|
|
|
|
IntRemoveHook(HookObj, WinStaObj);
|
|
|
|
|
|
|
|
ObmDereferenceObject(HookObj);
|
|
|
|
ObDereferenceObject(WinStaObj);
|
|
|
|
|
|
|
|
return TRUE;
|
2001-06-12 17:51:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
|
|
STDCALL
|
|
|
|
NtUserUnhookWinEvent(
|
|
|
|
DWORD Unknown0)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* EOF */
|