2010-12-20 80 views
4

我有一个无窗口应用程序,其唯一目的是安装一个32位钩子DLL文件并等待父程序(一个64位程序)退出。 64位程序是用C#编写的,而无窗口应用程序是用C++编写的。我本来有这个的GetMessage循环持有本程序打开:Win32无窗口应用程序 - 等待程序退出

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,虽然比狮子座稍微不同的方式试图建议。这是我使用的循环:

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

GetMessage永不返回是因为您没有创建窗口!

要使用消息队列,你必须有一些GUI。你可以创建一个隐藏的窗口。

+0

我有点怀疑这个。常规无窗应用程序如何保持开放状态? – Telanor 2010-12-20 20:55:45

+0

我决定这么做,因为GetMessage似乎是唯一一个没有破坏所有东西的等待函数。 – Telanor 2010-12-22 06:15:49

+1

-1:GetMessage可以在没有窗口的情况下使用。这不是答案,国际海事组织。如果MsgWaitForMultipleObject正确使用,它将不会返回(除非有线程唤醒的原因)。 PostThreadMessage上的MSDN显式地提到没有窗口的GetMessage:“发布消息的线程通过调用GetMessage或PeekMessage函数来检索消息,返回的MSG结构的hwnd成员为NULL。 – 2010-12-22 07:45:01

0

你应该通过发布WM_QUIT消息并正确处理它退出的过程中,由Raymond Chen在this article (Modality)中指定。不要在没有处理消息的情况下睡在循环内 - 这是错误的。您的应用程序应该处理消息或等待新消息。

+0

问题是GetMessage函数永远不会返回。一旦我打电话给它,它就坐在那里等待着永远。我无法让C#应用程序成功发送WM_QUIT消息,但即使我在C#应用程序从不发送WM_QUIT(如果崩溃)的情况下,C++应用程序也会一直等待 – Telanor 2010-12-20 05:21:04

1

您可以创建一个命名的事件,并使用:

MsgWaitForMultipleObjects

在你的消息循环。

C#应用程序只需打开并引发此事件以告诉您的应用程序退出。

这是一种最小的进程间通信。

+0

如果C#应用程序崩溃或终止该事件将永远不会被设置。最好等待进程句柄本身(请参阅我的答案)。 – 2010-12-20 08:24:28

+0

@Leo是的,你是对的。而且,如果C#应用程序需要在不退出的情况下关闭C++应用程序,那么它们都可能是有用的。 – patriiice 2010-12-20 08:39:19

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)。

+0

我试过类似的使用MsgWaitForMultipleObjects并遇到同样的问题。看看我的第二个编辑。 – Telanor 2010-12-20 21:11:14

+0

@Telanor,尝试使用QS_ALLEVENTS而不是QS_ALLPOSTMESSAGE – 2010-12-20 21:19:25

+0

我给了一个尝试,发生了同样的事 – Telanor 2010-12-20 21:27:05

相关问题