Windows(特别是Vista)如何确定我的应用程序是否挂起?

我有一个问题非常类似于这里描述的一个: http : //www.eggheadcafe.com/software/aspnet/30579866/prevent-vista-from-markin.aspx

该线程build议任务pipe理器将WM_NULL发送到进程,并期望进程在超时限制(5秒?)内使用此消息。 当我谷歌“WM_NULL挂”有很多引用相同的技术。

但是,我的应用程序的队列中没有看到任何WM_NULL消息,而它在一个漫长的操作上工作 – 我有一个辅助线程,每0.5秒切换到主线程,并调用PeekMessage()寻找WM_NULL,find任何!

那么,Windows(Vista)用来确定应用程序是否挂起的方法是什么?

我的应用程序应该使用哪些消息,以便Windows认为应用程序是响应式的?

更多细节 :

随着寻找WM_NULL的PeekMessage(),我们还调用PeekMessage()作为鼠标事件,因为我们也想知道用户是否select了窗口的某个区域,在那里绘制一个停止符号。 如果select区域,我们设置一个标志,主线程中的冗长操作定期检查,如果停止标志被选中,将停止。 Vista的问题在于,当它将应用程序声明为无响应时,它将用一个幻影窗口replace它的窗口 – 参见PeekMessage()的描述 :

如果顶层窗口停止对消息的响应时间超过几秒钟,系统会认为该窗口没有响应,并将其replace为具有相同z顺序,位置,大小和可视属性的幻影窗口。 这允许用户移动它,调整它的大小,甚至closures应用程序。 但是,这些是唯一可用的操作,因为应用程序实际上没有响应。 当一个应用程序被debugging时,系统不会产生一个幻影窗口。

这个鬼窗口不允许鼠标select通过我们的窗口,因为窗口不在屏幕上了! 所以我的目标是防止这个鬼窗口出现在第一个地方…

在一些更多的调查之后:

在我添加了迈克尔在回答这个问题时所build议的代码之后

while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } 

该应用程序不被视为Windows挂起了; 但是我不能使用这个解决scheme,因为应用程序开始反应select各种button等(这不应该发生)。 所以我试图看看哪些消息进来。我用Spy ++和debugging打印,都只显示两种消息:WM_TIMER和0x0118(WM_SYSTIMER)。 所以我修改了这样的代码

  while (PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE) || PeekMessage(&msg, NULL, 0x0118, 0x0118, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } 

令人惊讶的是,应用程序再次挂起!

现在我真的被卡住了。 如果我拦截进入的唯一消息,并让应用程序处理它们,那么Windows如何仍认为应用程序不处理事件?

任何有意义的build议将非常感激。

TaskManager可能使用IsHungAppWindow来确定应用程序是否挂起。 根据MSDN,如果应用程序不等待输入,不在启动处理中,或者在5秒内没有处理消息,则认为应用程序处于挂起状态。 所以没有必要的WM_NULL。

您不需要使用任何特定的消息 – 只需定期抽取消息并将长期任务移出UI线程。 如果你可以每0.5秒调用一次PeekMessage,就用下面的代码替换它:

 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } 

这将完全消耗你的消息队列,让你看起来更能响应用户。 不要过滤单个消息,例如鼠标消息。如果可能的话,应该每隔0.5秒执行一次,而长期试图将长时间的工作从UI线程中移除。

在发送消息之后,解决方案是一个额外的调用。

 // check for my messages while (PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE) || PeekMessage(&msg, NULL, 0x0118, 0x0118, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } // only to prevent ghost-window on vista! // we dont use the result and let the message in the queue (PM_NOREMOVE) PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);