SetWinEventHook 与 CreateProcess, C++
Posted
技术标签:
【中文标题】SetWinEventHook 与 CreateProcess, C++【英文标题】:SetWinEventHook with CreateProcess, C++ 【发布时间】:2013-12-22 17:31:47 【问题描述】:我正在使用 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 启动的进程。任何帮助表示赞赏!
【问题讨论】:
【参考方案1】:您可能需要完整且有效的事件循环 - 尝试:
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
TranslateMessage(&msg);
DispatchMessage(&msg);
如果您的应用程序不是 GUI 应用程序 - 或者更具体地说,如果您不需要除挂钩以外的任何事件循环 - 您可以添加另一个线程并在那里使用上面的事件循环(以及所有挂钩和取消挂钩)我想),或者将PeekMessage
与GetMessage
结合使用来创建非阻塞事件循环并定期调用它。
其次,你不应该在调用CreateProcess
之后直接移除你的钩子。窗口的创建通常发生在程序完全加载和初始化之后,这个过程可能需要一段时间。 CreateProcess
是异步工作的,这意味着它不会等到这一切都发生后才退出。
第三,为了能够接收任何类型的钩子消息,您的消息循环需要在 SetWinEventHook
和 UnhookWinEvent
之间执行 - 在任何其他情况下,您将一无所获。
最后,为了避免来自其他进程的消息传递给您的进程,您可能应该使用 CREATE_SUSPENDED
标志启动您的应用程序,使用适当的进程 ID 启动您的钩子,然后使用 ResumeThread
和 main 恢复进程执行线程句柄从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);
如果你的应用程序不是事件驱动的——只是常规的顺序应用程序,那么你应该定期调用上面的事件循环,直到你的WinEventProc
执行——你可能应该添加一些安全变量来查看它是否已经被执行。另一个好主意可能是包括一些超时(2-3 分钟?),以防没有发布任何事件(应用程序崩溃,应用程序由于某种原因没有创建对象)。为简单起见,我也跳过了任何错误检查。
你的钩子程序应该做这样的事情:
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.
[...]
编辑:
至于跳过消息循环 - 是的,这就是这个消息循环应该做的。
哪种消息循环最适合您取决于您的程序构造 - 如果您已经运行了偶数循环(Qt、MFC 等 GUI 框架...通常已经为您实现),那么您不需要无论如何添加。如果您希望您的应用程序等到 WinEvent 交付,那么您应该这样做:
//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;
挂钩功能应该这样做:
// In hooking function use:
docontinue = true;
MSG msg;
while (GetMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0)
TranslateMessage(&msg);
DispatchMessage(&msg);
if (!docontinue)
break;
这是最幼稚的方法,它有几个缺点,但如果你只需要做一个简单的操作,那么它可能对你来说就足够了。
【讨论】:
非常感谢你写了这么多。我将开始查看 PeekMessage 函数以了解更多信息。同时,我将 CreateProcess 移到了 setWinEventHook 调用之上,添加了恢复线程和 while(peekMessage) 循环。代码只是直接跳过了 while 循环,甚至没有碰到 WinEventProc 函数。在 SetWinEventHook 中,我必须将 ProcessInfo.process 转换为类型 DWORD 才能编译,我不知道会有多大的不同。 对不起,我的错 -SetWinEventHook
需要进程 ID 而不是进程句柄 - 你应该使用 dwProcessId
字段而不是 hProcess
- 那么你不应该需要转换任何东西 ;)跨度>
而不是docontinue = false;
使用PosteQuitMessage()
@milevyo 我相信我的方法更安全。在已经有事件循环的线程中使用这样的循环是完全可能的。在这种情况下,PostaQuitMessage()
将退出线程中的所有消息队列 - 可能与预期不同。以上是关于SetWinEventHook 与 CreateProcess, C++的主要内容,如果未能解决你的问题,请参考以下文章
csharp 利用SetWinEventHook事件钩子避免SetWindowsHookEx权限问题
SetWinEventHook 事件钩子(有些windows事件并没有消息对应,譬如弹出菜单,切换窗口,获得焦点,滚动条滚动等)good
typescript 解决方案“错误:gulp-typescript:项目不能同时用于两个编译*。使用createP创建多个项目