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

Windows(特别是Vista)如何确定我的应用程序是否挂起?,windows,windows-vista,windows-xp,Windows,Windows Vista,Windows Xp,我有一个与这里描述的问题非常相似的问题: 该线程建议任务管理器向进程发送WM_NULL,并期望进程在超时限制(5秒?)内使用此消息。 当我在谷歌上搜索“WM_NULL hung”时,有很多地方提到了相同的技术 然而,当我的应用程序在执行一个冗长的操作时,我在队列中没有看到任何WM_NULL消息-我有一个辅助线程,它每0.5秒切换到主线程,并调用PeekMessage()查找WM_NULL,但它没有找到任何消息 那么,Windows(Vista)使用什么方法来确定应用程序是否挂起 我的应用程序应

我有一个与这里描述的问题非常相似的问题:

该线程建议任务管理器向进程发送WM_NULL,并期望进程在超时限制(5秒?)内使用此消息。 当我在谷歌上搜索“WM_NULL hung”时,有很多地方提到了相同的技术

然而,当我的应用程序在执行一个冗长的操作时,我在队列中没有看到任何WM_NULL消息-我有一个辅助线程,它每0.5秒切换到主线程,并调用PeekMessage()查找WM_NULL,但它没有找到任何消息

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

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

更多详情:

除了PeekMessage()查找WM_NULL外,我们还为鼠标事件调用PeekMessage(),因为我们还想了解用户是否选择了窗口的某个区域,在该区域绘制了停止标志。如果选择了该区域,我们将设置一个标志,主线程中的长时间操作将定期检查该标志,如果选择了停止标志,则该标志将停止。 Vista的问题在于,当它将应用程序声明为无响应时,会将其窗口替换为重影窗口-请参阅:

如果顶级窗口停止响应消息的时间超过几秒钟,系统将认为该窗口没有响应,并将其替换为具有相同z顺序、位置、大小和视觉属性的重影窗口。这允许用户移动它,调整它的大小,甚至关闭应用程序。但是,这些是唯一可用的操作,因为应用程序实际上没有响应。调试应用程序时,系统不会生成重影窗口

这个鬼窗口不允许鼠标点击进入我们的窗口,因为窗口已经不在屏幕上了! 所以我的目标是首先防止这个鬼窗口出现

经过进一步调查后:

在我添加了他在回答这个问题时建议的代码之后

while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}
应用程序不再被Windows挂起;然而,我不能使用这个解决方案,因为应用程序开始对各种按钮的选择做出反应,等等(这是不应该发生的)。 所以我试着看看有哪些信息进来。我使用了Spy++和debug print,它们都只显示了两种消息:WM_TIMER和0x0118(WM_Systemimer)。所以我像这样修改了代码

 while (PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE) ||
        PeekMessage(&msg, NULL, 0x0118, 0x0118, PM_REMOVE))
 {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
 }
令人惊讶的是,应用程序再次挂起

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

任何有意义的建议都将不胜感激。

TaskManager可能会使用它来确定应用程序是否挂起。根据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);


你在UI线程上做什么?您是否考虑过尝试将阻塞操作移动到后台线程,而不是尝试对窗口管理器进行反向工程?UI线程正在忙于计算某些内容。不幸的是,与许多大型应用程序一样,将大量旧代码多线程化并不是一项简单的任务(更新了我的答案。请确保清空所有消息,以保证您将被取消托管。我相信我现在正在清空所有消息。循环看起来与您的示例完全相同。仍然会重影我的窗口…通过过滤消息,您告诉操作系统您对输入事件不感兴趣,并且可能可以自由声明您已挂起。您知道吗uld泵送所有消息,如果您不希望输入转到窗口上的其他控件,则应禁用它们。创建模式进度UI对话框可能是最简单的方法。如我所述,我的应用程序每0.5秒调用一次PeekMessage(),因此IsHungAppWindow()不应将其报告为挂起…您是否指定PM_REMOVE,或者是否为其提供特定于WM_NULL的筛选器?我认为MSDN在这里有误导性,您需要实际从队列中获取输入消息。是的,我指定PM_REMOVE,并提供筛选器-mix和max都是WM_NULL。这很可能是因为,您实际上没有处理任何使用因此,从用户和任务管理器的角度来看,r输入和are是“挂起”的。我附加了Spy++,它没有显示任何消息(甚至WM_NULL)被发送到窗口(或来自同一进程/线程的其他窗口)。我看到的最后一条消息是WM_PAINT,when(当应用程序处理数字时)没有新的消息出现,最后当窗口被ghost窗口替换时,会出现更多的消息。这让我回到了我原来的问题:如果不是通过发送WM_NULL,Windows如何确定我的应用程序已挂起?