[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 dwmsEventTime;
WINEVENTPROC Proc;
INT Mod;
ULONG_PTR offPfn;
} EVENTPROC_CALLBACK_ARGUMENTS, *PEVENTPROC_CALLBACK_ARGUMENTS;
typedef struct _LOADMENU_CALLBACK_ARGUMENTS

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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. */

View file

@ -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) )
{

View file

@ -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);
}

View file

@ -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,

View file

@ -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);
}