我正在用CreateProcess打开一个窗口,我在理解SetWinEventHook方面遇到了很多麻烦。
在调用函数中,我有:
HWINEVENTHOOK hook = SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_CREATE, NULL, WinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT );
BOOL result = CreateProcess(0, arguments,
NULL, NULL, FALSE, 0, NULL,
NULL, &StartupInfo, &ProcessInfo)
if (hook) {
UnhookWinEvent(hook);
}
创建进程顺利进行,但未调用链接到SetWinEventHook的WinEventProc函数。为了让WinEventProc被调用,我尝试过这样的事情:
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0);
在createProcess调用之后,但我不知道如何结束while循环,所以它会持续进行。
我已经做了很多阅读,但我不明白如何使用SetWinEventHook来捕获由CreateProcess启动的进程。任何帮助表示赞赏!
答案 0 :(得分:4)
您可能需要完整且有效的事件循环 - 尝试:
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
如果您的应用程序不是GUI应用程序 - 或者更具体地说,如果您不需要事件循环而不是钩子 - 您可以添加另一个线程并使用上面的事件循环(以及所有挂钩和取消挂钩)我想),或者将PeekMessage
与GetMessage
结合使用来创建非阻塞事件循环并定期调用它。
其次,在调用CreateProcess
后,您不应该直接删除挂钩。通常在程序完全加载和初始化之后创建窗口,并且此过程可能需要一段时间。 CreateProcess
异步工作,这意味着它不会在退出之前等待所有这一切。
第三,为了能够接收任何类型的挂钩消息,您的消息循环需要在SetWinEventHook
和UnhookWinEvent
之间执行 - 在任何其他情况下,您将无法获得任何内容。
最后,为了避免来自其他进程的消息传递给您的进程,您应该使用CREATE_SUSPENDED
标志启动应用程序,使用适当的进程ID启动挂钩,然后使用{{1}继续执行进程主要线程句柄从ResumeThread
获得。
CreateProcess
如果您的应用程序不是事件驱动的 - 只是常规顺序应用程序,那么您应该定期调用上面的事件循环,直到您的BOOL result = CreateProcess(0, arguments,
NULL, NULL, FALSE, CREATE_SUSPENDED, NULL,
NULL, &StartupInfo, &ProcessInfo);
HWINEVENTHOOK hook = SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_CREATE, NULL, WinEventProc, ProcessInfo.dwProcessId, 0, WINEVENT_OUTOFCONTEXT );
ResumeThread(ProcessInfo.hThread);
// If you don't have an event loop function in your application already, then you could insert a temporary one here.
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
执行 - 您可能应该添加一些安全保护变量以查看它是否已经执行。另一个好主意可能是包括一些超时(2-3分钟?),以防没有发布任何事件(应用程序崩溃,app由于某种原因没有创建任何对象)。为简单起见,我也跳过了任何错误检查。
你的钩子程序应该做那样的事情:
WinEventProc
修改强>
至于跳过消息循环 - 是的,这就是这个消息循环应该做的事情。
哪个消息循环最适合你取决于你的程序构造 - 如果你已经运行了一个偶数循环(像Qt这样的GUI框架,MFC ......通常已经为你实现了),那么你不需要无论如何添加任何。如果您希望您的应用程序等到WinEvent交付,那么您应该执行类似的操作:
void CALLBACK WinEventProc(
HWINEVENTHOOK hWinEventHook,
DWORD event,
HWND hwnd,
LONG idObject,
LONG idChild,
DWORD dwEventThread,
DWORD dwmsEventTime)
{
// This will handle the re-entrance problem nicely.
UnhookWinEvent(hWinEventHook);
// Do wathever you need to do with a window here.
[...]
}
挂钩功能应该:
//Global variable for stop-condition:
bool docontinue = false;
void CALLBACK WinEventProc(
HWINEVENTHOOK hWinEventHook,
DWORD event,
HWND hwnd,
LONG idObject,
LONG idChild,
DWORD dwEventThread,
DWORD dwmsEventTime)
{
// This will handle the re-entrance problem nicely.
UnhookWinEvent(hWinEventHook);
// Do wathever you need to do with a window here.
[...]
docontinue = false;
}
这是最天真的方法,它有几个缺点,但如果你只需要做一个简单的操作,那么它可能就足够了。