Windows(特别是 Vista)如何确定我的应用程序是否挂起? [英] How does Windows (specifically, Vista) determine if my application is hung?

查看:29
本文介绍了Windows(特别是 Vista)如何确定我的应用程序是否挂起?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a problem very similar to the one described here: http://www.eggheadcafe.com/software/aspnet/30579866/prevent-vista-from-markin.aspx

该线程建议任务管理器向进程发送 WM_NULL 并期望进程在超时限制(5 秒?)内使用此消息.当我在 google 上搜索WM_NULL 挂起"时,有很多对相同技术的引用.

That thread suggests that Task Manager sends WM_NULL to the process and expects the process to consume this message within timeout limit (5 seconds?). When I google for "WM_NULL hung" there are many references to the same technique.

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

However I don't see any WM_NULL messages in the queue of my application while it works on a lengthy operation - I have a secondary thread that switches to the main thread every 0.5 sec and calls PeekMessage() looking for WM_NULL, and it doesn't find any!

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

So, what's the method that Windows (Vista) uses to determine if an application is hung?

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

Which messages should my application consume so that Windows thinks that the application is responsive?

更多细节:

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

Along with PeekMessage() looking for WM_NULL, we also call PeekMessage() for mouse events, since we also want to understand if the user picked certain area of the window, where a stop sign is drawn. If the area is picked, we set a flag that the lengthy operation in the main thread periodically checks, and will stop if the stop sign is picked. The problem with Vista is that when it declares application as unresponsive, it replaces its window with a ghost window - see description of PeekMessage() :

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

If a top-level window stops responding to messages for more than several seconds, the system considers the window to be not responding and replaces it with a ghost window that has the same z-order, location, size, and visual attributes. This allows the user to move it, resize it, or even close the application. However, these are the only actions available because the application is actually not responding. When an application is being debugged, the system does not generate a ghost window.

这个幽灵窗口不允许鼠标选择穿过我们的窗口,因为窗口不再出现在屏幕上!所以我的目标是首先防止这个鬼窗出现...

This ghost window doesn't allow mouse picks to go through to our window, because the window is not on screen anymore! So my goal is to prevent this ghost window from appearing in the first place...

经过更多调查:

在我添加了 Michael 在他对这个问题的回复中建议的代码之后

After I added the code Michael suggested in his reply to this question

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

该应用程序不再被视作被 Windows 挂起;但是我不能使用这个解决方案,因为应用程序开始对各种按钮等的选择做出反应(这不应该发生).所以我试图查看传入的消息.我使用了 Spy++ 和调试打印,并且都只显示了两种消息:WM_TIMER 和 0x0118 (WM_SYSTIMER).所以我修改了这样的代码

the application is not considered hung by Windows anymore; however I cannot use this solution because application starts reacting to picks to various buttons, etc (which should not happen). So I tried to see which messages are coming in. I used Spy++ and also debug print, and both shown only two kinds of messages: WM_TIMER and 0x0118 (WM_SYSTIMER). So I modified the code like this

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

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

Surprisingly, the application hangs again!!

现在我真的被困住了.如果我拦截进来的唯一消息,让应用程序处理它们,为什么 Windows 仍然认为应用程序不处理事件??

Now I'm really stuck. If I'm intercepting the only messages that come in, and let application process them, how come Windows still thinks that the application doesn't process events??

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

Any meaningful suggestion would be GREATLY appreciated.

推荐答案

TaskManager 可能使用 IsHungAppWindow 确定应用程序是否挂起.根据 MSDN,如果应用程序未等待输入、不在启动处理中或在 5 秒内未处理消息,则将其视为挂起.所以不需要 WM_NULL.

TaskManager probably uses IsHungAppWindow to determine if an application is hung. Per MSDN, an application is considered hung if its not waiting for input, is not in startup processing, or has not not processed messages within 5 seconds. So no WM_NULL necessary.

您不需要使用任何特定的消息 - 只需定期抽取消息并将长任务移出 UI 线程即可.如果您可以每 0.5 秒调用一次 PeekMessage,请将其替换为:

You don't need to consume any specific messages - just regularly pump messages and move long tasks off of the UI thread. If you can get PeekMessage to be called every 0.5 seconds, replace it with something like:

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

这将完全耗尽您的消息队列,并使您对用户的反应更加灵敏.不要过滤单个消息,例如鼠标消息.如果可能,您应该每 0.5 秒以上执行此操作,并且长期尝试将长时间工作从 UI 线程中移出.

Which will completely drain your message queue and make you appear more responsive to the user. Do not filter individual messages such as mouse messages.. You should do this more than every 0.5 seconds if possible, and longer term try to move the long work off of the UI thread.

这篇关于Windows(特别是 Vista)如何确定我的应用程序是否挂起?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