Win32无窗口应用程序 - 等待程序退出

时间:2010-12-20 05:08:09

标签: c++ winapi windowless

我有一个无窗口应用程序,其唯一目的是安装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);
}

4 个答案:

答案 0 :(得分:4)

您有两个不同的问题:

  1. 如果C#程序退出(例如崩溃),如何使无窗口C ++程序自动退出。

    在C ++程序中,打开C#程序的句柄。由于C#程序运行C ++程序,让C#程序将自己的PID作为参数传递;然后,C ++程序可以使用OpenProcess打开该进程的句柄。

    然后在消息循环中使用MsgWaitForMultipleObjects。如果C#程序退出你需要的手柄,它将发出信号,你就会醒来。 (您也可以使用WaitForSingleObject(hProcess,0)==WAIT_OBJECT_0检查进程是否已发出信号,例如验证您被唤醒的原因,尽管MsgWaitForMultipleObjects结果也会告诉您。)

    您应该在退出时关闭进程句柄(虽然操作系统会在您退出时为您执行此操作,但如果您在不同的上下文中重复使用此代码,则这是一种很好的做法)。请注意,句柄超出了它所代表的流程,这就是您可以等待它的原因。

  2. 如何让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。例如,您可以创建一个隐藏窗口。