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

时间:2009-05-08 22:54:24

标签: windows windows-vista windows-xp

我遇到的问题与此处描述的问题非常类似: http://www.eggheadcafe.com/software/aspnet/30579866/prevent-vista-from-markin.aspx

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

但是我在应用程序的队列中看不到任何WM_NULL消息,而它在一个冗长的操作上工作 - 我有一个辅助线程,每隔0.5秒切换到主线程并调用PeekMessage()查找WM_NULL,并且它找不到任何东西!

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

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

更多细节:

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

  

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

这个鬼窗口不允许鼠标选择进入我们的窗口,因为窗口不在屏幕上了! 所以我的目标是防止这个鬼窗出现在第一位......

经过一些调查:

我添加了对此问题的回复中建议的代码Michael

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

该应用程序不再被Windows视为挂起;但是我不能使用这个解决方案,因为应用程序开始对选择各种按钮等做出反应(这不应该发生)。 所以我试着看看哪些消息正在进入。我使用Spy ++并调试打印,两者都只显示两种消息: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仍然认为应用程序不处理事件?

任何有意义的建议都会非常感激。

2 个答案:

答案 0 :(得分:4)

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线程。

答案 1 :(得分:0)

解决方案是在发送邮件后再拨打一个电话。


// 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);