- 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 */ PETHREAD Thread; /* Thread owning the event */
UINT eventMin; UINT eventMin;
UINT eventMax; UINT eventMax;
DWORD idProcess;
DWORD idThread;
WINEVENTPROC Proc; /* Event function */ WINEVENTPROC Proc; /* Event function */
BOOLEAN Ansi; /* Is it an Ansi event? */ BOOLEAN Ansi; /* Is it an Ansi event? */
ULONG Flags; /* Some internal flags */ ULONG Flags; /* Some internal flags */

View file

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

View file

@ -4,8 +4,9 @@
#define NDEBUG #define NDEBUG
#include <debug.h> #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 *********************************************************/ /* PRIVATE FUNCTIONS *********************************************************/
@ -43,6 +44,88 @@ GetMaskFromEvent(DWORD Event)
return Ret; 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 static
DWORD DWORD
@ -52,6 +135,48 @@ TimeStamp(VOID)
return (DWORD)((ULONGLONG)SharedUserData->TickCountLowDeprecated * SharedUserData->TickCountMultiplier / 16777216); 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 *****************************************************************/ /* FUNCTIONS *****************************************************************/
LRESULT LRESULT
@ -62,18 +187,26 @@ co_EVENT_CallEvents( DWORD event,
LONG idChild) LONG idChild)
{ {
PEVENTHOOK peh = UserHeapAlloc(sizeof(EVENTHOOK)); PEVENTHOOK pEH = UserHeapAlloc(sizeof(EVENTHOOK));
if ((gpsi->SrvEventActivity & GetMaskFromEvent(event))) return 0; // No events to run. 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, event,
hwnd, hwnd,
idObject, idObject,
idChild, idChild,
(DWORD)(NtCurrentTeb()->Cid).UniqueThread, (DWORD)(NtCurrentTeb()->Cid).UniqueThread,
TimeStamp(), TimeStamp(),
peh->Proc); pEH->Proc);
return Result; return Result;
} }
@ -86,7 +219,9 @@ NtUserNotifyWinEvent(
LONG idObject, LONG idObject,
LONG idChild) LONG idChild)
{ {
UserEnterExclusive();
UNIMPLEMENTED UNIMPLEMENTED
UserLeave();
} }
HWINEVENTHOOK HWINEVENTHOOK
@ -101,12 +236,98 @@ NtUserSetWinEventHook(
DWORD idThread, DWORD idThread,
UINT dwflags) UINT dwflags)
{ {
gpsi->SrvEventActivity |= GetMaskFromEvent(eventMin); PEVENTHOOK pEH;
gpsi->SrvEventActivity &= ~GetMaskFromEvent(eventMin); 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( NtUserUnhookWinEvent(
HWINEVENTHOOK hWinEventHook) 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 */ /* EOF */

View file

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

View file

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

View file

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