- Preliminary implementation of SetWinEventHook and UnhookWinEvent.

- Only wine cross test uses this and testing is not stable.
- Patches are welcome but all code is subject to change.
- All Hook code should be ready by Aug 4th.

svn path=/trunk/; revision=34988
This commit is contained in:
James Tabor 2008-07-31 23:48:35 +00:00
parent 30d2593564
commit 3e6656c48c
6 changed files with 263 additions and 17 deletions

View file

@ -33,6 +33,8 @@ typedef struct tagEVENTHOOK
PETHREAD Thread; /* Thread owning the event */
UINT eventMin;
UINT eventMax;
DWORD idProcess;
DWORD idThread;
WINEVENTPROC Proc; /* Event function */
BOOLEAN Ansi; /* Is it an Ansi event? */
ULONG Flags; /* Some internal flags */

View file

@ -4,6 +4,9 @@
#include "hook.h"
#define MSQ_HUNG 5000
#define MSQ_NORMAL 0
#define MSQ_ISHOOK 1
#define MSQ_ISEVENT 2
typedef struct _USER_MESSAGE
{
@ -25,7 +28,7 @@ typedef struct _USER_SENT_MESSAGE
ULONG_PTR CompletionCallbackContext;
/* entry in the dispatching list of the sender's message queue */
LIST_ENTRY DispatchingListEntry;
BOOL HookMessage;
INT HookMessage;
} USER_SENT_MESSAGE, *PUSER_SENT_MESSAGE;
typedef struct _USER_SENT_MESSAGE_NOTIFY
@ -121,7 +124,7 @@ MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue);
NTSTATUS FASTCALL
co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam,
UINT uTimeout, BOOL Block, BOOL HookMessage,
UINT uTimeout, BOOL Block, INT HookMessage,
ULONG_PTR *uResult);
PUSER_MESSAGE FASTCALL
MsqCreateMessage(LPMSG Msg, BOOLEAN FreeLParam);

View file

