«Завершить задачу» в диспетчере задач всегда устанавливает CloseReason.UserClosing

Я хочу регистрировать, если клиент пытается принудительно закрыть приложение. Я знаю, что у меня нет шансов поймать процесс kill. Но должно быть возможно через событие закрытия основной формы получить информацию о причине «CloseReason.TaskManagerClosing».

Но любые тесты, которые я проводил под Windows 8.1, всегда приводили причину CloseReason.UserClosing. Но в этом случае (по сравнению с обычным CloseReason.UserClosing) у меня есть около 0,2 с для запуска пользовательского кода после того, как моя программа будет убита!

Это новое поведение в Windows 8.1?


person dannyyy    schedule 07.03.2014    source источник


Ответы (2)


Да, я вижу это. И да, это изменение Windows, предыдущие версии диспетчера задач напрямую отправляли окну уведомление WM_CLOSE. Теперь я вижу, что он выдает ту же самую команду, которая выдается, когда вы закрываете окно с помощью кнопки «Закрыть» (WM_SYSCOMMAND, SC_CLOSE). Или нажмите Alt+F4 или воспользуйтесь системным меню. Таким образом, Winforms больше не может определить разницу между диспетчером задач и пользователем, закрывающим окно, и вы получаете CloseReason.UserClosing.

То, что произойдет дальше, ожидаемо, если вы не отреагируете на команду закрытия достаточно быстро, диспетчер задач без промедления убьет вашу программу с помощью TerminateProcess().

Имейте в виду, что попытка сохранить данные, когда пользователь прерывает вашу программу через диспетчер задач, является плохой практикой. Ваш пользователь обычно будет использовать это, если ваша программа работает со сбоями, вы больше не можете доверять данным и рискуете написать мусор. Теперь это усугубляется прерыванием вашего кода сохранения, высокими шансами на частично записанный файл или данными базы данных, которые больше нельзя использовать.

Для этого нет простого обходного пути, вероятность того, что Windows будет исправлена ​​​​для восстановления старого поведения, очень близка к нулю. очень важно, чтобы вы сохраняли свои данные транзакционным способом, чтобы не уничтожить ценные данные, если код сохранения будет прерван. Используйте File.Replace() для файловых данных, используйте транзакцию dbase для записи dbase.

Несовершенный способ обнаружения этого условия — использование событий Form.Deactivate и Activate. Если вы видели событие Deactivate и срабатывает событие FormClosing, то вполне вероятно, что другая программа завершает вашу работу.

Но обычный способ, которым вы справляетесь с этим, является распространенным: если пользователь завершает программу без сохранения данных, вы отображаете диалоговое окно, в котором спрашивается, сохранять ли данные. Диспетчер задач гарантирует, что дальше этого дело не пойдет.

person Hans Passant    schedule 07.03.2014
comment
Ганс, Message.LParam что-то рассказывает об этом... но не достоверно - person Sriram Sakthivel; 07.03.2014
comment
Спасибо, я не собирался сохранять данные при закрытии программы. Я искал надежный способ ведения журнала, когда мое приложение завершается ненормальным образом. Клиенты часто говорят нам, что они не убили процесс, и я почти уверен, что они это сделали... потому что в любой другой ситуации каждый шаг подробно регистрируется. - person dannyyy; 07.03.2014
comment
Тогда регистрация событий De/Activate — отличное решение. - person Hans Passant; 07.03.2014

Еще одно решение для определения того, когда диспетчер задач закрывает программу, заключается в проверке наличия фокуса на основной форме или любом из ее элементов управления. Когда вы закрываете через Диспетчер задач, приложение не находится в фокусе, тогда как если вы закрываете с помощью кнопки закрытия или Alt + F4, приложение имеет фокус. Я использовал простую проверку if:

private void MyForm_Closing(object sender, FormClosingEventArgs e)
{
    if (this.ContainsFocus)
    {
        // Put user close code here
    }
}
person knueser    schedule 25.07.2018
comment
Если пользователь сворачивает программу, а затем закрывает ее через контекстное меню мыши (щелчок правой кнопкой мыши по свернутому приложению на панели задач), ContainsFocus остается false. Так что это не совсем полезно. - person Rekshino; 09.02.2021