Как Windows (в частности, Vista) определяет, зависло ли мое приложение? - PullRequest
9 голосов
/ 09 мая 2009

У меня проблема, очень похожая на описанную здесь: 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 заключается в том, что когда она объявляет приложение не отвечающим, оно заменяет свое окно на призрачное окно - см. описание PeekMessage () :

Если окно верхнего уровня перестает отвечать на сообщения более чем на несколько секунд, система считает, что окно не отвечает, и заменяет его окном-призраком, имеющим тот же z-порядок, местоположение, размер и визуальные атрибуты , Это позволяет пользователю перемещать его, изменять его размер или даже закрывать приложение. Однако это единственные доступные действия, потому что приложение на самом деле не отвечает. Когда приложение отлаживается, система не создает окно-призрак.

Это призрачное окно не позволяет мышке проходить к нашему окну, потому что окно больше не отображается на экране! Поэтому моя цель - не допустить появления этого призрачного окна ...

ПОСЛЕ НЕКОТОРЫХ ИССЛЕДОВАНИЙ:

После того, как я добавил код Майкл предложил в своем ответе на этот вопрос

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 ]

4 голосов
/ 09 мая 2009

TaskManager, вероятно, использует IsHungAppWindow , чтобы определить, зависло ли приложение. Согласно MSDN, приложение считается зависшим, если оно не ожидает ввода, не обрабатывается при запуске или не обработало сообщения в течение 5 секунд. Так что WM_NULL не требуется.

Вам не нужно потреблять какие-либо конкретные сообщения - просто регулярно отправляйте сообщения и перемещайте длинные задачи из потока пользовательского интерфейса. Если вы можете заставить PeekMessage вызываться каждые 0,5 секунды, замените его на что-то вроде:

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

Что полностью истощит вашу очередь сообщений и сделает вас более отзывчивым к пользователю. Не фильтруйте отдельные сообщения, такие как сообщения мыши. Это следует делать чаще, чем каждые 0,5 секунды, если это возможно, и на более длительный срок пытайтесь отодвинуть длительную работу от потока пользовательского интерфейса.

0 голосов
/ 12 сентября 2009

Решение - один дополнительный звонок после отправки ваших сообщений.


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

...