From 6d4ff1a0c03695e6da1c9d71de6b27814101ce30 Mon Sep 17 00:00:00 2001 From: James Tabor Date: Sat, 2 Aug 2008 00:38:01 +0000 Subject: [PATCH] - 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 --- .../subsystems/win32/win32k/include/window.h | 2 + .../subsystems/win32/win32k/ntuser/event.c | 296 ++++++++++-------- reactos/subsystems/win32/win32k/ntuser/hook.c | 15 +- .../subsystems/win32/win32k/ntuser/window.c | 2 +- 4 files changed, 179 insertions(+), 136 deletions(-) diff --git a/reactos/subsystems/win32/win32k/include/window.h b/reactos/subsystems/win32/win32k/include/window.h index 3358d31c48f..d501ff757bf 100644 --- a/reactos/subsystems/win32/win32k/include/window.h +++ b/reactos/subsystems/win32/win32k/include/window.h @@ -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 */ diff --git a/reactos/subsystems/win32/win32k/ntuser/event.c b/reactos/subsystems/win32/win32k/ntuser/event.c index 821e5b842aa..7559422dda1 100644 --- a/reactos/subsystems/win32/win32k/ntuser/event.c +++ b/reactos/subsystems/win32/win32k/ntuser/event.c @@ -4,9 +4,14 @@ #define NDEBUG #include +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); } diff --git a/reactos/subsystems/win32/win32k/ntuser/hook.c b/reactos/subsystems/win32/win32k/ntuser/hook.c index 52c4a4b2819..134e974f4c4 100644 --- a/reactos/subsystems/win32/win32k/ntuser/hook.c +++ b/reactos/subsystems/win32/win32k/ntuser/hook.c @@ -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) diff --git a/reactos/subsystems/win32/win32k/ntuser/window.c b/reactos/subsystems/win32/win32k/ntuser/window.c index bc1a7ac23bb..6dfd8424a4d 100644 --- a/reactos/subsystems/win32/win32k/ntuser/window.c +++ b/reactos/subsystems/win32/win32k/ntuser/window.c @@ -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) {