diff --git a/reactos/subsystems/win32/win32k/include/hook.h b/reactos/subsystems/win32/win32k/include/hook.h index 221372b615b..0a020bfaed1 100644 --- a/reactos/subsystems/win32/win32k/include/hook.h +++ b/reactos/subsystems/win32/win32k/include/hook.h @@ -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 */ diff --git a/reactos/subsystems/win32/win32k/include/msgqueue.h b/reactos/subsystems/win32/win32k/include/msgqueue.h index 8a009dc0d8d..06ee33d3261 100644 --- a/reactos/subsystems/win32/win32k/include/msgqueue.h +++ b/reactos/subsystems/win32/win32k/include/msgqueue.h @@ -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); diff --git a/reactos/subsystems/win32/win32k/ntuser/event.c b/reactos/subsystems/win32/win32k/ntuser/event.c index bdec573132e..821e5b842aa 100644 --- a/reactos/subsystems/win32/win32k/ntuser/event.c +++ b/reactos/subsystems/win32/win32k/ntuser/event.c @@ -4,8 +4,9 @@ #define NDEBUG #include -//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 */ diff --git a/reactos/subsystems/win32/win32k/ntuser/hook.c b/reactos/subsystems/win32/win32k/ntuser/hook.c index 84a2679d250..52c4a4b2819 100644 --- a/reactos/subsystems/win32/win32k/ntuser/hook.c +++ b/reactos/subsystems/win32/win32k/ntuser/hook.c @@ -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; diff --git a/reactos/subsystems/win32/win32k/ntuser/message.c b/reactos/subsystems/win32/win32k/ntuser/message.c index ac1a77cca50..0889c717191 100644 --- a/reactos/subsystems/win32/win32k/ntuser/message.c +++ b/reactos/subsystems/win32/win32k/ntuser/message.c @@ -1555,7 +1555,7 @@ co_IntSendMessageTimeoutSingle(HWND hWnd, lParam, uTimeout, (uFlags & SMTO_BLOCK), - FALSE, + MSQ_NORMAL, uResult); } while ((STATUS_TIMEOUT == Status) && diff --git a/reactos/subsystems/win32/win32k/ntuser/msgqueue.c b/reactos/subsystems/win32/win32k/ntuser/msgqueue.c index ac2bc371555..d472d8ec2cb 100644 --- a/reactos/subsystems/win32/win32k/ntuser/msgqueue.c +++ b/reactos/subsystems/win32/win32k/ntuser/msgqueue.c @@ -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;