@ -4,8 +4,9 @@
#define NDEBUG
#include <debug.h>
//static PEVENTTABLE GlobalEvents;
static PEVENTTABLE GlobalEvents = NULL;
static ULONG EventSys[EVENT_SYSTEM_MINIMIZEEND+1] = {0};
static ULONG EventObj[( EVENT_OBJECT_ACCELERATORCHANGE - EVENT_OBJECT_CREATE) +1] = {0};
/* PRIVATE FUNCTIONS *********************************************************/
@ -43,6 +44,88 @@ GetMaskFromEvent(DWORD Event)
return Ret;
}
static
VOID
FASTCALL
IntEventUpCount(ULONG eventMin, ULONG eventMax)
{
INT i, Min, Max;
if ( eventMin >= EVENT_SYSTEM_SOUND && eventMax <= EVENT_SYSTEM_MINIMIZEEND)
{
for (i = eventMin; i < eventMax; i++)
{
gpsi->SrvEventActivity |= GetMaskFromEvent(i);
EventSys[i]++;
}
}
if ( eventMin >= EVENT_OBJECT_CREATE && eventMax <= EVENT_OBJECT_ACCELERATORCHANGE)
{
for (i = eventMin; i < eventMax; i++)
{
gpsi->SrvEventActivity |= GetMaskFromEvent(i);
EventObj[i - EVENT_OBJECT_CREATE]++;
}
}
if ( eventMin >= EVENT_SYSTEM_SOUND && eventMax <= EVENT_OBJECT_ACCELERATORCHANGE)
{
Max = EVENT_SYSTEM_MINIMIZEEND;
for (i = eventMin; i < Max; i++)
{
gpsi->SrvEventActivity |= GetMaskFromEvent(i);
EventSys[i]++;
}
Min = EVENT_OBJECT_CREATE;
for (i = Min; i < eventMax; i++)
{
gpsi->SrvEventActivity |= GetMaskFromEvent(i);
EventObj[i - EVENT_OBJECT_CREATE]++;
}
}
}
static
VOID
FASTCALL
IntEventDownCount(ULONG eventMin, ULONG eventMax)
{
INT i, Min, Max;
if ( eventMin >= EVENT_SYSTEM_SOUND && eventMax <= EVENT_SYSTEM_MINIMIZEEND)
{
for (i = eventMin; i < eventMax; i++)
{
EventSys[i]--;
if (!EventSys[i]) gpsi->SrvEventActivity &= ~GetMaskFromEvent(i);
}
}
if ( eventMin >= EVENT_OBJECT_CREATE && eventMax <= EVENT_OBJECT_ACCELERATORCHANGE)
{
for (i = eventMin; i < eventMax; i++)
{
EventObj[i - EVENT_OBJECT_CREATE]--;
if (!EventObj[i - EVENT_OBJECT_CREATE])
gpsi->SrvEventActivity &= ~GetMaskFromEvent(i);
}
}
if ( eventMin >= EVENT_SYSTEM_SOUND && eventMax <= EVENT_OBJECT_ACCELERATORCHANGE)
{
Max = EVENT_SYSTEM_MINIMIZEEND;
for (i = eventMin; i < Max; i++)
{
EventSys[i]--;
if (!EventSys[i]) gpsi->SrvEventActivity &= ~GetMaskFromEvent(i);
}
Min = EVENT_OBJECT_CREATE;
for (i = Min; i < eventMax; i++)
{
EventObj[i - EVENT_OBJECT_CREATE]--;
if (!EventObj[i - EVENT_OBJECT_CREATE])
gpsi->SrvEventActivity &= ~GetMaskFromEvent(i);
}
}
}
static
DWORD
@ -52,6 +135,48 @@ TimeStamp(VOID)
return (DWORD)((ULONGLONG)SharedUserData->TickCountLowDeprecated * SharedUserData->TickCountMultiplier / 16777216);
}
static
LRESULT
FASTCALL
IntCallLowLevelEvent( PEVENTHOOK pEH,
DWORD event,
HWND hwnd,
LONG idObject,
LONG idChild)
{
NTSTATUS Status;
ULONG_PTR uResult;
/* FIXME should get timeout from
* HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */
Status = co_MsqSendMessage(((PW32THREAD)pEH->Thread->Tcb.Win32Thread)->MessageQueue,
hwnd,
event,
idObject,
idChild,
5000,
TRUE,
MSQ_ISEVENT,
&uResult);
return NT_SUCCESS(Status) ? uResult : 0;
}
static
BOOL
FASTCALL
IntRemoveEvent(PEVENTHOOK pEH)
{
if (pEH)
{
RemoveEntryList(&pEH->Chain);
GlobalEvents->Counts--;
UserDeleteObject(pEH->Self, otEvent);
return TRUE;
}
return FALSE;
}
/* FUNCTIONS *****************************************************************/
LRESULT
@ -62,18 +187,26 @@ co_EVENT_CallEvents( DWORD event,
LONG idChild)
{
PEVENTHOOK peh = UserHeapAlloc(sizeof(EVENTHOOK));
PEVENTHOOK pEH = UserHeapAlloc(sizeof(EVENTHOOK));
if ((gpsi->SrvEventActivity & GetMaskFromEvent(event))) return 0; // No events to run.
LRESULT Result = co_IntCallEventProc(peh->Self,
if ((pEH->Thread != PsGetCurrentThread()) && (pEH->Thread != NULL))
{
// Post it in message queue.
return IntCallLowLevelEvent(pEH, event, hwnd, idObject, idChild);
}
LRESULT Result = co_IntCallEventProc(pEH->Self,
event,
hwnd,
idObject,
idChild,
(DWORD)(NtCurrentTeb()->Cid).UniqueThread,
TimeStamp(),
peh->Proc);
pEH->Proc);
return Result;
}
@ -86,7 +219,9 @@ NtUserNotifyWinEvent(
LONG idObject,
LONG idChild)
{
UserEnterExclusive();
UNIMPLEMENTED
UserLeave();
}
HWINEVENTHOOK
@ -101,12 +236,98 @@ NtUserSetWinEventHook(
DWORD idThread,
UINT dwflags)
{
gpsi->SrvEventActivity |= GetMaskFromEvent(eventMin);
gpsi->SrvEventActivity &= ~GetMaskFromEvent(eventMin);
PEVENTHOOK pEH;
HWINEVENTHOOK Ret = NULL;
UNICODE_STRING ModuleName;
NTSTATUS Status;
HANDLE Handle;
UNIMPLEMENTED
UserEnterExclusive();
return 0;
DPRINT1("WARNING! Use at your own risk! Function is UNIMPLEMENTED!\n");
if ( !GlobalEvents )
{
GlobalEvents = ExAllocatePoolWithTag(PagedPool, sizeof(EVENTTABLE), TAG_HOOK);
GlobalEvents->Counts = 0;
InitializeListHead(&GlobalEvents->Events);
}
pEH = UserCreateObject(gHandleTable, &Handle, otEvent, sizeof(EVENTHOOK));
if (pEH)
{
InsertTailList(&GlobalEvents->Events, &pEH->Chain);
GlobalEvents->Counts++;
pEH->Self = Handle;
pEH->Thread = PsGetCurrentThread();
pEH->eventMin = eventMin;
pEH->eventMax = eventMax;
pEH->idProcess = idProcess;
pEH->idThread = idThread;
pEH->Ansi = FALSE;
pEH->Flags = dwflags;
if ((dwflags & WINEVENT_INCONTEXT) && !hmodWinEventProc)
{
SetLastWin32Error(ERROR_HOOK_NEEDS_HMOD);
goto SetEventExit;
}
if (eventMin > eventMax)
{
SetLastWin32Error(ERROR_INVALID_HOOK_FILTER);
goto SetEventExit;
}
if (NULL != hmodWinEventProc)
{
Status = MmCopyFromCaller(&ModuleName, puString, sizeof(UNICODE_STRING));
if (! NT_SUCCESS(Status))
{
UserDereferenceObject(pEH);
IntRemoveEvent(pEH);
SetLastNtError(Status);
goto SetEventExit;
}
pEH->ModuleName.Buffer = ExAllocatePoolWithTag(PagedPool,
ModuleName.MaximumLength,
TAG_HOOK);
if (NULL == pEH->ModuleName.Buffer)
{
UserDereferenceObject(pEH);
IntRemoveEvent(pEH);
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
goto SetEventExit;
}
pEH->ModuleName.MaximumLength = ModuleName.MaximumLength;
Status = MmCopyFromCaller(pEH->ModuleName.Buffer,
ModuleName.Buffer,
ModuleName.MaximumLength);
if (! NT_SUCCESS(Status))
{
ExFreePool(pEH->ModuleName.Buffer);
UserDereferenceObject(pEH);
IntRemoveEvent(pEH);
SetLastNtError(Status);
goto SetEventExit;
}
pEH->ModuleName.Length = ModuleName.Length;
pEH->Proc = (void *)((char *)lpfnWinEventProc - (char *)hmodWinEventProc);
}
else
pEH->Proc = lpfnWinEventProc;
Ret = Handle;
/*
Now we are good, set the Events and counts.
*/
IntEventUpCount(eventMin, eventMax);
}
SetEventExit:
UserLeave();
return Ret;
}
@ -115,9 +336,22 @@ STDCALL
NtUserUnhookWinEvent(
HWINEVENTHOOK hWinEventHook)
{
UNIMPLEMENTED
PEVENTHOOK pEH;
BOOL Ret = FALSE;
return FALSE;
UserEnterExclusive();
DPRINT1("WARNING! Use at your own risk! Function is UNIMPLEMENTED!\n");
pEH = (PEVENTHOOK)UserGetObject(gHandleTable, hWinEventHook, otEvent);
if (pEH)
{
IntEventDownCount(pEH->eventMin, pEH->eventMax);
Ret = IntRemoveEvent(pEH);
}
UserLeave();
return Ret;
}
/* EOF */

