diff --git a/reactos/win32ss/include/callback.h b/reactos/win32ss/include/callback.h index 51daaa221e7..1af7552ae7c 100644 --- a/reactos/win32ss/include/callback.h +++ b/reactos/win32ss/include/callback.h @@ -79,6 +79,8 @@ typedef struct _EVENTPROC_CALLBACK_ARGUMENTS DWORD dwEventThread; DWORD dwmsEventTime; WINEVENTPROC Proc; + INT Mod; + ULONG_PTR offPfn; } EVENTPROC_CALLBACK_ARGUMENTS, *PEVENTPROC_CALLBACK_ARGUMENTS; typedef struct _LOADMENU_CALLBACK_ARGUMENTS diff --git a/reactos/win32ss/user/ntuser/callback.c b/reactos/win32ss/user/ntuser/callback.c index 705cab4a8e8..3ad414be6b5 100644 --- a/reactos/win32ss/user/ntuser/callback.c +++ b/reactos/win32ss/user/ntuser/callback.c @@ -805,7 +805,9 @@ co_IntCallEventProc(HWINEVENTHOOK hook, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime, - WINEVENTPROC Proc) + WINEVENTPROC Proc, + INT Mod, + ULONG_PTR offPfn) { LRESULT Result = 0; NTSTATUS Status; @@ -830,6 +832,8 @@ co_IntCallEventProc(HWINEVENTHOOK hook, Common->dwEventThread = dwEventThread; Common->dwmsEventTime = dwmsEventTime; Common->Proc = Proc; + Common->Mod = Mod; + Common->offPfn = offPfn; ResultPointer = NULL; ResultLength = sizeof(LRESULT); diff --git a/reactos/win32ss/user/ntuser/callback.h b/reactos/win32ss/user/ntuser/callback.h index 9351e4cdb3e..d60986b6fd9 100644 --- a/reactos/win32ss/user/ntuser/callback.h +++ b/reactos/win32ss/user/ntuser/callback.h @@ -42,7 +42,9 @@ co_IntCallEventProc(HWINEVENTHOOK hook, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime, - WINEVENTPROC Proc); + WINEVENTPROC Proc, + INT Mod, + ULONG_PTR offPfn); VOID FASTCALL IntCleanupThreadCallbacks(PTHREADINFO W32Thread); diff --git a/reactos/win32ss/user/ntuser/event.c b/reactos/win32ss/user/ntuser/event.c index d51fde73348..e4f9cc93232 100644 --- a/reactos/win32ss/user/ntuser/event.c +++ b/reactos/win32ss/user/ntuser/event.c @@ -14,6 +14,7 @@ typedef struct _EVENTPACK PEVENTHOOK pEH; LONG idObject; LONG idChild; + LONG idThread; } EVENTPACK, *PEVENTPACK; static PEVENTTABLE GlobalEvents = NULL; @@ -98,11 +99,11 @@ IntCallLowLevelEvent( PEVENTHOOK pEH, DWORD event, HWND hwnd, LONG idObject, - LONG idChild) + LONG idChild, + LONG idThread) { - NTSTATUS Status; PEVENTPACK pEP; - ULONG_PTR uResult = 0; + MSG Msg; pEP = ExAllocatePoolWithTag(NonPagedPool, sizeof(EVENTPACK), TAG_HOOK); if (!pEP) return 0; @@ -110,23 +111,16 @@ IntCallLowLevelEvent( PEVENTHOOK pEH, pEP->pEH = pEH; pEP->idObject = idObject; pEP->idChild = idChild; + pEP->idThread = idThread; - /* FIXME: Should get timeout from - * HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */ - Status = co_MsqSendMessage( pEH->head.pti, - hwnd, - event, - 0, - (LPARAM)pEP, - 300, - TRUE, - MSQ_ISEVENT, - &uResult); - if (!NT_SUCCESS(Status)) - { - ExFreePoolWithTag(pEP, TAG_HOOK); - } - return NT_SUCCESS(Status) ? uResult : 0; + Msg.message = event; + Msg.hwnd = hwnd; + Msg.wParam = 0; + Msg.lParam = POSTEVENT_NWE; + Msg.time = 0; + + MsqPostMessage(pEH->head.pti, &Msg, FALSE, QS_EVENT, POSTEVENT_NWE, (LONG_PTR)pEP); + return 0; } BOOLEAN @@ -155,7 +149,7 @@ IntRemoveEvent(PVOID Object) LRESULT APIENTRY co_EVENT_CallEvents( DWORD event, - HWND hwnd, + HWND hwnd, UINT_PTR idObject, LONG_PTR idChild) { @@ -164,15 +158,17 @@ co_EVENT_CallEvents( DWORD event, PEVENTPACK pEP = (PEVENTPACK)idChild; pEH = pEP->pEH; - + TRACE("Dispatch Event 0x%x, idObject %d hwnd %p\n", event, idObject, hwnd); Result = co_IntCallEventProc( UserHMGetHandle(pEH), event, hwnd, pEP->idObject, pEP->idChild, - PtrToUint(NtCurrentTeb()->ClientId.UniqueThread), + pEP->idThread, (DWORD)EngGetTickCount(), - pEH->Proc); + pEH->Proc, + pEH->ihmod, + pEH->offPfn); ExFreePoolWithTag(pEP, TAG_HOOK); return Result; @@ -211,29 +207,19 @@ IntNotifyWinEvent( if (!pEH) break; UserReferenceObject(pEH); // Must be inside the event window. - if ( (pEH->eventMin <= Event) && (pEH->eventMax >= Event)) + if ( Event >= pEH->eventMin && Event <= pEH->eventMax ) { // if all process || all thread || other thread same process // if ^skip own thread && ((Pid && CPid == Pid && ^skip own process) || all process) - if ( (!pEH->idProcess || pEH->idProcess == PtrToUint(pti->pEThread->Cid.UniqueProcess)) && - (!(pEH->Flags & WINEVENT_SKIPOWNPROCESS) || pEH->head.pti->ppi != pti->ppi) && - (!pEH->idThread || pEH->idThread == PtrToUint(pti->pEThread->Cid.UniqueThread)) && - (!(pEH->Flags & WINEVENT_SKIPOWNTHREAD) || pEH->head.pti != pti) && - pEH->head.pti->rpdesk == ptiCurrent->rpdesk ) // Same as hooks. + if (!( (pEH->idProcess && pEH->idProcess != PtrToUint(pti->pEThread->Cid.UniqueProcess)) || + (pEH->Flags & WINEVENT_SKIPOWNPROCESS && pEH->head.pti->ppi == pti->ppi) || + (pEH->idThread && pEH->idThread != PtrToUint(pti->pEThread->Cid.UniqueThread)) || + (pEH->Flags & WINEVENT_SKIPOWNTHREAD && pEH->head.pti == pti) || + pEH->head.pti->rpdesk != ptiCurrent->rpdesk ) ) // Same as hooks. { - // Send message to the thread if pEH is not current. - if (pEH->head.pti != ptiCurrent) + if (pEH->Flags & WINEVENT_INCONTEXT) { - ERR("Global Event 0x%x, idObject %d\n", Event, idObject); - IntCallLowLevelEvent( pEH, - Event, - pWnd ? UserHMGetHandle(pWnd) : NULL, - idObject, - idChild); - } - else - { - ERR("Local Event 0x%x, idObject %d\n", Event, idObject); + TRACE("In Event 0x%x, idObject %d hwnd %p\n", Event, idObject, pWnd ? UserHMGetHandle(pWnd) : NULL); co_IntCallEventProc( UserHMGetHandle(pEH), Event, pWnd ? UserHMGetHandle(pWnd) : NULL, @@ -241,7 +227,19 @@ IntNotifyWinEvent( idChild, PtrToUint(NtCurrentTeb()->ClientId.UniqueThread), (DWORD)EngGetTickCount(), - pEH->Proc); + pEH->Proc, + pEH->ihmod, + pEH->offPfn); + } + else + { + TRACE("Out Event 0x%x, idObject %d hwnd %p\n", Event, idObject, pWnd ? UserHMGetHandle(pWnd) : NULL); + IntCallLowLevelEvent( pEH, + Event, + pWnd ? UserHMGetHandle(pWnd) : NULL, + idObject, + idChild, + PtrToUint(NtCurrentTeb()->ClientId.UniqueThread)); } } } @@ -329,10 +327,25 @@ NtUserSetWinEventHook( goto SetEventExit; } - if ((dwflags & WINEVENT_INCONTEXT) && !hmodWinEventProc) + if (dwflags & WINEVENT_INCONTEXT) { - EngSetLastError(ERROR_HOOK_NEEDS_HMOD); - goto SetEventExit; + if (!hmodWinEventProc) + { + ERR("Hook needs a module\n"); + EngSetLastError(ERROR_HOOK_NEEDS_HMOD); + goto SetEventExit; + } + if (puString == NULL) + { + ERR("Dll not found\n"); + EngSetLastError(ERROR_DLL_NOT_FOUND); + goto SetEventExit; + } + } + else + { + TRACE("Out of Context\n"); + hmodWinEventProc = 0; } if (idThread) @@ -371,14 +384,18 @@ NtUserSetWinEventHook( If WINEVENT_OUTOFCONTEXT just use proc.. Do this instead.... */ - if (NULL != hmodWinEventProc) + if (hmodWinEventProc != NULL) { pEH->offPfn = (ULONG_PTR)((char *)lpfnWinEventProc - (char *)hmodWinEventProc); pEH->ihmod = (INT)hmodWinEventProc; pEH->Proc = lpfnWinEventProc; } else + { pEH->Proc = lpfnWinEventProc; + pEH->offPfn = 0; + pEH->ihmod = (INT)hmodWinEventProc; + } UserDereferenceObject(pEH); diff --git a/reactos/win32ss/user/ntuser/hook.c b/reactos/win32ss/user/ntuser/hook.c index e1bb3a76932..19c117b6818 100644 --- a/reactos/win32ss/user/ntuser/hook.c +++ b/reactos/win32ss/user/ntuser/hook.c @@ -1251,6 +1251,23 @@ co_HOOK_CallHooks( INT HookId, TRACE("\nGlobal Hook posting to another Thread! %d\n",HookId ); Result = co_IntCallLowLevelHook(Hook, Code, wParam, lParam); } + else if (ptiHook->ppi == pti->ppi) + { + TRACE("\nGlobal Hook calling to another Thread! %d\n",HookId ); + ObReferenceObject(ptiHook->pEThread); + IntReferenceThreadInfo(ptiHook); + Result = co_IntCallHookProc( HookId, + Code, + wParam, + lParam, + Hook->Proc, + Hook->ihmod, + Hook->offPfn, + Hook->Ansi, + &Hook->ModuleName); + IntDereferenceThreadInfo(ptiHook); + ObDereferenceObject(ptiHook->pEThread); + } } else { /* Make the direct call. */ diff --git a/reactos/win32ss/user/ntuser/message.c b/reactos/win32ss/user/ntuser/message.c index 90ec8365c98..8c60008f5c9 100644 --- a/reactos/win32ss/user/ntuser/message.c +++ b/reactos/win32ss/user/ntuser/message.c @@ -652,6 +652,20 @@ static LRESULT handle_internal_message( PWND pWnd, UINT msg, WPARAM wparam, LPAR return 0; } +static LRESULT handle_internal_events( PTHREADINFO pti, PWND pWnd, LONG_PTR ExtraInfo, PMSG pMsg) +{ + LRESULT Result = 0; + + switch(pMsg->lParam) + { + case POSTEVENT_NWE: + { + co_EVENT_CallEvents( pMsg->message, pMsg->hwnd, pMsg->wParam, ExtraInfo); + } + } + return Result; +} + LRESULT FASTCALL IntDispatchMessage(PMSG pMsg) { @@ -845,7 +859,7 @@ co_IntPeekMessage( PMSG Msg, ExtraInfo, Msg )) { - return TRUE; + return TRUE; } /* Only check for quit messages if not posted messages pending. */ @@ -880,6 +894,24 @@ co_IntPeekMessage( PMSG Msg, return TRUE; } + /* Now check for System Event messages. */ + { + LONG_PTR eExtraInfo; + MSG eMsg; + if (MsqPeekMessage( pti, + TRUE, + Window, + 0, + 0, + QS_EVENT, + &eExtraInfo, + &eMsg )) + { + handle_internal_events( pti, Window, eExtraInfo, &eMsg); + continue; + } + } + /* Check for sent messages again. */ while ( co_MsqDispatchOneSentMessage(pti) ) { diff --git a/reactos/win32ss/user/ntuser/msgqueue.c b/reactos/win32ss/user/ntuser/msgqueue.c index c5b90994023..d5f13f5e649 100644 --- a/reactos/win32ss/user/ntuser/msgqueue.c +++ b/reactos/win32ss/user/ntuser/msgqueue.c @@ -800,13 +800,6 @@ co_MsqDispatchOneSentMessage(PTHREADINFO pti) Message->Msg.wParam, Message->Msg.lParam); } - else if (Message->HookMessage == MSQ_ISEVENT) - { // Direct Event Call processor - Result = co_EVENT_CallEvents( Message->Msg.message, - Message->Msg.hwnd, - Message->Msg.wParam, - Message->Msg.lParam); - } else if(Message->HookMessage == MSQ_INJECTMODULE) { Result = IntLoadHookModule(Message->Msg.message, @@ -2076,6 +2069,13 @@ MsqCleanupThreadMsgs(PTHREADINFO pti) { CurrentEntry = RemoveHeadList(&pti->PostedMessagesListHead); CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry); + if (CurrentMessage->dwQEvent) + { + if (CurrentMessage->dwQEvent == POSTEVENT_NWE) + { + ExFreePoolWithTag( (PVOID)CurrentMessage->ExtraInfo, TAG_HOOK); + } + } MsqDestroyMessage(CurrentMessage); } diff --git a/reactos/win32ss/user/ntuser/msgqueue.h b/reactos/win32ss/user/ntuser/msgqueue.h index 326e6831a6d..a3a19d3939e 100644 --- a/reactos/win32ss/user/ntuser/msgqueue.h +++ b/reactos/win32ss/user/ntuser/msgqueue.h @@ -3,8 +3,7 @@ #define MSQ_HUNG 5000 #define MSQ_NORMAL 0 #define MSQ_ISHOOK 1 -#define MSQ_ISEVENT 2 -#define MSQ_INJECTMODULE 3 +#define MSQ_INJECTMODULE 2 typedef struct _USER_MESSAGE { @@ -116,6 +115,8 @@ enum internal_event_message WM_ASYNC_DESTROYWINDOW }; +#define POSTEVENT_NWE 14 + BOOL FASTCALL MsqIsHung(PTHREADINFO pti); VOID CALLBACK HungAppSysTimerProc(HWND,UINT,UINT_PTR,DWORD); NTSTATUS FASTCALL co_MsqSendMessage(PTHREADINFO ptirec, diff --git a/reactos/win32ss/user/user32/windows/hook.c b/reactos/win32ss/user/user32/windows/hook.c index 3816128da2a..09dc07d033d 100644 --- a/reactos/win32ss/user/user32/windows/hook.c +++ b/reactos/win32ss/user/user32/windows/hook.c @@ -357,6 +357,9 @@ SetWinEventHook( { WCHAR ModuleName[MAX_PATH]; UNICODE_STRING USModuleName; + PUNICODE_STRING pusmodName; + + RtlInitUnicodeString(&USModuleName, NULL); if ((hmodWinEventProc != NULL) && (dwFlags & WINEVENT_INCONTEXT)) { @@ -365,16 +368,17 @@ SetWinEventHook( return NULL; } RtlInitUnicodeString(&USModuleName, ModuleName); + pusmodName = &USModuleName; } else { - RtlInitUnicodeString(&USModuleName, NULL); + pusmodName = NULL; } return NtUserSetWinEventHook(eventMin, eventMax, hmodWinEventProc, - &USModuleName, + pusmodName, pfnWinEventProc, idProcess, idThread, @@ -779,16 +783,53 @@ NTSTATUS WINAPI User32CallEventProcFromKernel(PVOID Arguments, ULONG ArgumentLength) { PEVENTPROC_CALLBACK_ARGUMENTS Common; + WINEVENTPROC Proc; + WCHAR module[MAX_PATH]; + DWORD len; + HMODULE mod = NULL; + BOOL Loaded = FALSE; Common = (PEVENTPROC_CALLBACK_ARGUMENTS) Arguments; - Common->Proc(Common->hook, - Common->event, - Common->hwnd, - Common->idObject, - Common->idChild, - Common->dwEventThread, - Common->dwmsEventTime); + Proc = Common->Proc; + + if (Common->offPfn && Common->Mod) + { // Validate the module again. + if (!(len = GetModuleFileNameW((HINSTANCE)Common->Mod, module, MAX_PATH)) || len >= MAX_PATH) + { + ERR("Error check for module!\n"); + Common->Mod = 0; + } + + if (Common->Mod && !(mod = GetModuleHandleW(module))) + { + TRACE("Reloading Event Module.\n"); + if (!(mod = LoadLibraryExW(module, NULL, LOAD_WITH_ALTERED_SEARCH_PATH))) + { + ERR("Failed to load Event Module.\n"); + } + else + { + Loaded = TRUE; // Free it only when loaded. + } + } + + if (mod) + { + TRACE("Loading Event Module. %S\n",module); + Proc = (WINEVENTPROC)((char *)mod + Common->offPfn); + } + } + + Proc(Common->hook, + Common->event, + Common->hwnd, + Common->idObject, + Common->idChild, + Common->dwEventThread, + Common->dwmsEventTime); + + if (Loaded) FreeLibrary(mod); return ZwCallbackReturn(NULL, 0, STATUS_SUCCESS); }