我有一个无窗口应用程序,其唯一目的是安装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 ++应用程序时按下某个键,键就会被吃掉。删除睡眠使其工作正常,但正如预期的那样,它使用100%CPU,这是我不想要的。我试图完全删除消息循环,而是使用WaitForSingleObject,在线程上有无限超时,当isMainProgramRunning返回false时结束。这基本上锁定了整台计算机。
我真的不明白为什么GetMessage,就我所见,从未返回,但是无限期地暂停了主线程,没有引起这些问题,而WaitForSingleObject导致每个应用程序在我点击它时冻结。在C#应用程序关闭之前,如何让C ++应用程序保持打开状态?
编辑:
因为我已经向我指出睡在消息泵中是坏的,让我问一下:有没有办法在消息等待时指定超时,所以程序没有无限期地等待消息,但是相反,将等待大约250毫秒,超时,让我运行isMainProgramRunning方法,然后再等一下?
EDIT2:
我尝试使用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 ++应用程序休眠或被暂停时,钩子中的所有处理似乎也暂停?
EDIT3:
这是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);
}
答案 0 :(得分:4)
您有两个不同的问题:
如果C#程序退出(例如崩溃),如何使无窗口C ++程序自动退出。
在C ++程序中,打开C#程序的句柄。由于C#程序运行C ++程序,让C#程序将自己的PID作为参数传递;然后,C ++程序可以使用OpenProcess打开该进程的句柄。
然后在消息循环中使用MsgWaitForMultipleObjects。如果C#程序退出你需要的手柄,它将发出信号,你就会醒来。 (您也可以使用WaitForSingleObject(hProcess,0)==WAIT_OBJECT_0
检查进程是否已发出信号,例如验证您被唤醒的原因,尽管MsgWaitForMultipleObjects结果也会告诉您。)
您应该在退出时关闭进程句柄(虽然操作系统会在您退出时为您执行此操作,但如果您在不同的上下文中重复使用此代码,则这是一种很好的做法)。请注意,句柄超出了它所代表的流程,这就是您可以等待它的原因。
如何让C#程序指示C ++程序退出。
如果你让#1工作,你可能不需要这个,但你可以让C#程序在你想要的时候向C ++发布一条消息。
不要使用PostQuitMessage,也不要跨线程或进程发布或发送WM_QUIT。
相反,请使用PostThreadMessage发布两个应用同意的其他消息(例如WM_APP + 1)。
答案 1 :(得分:1)
您可以创建命名事件并使用:
消息循环中的MsgWaitForMultipleObjects
。
C#应用程序只需打开并引发此事件即可告诉您的应用程序退出。
这是一种最小的进程间通信。
答案 2 :(得分:0)
您应该通过向其发布WM_QUIT消息并正确处理它来退出流程,如this article (Modality)中由Raymond Chen所指定的那样。不处理消息就不要在循环内睡觉 - 这是错误的。您的应用应该处理消息或等待新消息。
答案 3 :(得分:0)
GetMessage永远不会返回是因为您没有创建窗口!
要使用消息队列,您必须拥有一些GUI。例如,您可以创建一个隐藏窗口。