我有一个无窗口的应用程序,其唯一目的是安装一个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);
}
由于某些原因,Sleep会导致问题。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);
}