views:

786

answers:

2

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

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.

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!

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

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

MORE DETAILS :

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() :

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...

AFTER SOME MORE INVESTIGATIONS :

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

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!!

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.

+4  A: 

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.

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

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.

Michael
As I mentioned, my application calls PeekMessage() every 0.5 seconds, so IsHungAppWindow() should not report it as hung...
shturm
Do you specify PM_REMOVE, or do you give it a filter that is specific WM_NULL?I believe MSDN is misleading here, you need to actually fetch input messages off of the queue.
Michael
Yes, I specify PM_REMOVE, and also provide filter - both mix and max are WM_NULL.
shturm
That's most likely it, you are not actually processing any user input and are are therefore "hung" from the user and task managers perspective.
Michael
Nope, the calls to TranslateMessage() and DispatchMessage() don't help - the application is still declared "Not Responsive" by Windows...There is more to the story - I'm going to update the main post now with the details.
shturm
OK, there is definitely something more going on here since pumping messages should be enough to make the app responsive. You are doing this in a loop as long as there are messages in the queueu correct? Does your appear <appear> responsive to you, or does it appear hung - you can't move it, doesn't paint, etc.?
Michael
I've attached Spy++ and it shows no messages whatsoever (even WM_NULL) being sent to the window (or other windows from the same process/thread). The last message I see is WM_PAINT, when (while application crunches numbers) no new messages appear, and finally when the window is replaced with ghost window, some more messages appear.Which brings me back to my original question: if not by sending WM_NULL, how else Windows determines that my application is hung?
shturm
I added more details of my investigations to the post - please see there.
shturm
A: