- Implemented NotifyWinEvent, SetWinEventHook and UnhookWinEvent.

- I only enables test_winevents(), test_set_hook() and all related with wine Msg tests. The test takes a while to run due to the IsWinEventHookInstalled check. I optimized our mask set to take this into account. The results are, the test is slow and our code is fast.
- We pass all Event and Local Hook tests. Will research the problem with global hooks and finish it up.

svn path=/trunk/; revision=35022
This commit is contained in:
James Tabor 2008-08-02 00:38:01 +00:00
parent 4509402aa9
commit 6d4ff1a0c0
4 changed files with 179 additions and 136 deletions

View file

@ -167,6 +167,8 @@ IntShowOwnedPopups( PWINDOW_OBJECT owner, BOOL fShow );
LRESULT FASTCALL
IntDefWindowProc( PWINDOW_OBJECT Window, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL Ansi);
VOID FASTCALL IntNotifyWinEvent(DWORD, PWINDOW_OBJECT, LONG, LONG);
#endif /* _WIN32K_WINDOW_H */
/* EOF */

View file

@ -4,9 +4,14 @@
#define NDEBUG
#include <debug.h>
typedef struct _EVENTPACK
{
PEVENTHOOK pEH;
LONG idObject;
LONG idChild;
} EVENTPACK, *PEVENTPACK;
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 *********************************************************/
@ -47,92 +52,38 @@ GetMaskFromEvent(DWORD Event)
static
VOID
FASTCALL
IntEventUpCount(ULONG eventMin, ULONG eventMax)
IntSetSrvEventMask( UINT EventMin, UINT EventMax)
{
INT i, Min, Max;
if ( eventMin >= EVENT_SYSTEM_SOUND && eventMax <= EVENT_SYSTEM_MINIMIZEEND)
UINT event;
DPRINT("SetSrvEventMask 1\n");
for ( event = EventMin; event <= EventMax; event++)
{
for (i = eventMin; i < eventMax; i++)
if ((event >= EVENT_SYSTEM_SOUND && event <= EVENT_SYSTEM_MINIMIZEEND) ||
(event >= EVENT_CONSOLE_CARET && event <= EVENT_CONSOLE_END_APPLICATION) ||
(event >= EVENT_OBJECT_CREATE && event <= EVENT_OBJECT_ACCELERATORCHANGE))
{
gpsi->SrvEventActivity |= GetMaskFromEvent(i);
EventSys[i]++;
gpsi->SrvEventActivity |= GetMaskFromEvent(event);
}
if (event > EVENT_SYSTEM_MINIMIZEEND && event < EVENT_CONSOLE_CARET)
{
event = EVENT_CONSOLE_CARET-1;
gpsi->SrvEventActivity |= GetMaskFromEvent(event);
}
if (event > EVENT_CONSOLE_END_APPLICATION && event < EVENT_OBJECT_CREATE )
{
event = EVENT_OBJECT_CREATE-1;
gpsi->SrvEventActivity |= GetMaskFromEvent(event);
}
if (event > EVENT_OBJECT_ACCELERATORCHANGE && event < EVENT_MAX)
{
event = EVENT_MAX-1;
gpsi->SrvEventActivity |= GetMaskFromEvent(event);
break;
}
}
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
FASTCALL
TimeStamp(VOID)
{
return (DWORD)((ULONGLONG)SharedUserData->TickCountLowDeprecated * SharedUserData->TickCountMultiplier / 16777216);
if (!gpsi->SrvEventActivity)
gpsi->SrvEventActivity |= SRV_EVENT_RUNNING; // Set something.
DPRINT("SetSrvEventMask 2 : %x\n", gpsi->SrvEventActivity);
}
static
@ -146,14 +97,19 @@ IntCallLowLevelEvent( PEVENTHOOK pEH,
{
NTSTATUS Status;
ULONG_PTR uResult;
EVENTPACK EP;
EP.pEH = pEH;
EP.idObject = idObject;
EP.idChild = idChild;
/* 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,
0,
(LPARAM)&EP,
5000,
TRUE,
MSQ_ISEVENT,
@ -162,6 +118,7 @@ IntCallLowLevelEvent( PEVENTHOOK pEH,
return NT_SUCCESS(Status) ? uResult : 0;
}
static
BOOL
FASTCALL
@ -171,6 +128,7 @@ IntRemoveEvent(PEVENTHOOK pEH)
{
RemoveEntryList(&pEH->Chain);
GlobalEvents->Counts--;
if (!GlobalEvents->Counts) gpsi->SrvEventActivity = 0;
UserDeleteObject(pEH->Self, otEvent);
return TRUE;
}
@ -186,30 +144,73 @@ co_EVENT_CallEvents( DWORD event,
LONG idObject,
LONG idChild)
{
PEVENTHOOK pEH;
LRESULT Result;
PEVENTPACK pEP = (PEVENTPACK)idChild;
PEVENTHOOK pEH = UserHeapAlloc(sizeof(EVENTHOOK));
if ((gpsi->SrvEventActivity & GetMaskFromEvent(event))) return 0; // No events to run.
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 = pEP->pEH;
Result = co_IntCallEventProc( pEH->Self,
event,
hwnd,
pEP->idObject,
pEP->idChild,
(DWORD)(NtCurrentTeb()->Cid).UniqueThread,
(DWORD)EngGetTickCount(),
pEH->Proc);
return Result;
}
VOID
FASTCALL
IntNotifyWinEvent(
DWORD Event,
PWINDOW_OBJECT Window,
LONG idObject,
LONG idChild)
{
PEVENTHOOK pEH;
LRESULT Result;
if (!GlobalEvents->Counts) return;
pEH = (PEVENTHOOK)GlobalEvents->Events.Flink;
do
{
UserReferenceObject(pEH);
// Must be inside the event window.
if ( (pEH->eventMin <= Event) && (pEH->eventMax >= Event))
{
if ((pEH->Thread != PsGetCurrentThread()) && (pEH->Thread != NULL))
{ // if all process || all thread || other thread same process
if (!(pEH->idProcess) || !(pEH->idThread) ||
((DWORD)(NtCurrentTeb()->Cid).UniqueProcess == pEH->idProcess))
{
Result = IntCallLowLevelEvent(pEH, Event, Window->hSelf, idObject, idChild);
}
}// if ^skip own thread && ((Pid && CPid == Pid && ^skip own process) || all process)
else if ( !(pEH->Flags & WINEVENT_SKIPOWNTHREAD) &&
( ((pEH->idProcess &&
(DWORD)(NtCurrentTeb()->Cid).UniqueProcess == pEH->idProcess) &&
!(pEH->Flags & WINEVENT_SKIPOWNPROCESS)) ||
!pEH->idProcess ) )
{
Result = co_IntCallEventProc( pEH->Self,
Event,
Window->hSelf,
idObject,
idChild,
(DWORD)(NtCurrentTeb()->Cid).UniqueThread,
(DWORD)EngGetTickCount(),
pEH->Proc);
}
}
UserDereferenceObject(pEH);
pEH = (PEVENTHOOK)pEH->Chain.Flink;
} while (pEH != (PEVENTHOOK)&GlobalEvents->Events.Flink);
}
VOID
STDCALL
@ -219,8 +220,22 @@ NtUserNotifyWinEvent(
LONG idObject,
LONG idChild)
{
PWINDOW_OBJECT Window = NULL;
USER_REFERENCE_ENTRY Ref;
UserEnterExclusive();
UNIMPLEMENTED
/* Validate input */
if (hWnd && (hWnd != INVALID_HANDLE_VALUE) && !(Window = UserGetWindowObject(hWnd)))
{
return;
}
if (gpsi->SrvEventActivity & GetMaskFromEvent(Event))
{
UserRefObjectCo(Window, &Ref);
IntNotifyWinEvent( Event, Window, idObject, idChild);
UserDerefObjectCo(Window);
}
UserLeave();
}
@ -241,11 +256,10 @@ NtUserSetWinEventHook(
UNICODE_STRING ModuleName;
NTSTATUS Status;
HANDLE Handle;
PETHREAD Thread = NULL;
UserEnterExclusive();
DPRINT1("WARNING! Use at your own risk! Function is UNIMPLEMENTED!\n");
if ( !GlobalEvents )
{
GlobalEvents = ExAllocatePoolWithTag(PagedPool, sizeof(EVENTTABLE), TAG_HOOK);
@ -253,6 +267,34 @@ NtUserSetWinEventHook(
InitializeListHead(&GlobalEvents->Events);
}
if (eventMin > eventMax)
{
SetLastWin32Error(ERROR_INVALID_HOOK_FILTER);
goto SetEventExit;
}
if (!lpfnWinEventProc)
{
SetLastWin32Error(ERROR_INVALID_FILTER_PROC);
goto SetEventExit;
}
if ((dwflags & WINEVENT_INCONTEXT) && !hmodWinEventProc)
{
SetLastWin32Error(ERROR_HOOK_NEEDS_HMOD);
goto SetEventExit;
}
if (idThread)
{
Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)idThread, &Thread);
if (!NT_SUCCESS(Status))
{
SetLastWin32Error(ERROR_INVALID_THREAD_ID);
goto SetEventExit;
}
}
pEH = UserCreateObject(gHandleTable, &Handle, otEvent, sizeof(EVENTHOOK));
if (pEH)
{
@ -260,7 +302,10 @@ NtUserSetWinEventHook(
GlobalEvents->Counts++;
pEH->Self = Handle;
pEH->Thread = PsGetCurrentThread();
if (Thread)
pEH->Thread = Thread;
else
pEH->Thread = PsGetCurrentThread();
pEH->eventMin = eventMin;
pEH->eventMax = eventMax;
pEH->idProcess = idProcess;
@ -268,21 +313,13 @@ NtUserSetWinEventHook(
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));
Status = MmCopyFromCaller(&ModuleName,
puString,
sizeof(UNICODE_STRING));
if (! NT_SUCCESS(Status))
{
UserDereferenceObject(pEH);
@ -290,9 +327,11 @@ NtUserSetWinEventHook(
SetLastNtError(Status);
goto SetEventExit;
}
pEH->ModuleName.Buffer = ExAllocatePoolWithTag(PagedPool,
ModuleName.MaximumLength,
TAG_HOOK);
if (NULL == pEH->ModuleName.Buffer)
{
UserDereferenceObject(pEH);
@ -300,10 +339,13 @@ NtUserSetWinEventHook(
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);
@ -312,25 +354,24 @@ NtUserSetWinEventHook(
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);
IntSetSrvEventMask( eventMin, eventMax);
}
SetEventExit:
if (Thread) ObDereferenceObject(Thread);
UserLeave();
return Ret;
}
BOOL
STDCALL
NtUserUnhookWinEvent(
@ -341,12 +382,9 @@ NtUserUnhookWinEvent(
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);
}

View file

@ -974,12 +974,18 @@ NtUserSetWindowsHookEx(
DPRINT("Enter NtUserSetWindowsHookEx\n");
UserEnterExclusive();
if (HookId < WH_MINHOOK || WH_MAXHOOK < HookId || NULL == HookProc)
if (HookId < WH_MINHOOK || WH_MAXHOOK < HookId )
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
RETURN( NULL);
}
if (!HookProc)
{
SetLastWin32Error(ERROR_INVALID_FILTER_PROC);
RETURN( NULL);
}
ClientInfo = GetWin32ClientInfo();
if (ThreadId) /* thread-local hook */
@ -1029,7 +1035,7 @@ NtUserSetWindowsHookEx(
}
else if (NULL == Mod)
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
SetLastWin32Error(ERROR_HOOK_NEEDS_HMOD);
RETURN( NULL);
}
else
@ -1039,10 +1045,7 @@ NtUserSetWindowsHookEx(
Global = TRUE;
}
/* We only (partially) support local WH_CBT hooks and
* WH_KEYBOARD_LL, WH_MOUSE_LL and WH_GETMESSAGE hooks for now
*/
if (Global ||
if ( Global ||
WH_DEBUG == HookId ||
WH_JOURNALPLAYBACK == HookId ||
WH_JOURNALRECORD == HookId)

View file

@ -2059,7 +2059,7 @@ AllocErr:
RETURN((HWND)0);
}
#if 0
Result = co_EVENT_CallEvents(EVENT_OBJECT_CREATE, Window->hSelf, OBJID_WINDOW, 0);
Result = IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_WINDOW, 0);
if (Result == (LRESULT)-1)
{