我有一个无窗口应用程序,其唯一目的是安装 32 位挂钩 DLL 文件并等待父程序(64 位程序)退出。64 位程序是用 C# 编写的,无窗口应用程序是用 C++ 编写的。我最初有一个保持程序打开的 GetMessage 循环:
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
我正在使用 C# 中的 Process.Kill 方法关闭 C++ 应用程序,但我发现这不允许 C++ 应用程序干净地关闭。此外,如果 C# 应用程序崩溃,C++ 应用程序将永远保持打开状态。我让 C++ 应用程序检查 C# 应用程序是否仍在运行,使用以下循环:
while(true)
{
if(PeekMessage(&msg, NULL, 0, 0, true))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if(!isMainProgramRunning())
break;
Sleep(1000);
}
由于某种原因,睡眠会导致问题。DLL文件安装的钩子是WH_CBT和WH_KEYBOARD。每当我在 C++ 应用程序使用此循环运行时按下一个键,这些键就会被吃掉。删除 Sleep 使其工作正常,但正如预期的那样,它使用 100% CPU,这是我不想要的。我尝试完全删除消息循环,而是在线程上使用具有无限超时的 WaitForSingleObject,该线程将在 isMainProgramRunning 返回 false 时结束。这基本上锁定了整个计算机。
我真的不明白为什么 GetMessage,据我所见,从未返回,而是无限期地暂停主线程,但没有导致这些问题,但 WaitForSingleObject 会导致每个应用程序在我单击它时冻结。如何让 C++ 应用程序保持打开状态,直到 C# 应用程序关闭?
编辑:
既然有人向我指出在消息泵中休眠是不好的,让我问一下:有没有办法指定消息等待的超时时间,所以程序不会无限期地等待消息,而是会等待大约 250 毫秒,超时,让我运行 isMainProgramRunning 方法,然后再等一下?
编辑2:
我尝试使用 MsgWaitForMultipleObjects,尽管与 Leo 建议的方式有些不同。这是我使用的循环:
while(MsgWaitForMultipleObjects (0, NULL, true, 250, QS_ALLPOSTMESSAGE) != WAIT_FAILED)
{
if(PeekMessage(&msg, NULL, 0, 0, true))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if(!isMainProgramRunning())
break;
}
我再次遇到了与睡眠相同的问题。我还尝试暂停主线程并让另一个线程恢复它。同样的问题。GetMessage 是做什么的,它允许它等待而不会导致这些问题?也许这应该是另一篇文章的主题,但为什么当安装钩子的 C++ 应用程序休眠或挂起时,钩子中的所有处理似乎也挂起?
编辑3:
这是 C++ 应用程序调用以安装挂钩的 DLL 方法:
extern "C" __declspec(dllexport) void install()
{
cbtHook = SetWindowsHookEx(WH_CBT, hookWindowEvents, hinst, NULL);
if(cbtHook == NULL)
MessageBox(NULL, "Unable to install CBT hook", "Error!", MB_OK);
keyHook = SetWindowsHookEx(WH_KEYBOARD, LowLevelKeyboardProc, hinst, NULL);
if(keyHook == NULL)
MessageBox(NULL, "Unable to install key hook", "Error!", MB_OK);
}