[Win32ss]

- Fix wine msg:test_winevents.
- Fix global hooks while sending to same process different thread. Yes, interesting.
- Fix event hooks, use posting (faster) instead of sending. This fixed a problem while sending to the same thread.

svn path=/trunk/; revision=66310
This commit is contained in:
James Tabor 2015-02-16 03:32:46 +00:00
parent 2ff860c8f1
commit 0a97b2b39d
9 changed files with 183 additions and 67 deletions

View file

@ -79,6 +79,8 @@ typedef struct _EVENTPROC_CALLBACK_ARGUMENTS
DWORD dwEventThread; DWORD dwEventThread;
DWORD dwmsEventTime; DWORD dwmsEventTime;
WINEVENTPROC Proc; WINEVENTPROC Proc;
INT Mod;
ULONG_PTR offPfn;
} EVENTPROC_CALLBACK_ARGUMENTS, *PEVENTPROC_CALLBACK_ARGUMENTS; } EVENTPROC_CALLBACK_ARGUMENTS, *PEVENTPROC_CALLBACK_ARGUMENTS;
typedef struct _LOADMENU_CALLBACK_ARGUMENTS typedef struct _LOADMENU_CALLBACK_ARGUMENTS

View file

@ -805,7 +805,9 @@ co_IntCallEventProc(HWINEVENTHOOK hook,
LONG idChild, LONG idChild,
DWORD dwEventThread, DWORD dwEventThread,
DWORD dwmsEventTime, DWORD dwmsEventTime,
WINEVENTPROC Proc) WINEVENTPROC Proc,
INT Mod,
ULONG_PTR offPfn)
{ {
LRESULT Result = 0; LRESULT Result = 0;
NTSTATUS Status; NTSTATUS Status;
@ -830,6 +832,8 @@ co_IntCallEventProc(HWINEVENTHOOK hook,
Common->dwEventThread = dwEventThread; Common->dwEventThread = dwEventThread;
Common->dwmsEventTime = dwmsEventTime; Common->dwmsEventTime = dwmsEventTime;
Common->Proc = Proc; Common->Proc = Proc;
Common->Mod = Mod;
Common->offPfn = offPfn;
ResultPointer = NULL; ResultPointer = NULL;
ResultLength = sizeof(LRESULT); ResultLength = sizeof(LRESULT);

View file

@ -42,7 +42,9 @@ co_IntCallEventProc(HWINEVENTHOOK hook,
LONG idChild, LONG idChild,
DWORD dwEventThread, DWORD dwEventThread,
DWORD dwmsEventTime, DWORD dwmsEventTime,
WINEVENTPROC Proc); WINEVENTPROC Proc,
INT Mod,
ULONG_PTR offPfn);
VOID FASTCALL VOID FASTCALL
IntCleanupThreadCallbacks(PTHREADINFO W32Thread); IntCleanupThreadCallbacks(PTHREADINFO W32Thread);

View file

@ -14,6 +14,7 @@ typedef struct _EVENTPACK
PEVENTHOOK pEH; PEVENTHOOK pEH;
LONG idObject; LONG idObject;
LONG idChild; LONG idChild;
LONG idThread;
} EVENTPACK, *PEVENTPACK; } EVENTPACK, *PEVENTPACK;
static PEVENTTABLE GlobalEvents = NULL; static PEVENTTABLE GlobalEvents = NULL;
@ -98,11 +99,11 @@ IntCallLowLevelEvent( PEVENTHOOK pEH,
DWORD event, DWORD event,
HWND hwnd, HWND hwnd,
LONG idObject, LONG idObject,
LONG idChild) LONG idChild,
LONG idThread)
{ {
NTSTATUS Status;
PEVENTPACK pEP; PEVENTPACK pEP;
ULONG_PTR uResult = 0; MSG Msg;
pEP = ExAllocatePoolWithTag(NonPagedPool, sizeof(EVENTPACK), TAG_HOOK); pEP = ExAllocatePoolWithTag(NonPagedPool, sizeof(EVENTPACK), TAG_HOOK);
if (!pEP) return 0; if (!pEP) return 0;
@ -110,23 +111,16 @@ IntCallLowLevelEvent( PEVENTHOOK pEH,
pEP->pEH = pEH; pEP->pEH = pEH;
pEP->idObject = idObject; pEP->idObject = idObject;
pEP->idChild = idChild; pEP->idChild = idChild;
pEP->idThread = idThread;
/* FIXME: Should get timeout from Msg.message = event;
* HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */ Msg.hwnd = hwnd;
Status = co_MsqSendMessage( pEH->head.pti, Msg.wParam = 0;
hwnd, Msg.lParam = POSTEVENT_NWE;
event, Msg.time = 0;
0,
(LPARAM)pEP, MsqPostMessage(pEH->head.pti, &Msg, FALSE, QS_EVENT, POSTEVENT_NWE, (LONG_PTR)pEP);
300, return 0;
TRUE,
MSQ_ISEVENT,
&uResult);
if (!NT_SUCCESS(Status))
{
ExFreePoolWithTag(pEP, TAG_HOOK);
}
return NT_SUCCESS(Status) ? uResult : 0;
} }
BOOLEAN BOOLEAN
@ -155,7 +149,7 @@ IntRemoveEvent(PVOID Object)
LRESULT LRESULT
APIENTRY APIENTRY
co_EVENT_CallEvents( DWORD event, co_EVENT_CallEvents( DWORD event,
HWND hwnd, HWND hwnd,
UINT_PTR idObject, UINT_PTR idObject,
LONG_PTR idChild) LONG_PTR idChild)
{ {
@ -164,15 +158,17 @@ co_EVENT_CallEvents( DWORD event,
PEVENTPACK pEP = (PEVENTPACK)idChild; PEVENTPACK pEP = (PEVENTPACK)idChild;
pEH = pEP->pEH; pEH = pEP->pEH;
TRACE("Dispatch Event 0x%x, idObject %d hwnd %p\n", event, idObject, hwnd);
Result = co_IntCallEventProc( UserHMGetHandle(pEH), Result = co_IntCallEventProc( UserHMGetHandle(pEH),
event, event,
hwnd, hwnd,
pEP->idObject, pEP->idObject,
pEP->idChild, pEP->idChild,
PtrToUint(NtCurrentTeb()->ClientId.UniqueThread), pEP->idThread,
(DWORD)EngGetTickCount(), (DWORD)EngGetTickCount(),
pEH->Proc); pEH->Proc,
pEH->ihmod,
pEH->offPfn);
ExFreePoolWithTag(pEP, TAG_HOOK); ExFreePoolWithTag(pEP, TAG_HOOK);
return Result; return Result;
@ -211,29 +207,19 @@ IntNotifyWinEvent(
if (!pEH) break; if (!pEH) break;
UserReferenceObject(pEH); UserReferenceObject(pEH);
// Must be inside the event window. // 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 all process || all thread || other thread same process
// if ^skip own thread && ((Pid && CPid == Pid && ^skip own process) || all process) // if ^skip own thread && ((Pid && CPid == Pid && ^skip own process) || all process)
if ( (!pEH->idProcess || pEH->idProcess == PtrToUint(pti->pEThread->Cid.UniqueProcess)) && if (!( (pEH->idProcess && pEH->idProcess != PtrToUint(pti->pEThread->Cid.UniqueProcess)) ||
(!(pEH->Flags & WINEVENT_SKIPOWNPROCESS) || pEH->head.pti->ppi != pti->ppi) && (pEH->Flags & WINEVENT_SKIPOWNPROCESS && pEH->head.pti->ppi == pti->ppi) ||
(!pEH->idThread || pEH->idThread == PtrToUint(pti->pEThread->Cid.UniqueThread)) && (pEH->idThread && pEH->idThread != PtrToUint(pti->pEThread->Cid.UniqueThread)) ||
(!(pEH->Flags & WINEVENT_SKIPOWNTHREAD) || pEH->head.pti != pti) && (pEH->Flags & WINEVENT_SKIPOWNTHREAD && pEH->head.pti == pti) ||
pEH->head.pti->rpdesk == ptiCurrent->rpdesk ) // Same as hooks. pEH->head.pti->rpdesk != ptiCurrent->rpdesk ) ) // Same as hooks.
{ {
// Send message to the thread if pEH is not current. if (pEH->Flags & WINEVENT_INCONTEXT)
if (pEH->head.pti != ptiCurrent)
{ {
ERR("Global Event 0x%x, idObject %d\n", Event, idObject); TRACE("In Event 0x%x, idObject %d hwnd %p\n", Event, idObject, pWnd ? UserHMGetHandle(pWnd) : NULL);
IntCallLowLevelEvent( pEH,
Event,
pWnd ? UserHMGetHandle(pWnd) : NULL,
idObject,
idChild);
}
else
{
ERR("Local Event 0x%x, idObject %d\n", Event, idObject);
co_IntCallEventProc( UserHMGetHandle(pEH), co_IntCallEventProc( UserHMGetHandle(pEH),
Event, Event,
pWnd ? UserHMGetHandle(pWnd) : NULL, pWnd ? UserHMGetHandle(pWnd) : NULL,
@ -241,7 +227,19 @@ IntNotifyWinEvent(
idChild, idChild,
PtrToUint(NtCurrentTeb()->ClientId.UniqueThread), PtrToUint(NtCurrentTeb()->ClientId.UniqueThread),
(DWORD)EngGetTickCount(), (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; goto SetEventExit;
} }
if ((dwflags & WINEVENT_INCONTEXT) && !hmodWinEventProc) if (dwflags & WINEVENT_INCONTEXT)
{ {
EngSetLastError(ERROR_HOOK_NEEDS_HMOD); if (!hmodWinEventProc)
goto SetEventExit; {
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) if (idThread)
@ -371,14 +384,18 @@ NtUserSetWinEventHook(
If WINEVENT_OUTOFCONTEXT just use proc.. If WINEVENT_OUTOFCONTEXT just use proc..
Do this instead.... Do this instead....
*/ */
if (NULL != hmodWinEventProc) if (hmodWinEventProc != NULL)
{ {
pEH->offPfn = (ULONG_PTR)((char *)lpfnWinEventProc - (char *)hmodWinEventProc); pEH->offPfn = (ULONG_PTR)((char *)lpfnWinEventProc - (char *)hmodWinEventProc);
pEH->ihmod = (INT)hmodWinEventProc; pEH->ihmod = (INT)hmodWinEventProc;
pEH->Proc = lpfnWinEventProc; pEH->Proc = lpfnWinEventProc;
} }
else else
{
pEH->Proc = lpfnWinEventProc; pEH->Proc = lpfnWinEventProc;
pEH->offPfn = 0;
pEH->ihmod = (INT)hmodWinEventProc;
}
UserDereferenceObject(pEH); UserDereferenceObject(pEH);

View file

@ -1251,6 +1251,23 @@ co_HOOK_CallHooks( INT HookId,
TRACE("\nGlobal Hook posting to another Thread! %d\n",HookId ); TRACE("\nGlobal Hook posting to another Thread! %d\n",HookId );
Result = co_IntCallLowLevelHook(Hook, Code, wParam, lParam); 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 else
{ /* Make the direct call. */ { /* Make the direct call. */

View file

@ -652,6 +652,20 @@ static LRESULT handle_internal_message( PWND pWnd, UINT msg, WPARAM wparam, LPAR
return 0; 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 LRESULT FASTCALL
IntDispatchMessage(PMSG pMsg) IntDispatchMessage(PMSG pMsg)
{ {
@ -845,7 +859,7 @@ co_IntPeekMessage( PMSG Msg,
ExtraInfo, ExtraInfo,
Msg )) Msg ))
{ {
return TRUE; return TRUE;
} }
/* Only check for quit messages if not posted messages pending. */ /* Only check for quit messages if not posted messages pending. */
@ -880,6 +894,24 @@ co_IntPeekMessage( PMSG Msg,
return TRUE; 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. */ /* Check for sent messages again. */
while ( co_MsqDispatchOneSentMessage(pti) ) while ( co_MsqDispatchOneSentMessage(pti) )
{ {

View file

@ -800,13 +800,6 @@ co_MsqDispatchOneSentMessage(PTHREADINFO pti)
Message->Msg.wParam, Message->Msg.wParam,
Message->Msg.lParam); 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) else if(Message->HookMessage == MSQ_INJECTMODULE)
{ {
Result = IntLoadHookModule(Message->Msg.message, Result = IntLoadHookModule(Message->Msg.message,
@ -2076,6 +2069,13 @@ MsqCleanupThreadMsgs(PTHREADINFO pti)
{ {
CurrentEntry = RemoveHeadList(&pti->PostedMessagesListHead); CurrentEntry = RemoveHeadList(&pti->PostedMessagesListHead);
CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry); CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
if (CurrentMessage->dwQEvent)
{
if (CurrentMessage->dwQEvent == POSTEVENT_NWE)
{
ExFreePoolWithTag( (PVOID)CurrentMessage->ExtraInfo, TAG_HOOK);
}
}
MsqDestroyMessage(CurrentMessage); MsqDestroyMessage(CurrentMessage);
} }

View file

@ -3,8 +3,7 @@
#define MSQ_HUNG 5000 #define MSQ_HUNG 5000
#define MSQ_NORMAL 0 #define MSQ_NORMAL 0
#define MSQ_ISHOOK 1 #define MSQ_ISHOOK 1
#define MSQ_ISEVENT 2 #define MSQ_INJECTMODULE 2
#define MSQ_INJECTMODULE 3
typedef struct _USER_MESSAGE typedef struct _USER_MESSAGE
{ {
@ -116,6 +115,8 @@ enum internal_event_message
WM_ASYNC_DESTROYWINDOW WM_ASYNC_DESTROYWINDOW
}; };
#define POSTEVENT_NWE 14
BOOL FASTCALL MsqIsHung(PTHREADINFO pti); BOOL FASTCALL MsqIsHung(PTHREADINFO pti);
VOID CALLBACK HungAppSysTimerProc(HWND,UINT,UINT_PTR,DWORD); VOID CALLBACK HungAppSysTimerProc(HWND,UINT,UINT_PTR,DWORD);
NTSTATUS FASTCALL co_MsqSendMessage(PTHREADINFO ptirec, NTSTATUS FASTCALL co_MsqSendMessage(PTHREADINFO ptirec,

View file

@ -357,6 +357,9 @@ SetWinEventHook(
{ {
WCHAR ModuleName[MAX_PATH]; WCHAR ModuleName[MAX_PATH];
UNICODE_STRING USModuleName; UNICODE_STRING USModuleName;
PUNICODE_STRING pusmodName;
RtlInitUnicodeString(&USModuleName, NULL);
if ((hmodWinEventProc != NULL) && (dwFlags & WINEVENT_INCONTEXT)) if ((hmodWinEventProc != NULL) && (dwFlags & WINEVENT_INCONTEXT))
{ {
@ -365,16 +368,17 @@ SetWinEventHook(
return NULL; return NULL;
} }
RtlInitUnicodeString(&USModuleName, ModuleName); RtlInitUnicodeString(&USModuleName, ModuleName);
pusmodName = &USModuleName;
} }
else else
{ {
RtlInitUnicodeString(&USModuleName, NULL); pusmodName = NULL;
} }
return NtUserSetWinEventHook(eventMin, return NtUserSetWinEventHook(eventMin,
eventMax, eventMax,
hmodWinEventProc, hmodWinEventProc,
&USModuleName, pusmodName,
pfnWinEventProc, pfnWinEventProc,
idProcess, idProcess,
idThread, idThread,
@ -779,16 +783,53 @@ NTSTATUS WINAPI
User32CallEventProcFromKernel(PVOID Arguments, ULONG ArgumentLength) User32CallEventProcFromKernel(PVOID Arguments, ULONG ArgumentLength)
{ {
PEVENTPROC_CALLBACK_ARGUMENTS Common; PEVENTPROC_CALLBACK_ARGUMENTS Common;
WINEVENTPROC Proc;
WCHAR module[MAX_PATH];
DWORD len;
HMODULE mod = NULL;
BOOL Loaded = FALSE;
Common = (PEVENTPROC_CALLBACK_ARGUMENTS) Arguments; Common = (PEVENTPROC_CALLBACK_ARGUMENTS) Arguments;
Common->Proc(Common->hook, Proc = Common->Proc;
Common->event,
Common->hwnd, if (Common->offPfn && Common->Mod)
Common->idObject, { // Validate the module again.
Common->idChild, if (!(len = GetModuleFileNameW((HINSTANCE)Common->Mod, module, MAX_PATH)) || len >= MAX_PATH)
Common->dwEventThread, {
Common->dwmsEventTime); 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); return ZwCallbackReturn(NULL, 0, STATUS_SUCCESS);
} }