View file

@ -281,7 +281,7 @@ IntCallLowLevelHook(PHOOK Hook, INT Code, WPARAM wParam, LPARAM lParam)
lParam,
5000,
TRUE,
TRUE,
MSQ_ISHOOK,
&uResult);
return NT_SUCCESS(Status) ? uResult : 0;

View file

@ -1555,7 +1555,7 @@ co_IntSendMessageTimeoutSingle(HWND hWnd,
lParam,
uTimeout,
(uFlags & SMTO_BLOCK),
FALSE,
MSQ_NORMAL,
uResult);
}
while ((STATUS_TIMEOUT == Status) &&

View file

@ -929,13 +929,20 @@ co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
InsertTailList(&MessageQueue->LocalDispatchingMessagesHead,
&Message->ListEntry);
if (Message->HookMessage)
if (Message->HookMessage == MSQ_ISHOOK)
{
Result = co_HOOK_CallHooks(Message->Msg.message,
(INT)(INT_PTR)Message->Msg.hwnd,
Message->Msg.wParam,
Message->Msg.lParam);
}
else if (Message->HookMessage == MSQ_ISEVENT)
{
Result = co_EVENT_CallEvents( Message->Msg.message,
Message->Msg.hwnd,
(LONG) Message->Msg.wParam,
(LONG) Message->Msg.lParam);
}
else
{
/* Call the window procedure. */
@ -1090,7 +1097,7 @@ MsqSendNotifyMessage(PUSER_MESSAGE_QUEUE MessageQueue,
NTSTATUS FASTCALL
co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam,
UINT uTimeout, BOOL Block, BOOL HookMessage,
UINT uTimeout, BOOL Block, INT HookMessage,
ULONG_PTR *uResult)
{
PUSER_SENT_MESSAGE Message;