Author: jimtabor Date: Thu Jul 31 18:48:35 2008 New Revision: 34988
URL: http://svn.reactos.org/svn/reactos?rev=34988&view=rev Log: - 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.
Modified: trunk/reactos/subsystems/win32/win32k/include/hook.h trunk/reactos/subsystems/win32/win32k/include/msgqueue.h trunk/reactos/subsystems/win32/win32k/ntuser/event.c trunk/reactos/subsystems/win32/win32k/ntuser/hook.c trunk/reactos/subsystems/win32/win32k/ntuser/message.c trunk/reactos/subsystems/win32/win32k/ntuser/msgqueue.c
Modified: trunk/reactos/subsystems/win32/win32k/include/hook.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/inc... ============================================================================== --- trunk/reactos/subsystems/win32/win32k/include/hook.h [iso-8859-1] (original) +++ trunk/reactos/subsystems/win32/win32k/include/hook.h [iso-8859-1] Thu Jul 31 18:48:35 2008 @@ -33,6 +33,8 @@ 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 */
Modified: trunk/reactos/subsystems/win32/win32k/include/msgqueue.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/inc... ============================================================================== --- trunk/reactos/subsystems/win32/win32k/include/msgqueue.h [iso-8859-1] (original) +++ trunk/reactos/subsystems/win32/win32k/include/msgqueue.h [iso-8859-1] Thu Jul 31 18:48:35 2008 @@ -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 @@ 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 @@ 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);
Modified: trunk/reactos/subsystems/win32/win32k/ntuser/event.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/ntu... ============================================================================== --- trunk/reactos/subsystems/win32/win32k/ntuser/event.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/win32/win32k/ntuser/event.c [iso-8859-1] Thu Jul 31 18:48:35 2008 @@ -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 @@ 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 @@ -50,6 +133,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 *****************************************************************/ @@ -62,18 +187,26 @@ 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 @@ LONG idObject, LONG idChild) { + UserEnterExclusive(); UNIMPLEMENTED + UserLeave(); }
HWINEVENTHOOK @@ -101,12 +236,98 @@ DWORD idThread, UINT dwflags) { - gpsi->SrvEventActivity |= GetMaskFromEvent(eventMin); - gpsi->SrvEventActivity &= ~GetMaskFromEvent(eventMin); - - UNIMPLEMENTED - - return 0; + PEVENTHOOK pEH; + HWINEVENTHOOK Ret = NULL; + UNICODE_STRING ModuleName; + NTSTATUS Status; + HANDLE Handle; + + UserEnterExclusive(); + + 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 @@ NtUserUnhookWinEvent( HWINEVENTHOOK hWinEventHook) { - UNIMPLEMENTED - - return FALSE; + PEVENTHOOK pEH; + BOOL Ret = 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 */
Modified: trunk/reactos/subsystems/win32/win32k/ntuser/hook.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/ntu... ============================================================================== --- trunk/reactos/subsystems/win32/win32k/ntuser/hook.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/win32/win32k/ntuser/hook.c [iso-8859-1] Thu Jul 31 18:48:35 2008 @@ -281,7 +281,7 @@ lParam, 5000, TRUE, - TRUE, + MSQ_ISHOOK, &uResult);
return NT_SUCCESS(Status) ? uResult : 0;
Modified: trunk/reactos/subsystems/win32/win32k/ntuser/message.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/ntu... ============================================================================== --- trunk/reactos/subsystems/win32/win32k/ntuser/message.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/win32/win32k/ntuser/message.c [iso-8859-1] Thu Jul 31 18:48:35 2008 @@ -1555,7 +1555,7 @@ lParam, uTimeout, (uFlags & SMTO_BLOCK), - FALSE, + MSQ_NORMAL, uResult); } while ((STATUS_TIMEOUT == Status) &&
Modified: trunk/reactos/subsystems/win32/win32k/ntuser/msgqueue.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/ntu... ============================================================================== --- trunk/reactos/subsystems/win32/win32k/ntuser/msgqueue.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/win32/win32k/ntuser/msgqueue.c [iso-8859-1] Thu Jul 31 18:48:35 2008 @@ -929,12 +929,19 @@ 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 { @@ -1090,7 +1097,7 @@ 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;