Работает ли событие Application.ApplicationExit, чтобы получать уведомления о выходе в приложениях, отличных от Winforms? - PullRequest
5 голосов
/ 09 февраля 2009

Наша библиотека кода должна быть уведомлена при выходе из приложения. Итак, мы подписались на событие System.Window.Forms.Application.ApplicationExit. Это хорошо работает для приложений Winforms, но работает ли оно и для других типов приложений, таких как консольные приложения, службы и веб-приложения (такие как ASP.NET)? Пространство имен предполагает, что это не так, и, по-видимому, оно возникает при вызове Application.Exit() (явно или косвенно), что может быть неправильно для вызова этих других случаев.

Есть ли какое-нибудь другое событие, которое было бы лучше в этих других случаях или которое было бы более универсальным (замечательно, если оно также работает для Winforms)? Например, есть ли событие, когда вызывается Environment.Exit() (консольное приложение)?

Я обнаружил упоминание о событии Exited в System.Diagnostic.Process, но, похоже, оно предназначено для отслеживания выхода из другого процесса, и оно, как представляется, не получено процессом о себе (например, Process.GetCurrentProcess().Exited += Process_Exited; Process.GetCurrentProcess().EnableRaisingEvents = true;). Я думаю, что он может быть поднят только после фактического завершения процесса, так что это не сработает.

Это особенно для .NET 2.0 и C #.

1 Ответ

10 голосов
/ 20 июля 2009

Мы наконец-то узнали больше об этом (но к тому времени моя машина была восстановлена ​​и потеряла файлы cookie в моем незарегистрированном профиле здесь; надеюсь, она позволит собранию опубликовать этот ответ).

Дальнейшее расследование в конечном итоге выявило еще несколько событий, которые мы сочли полезными:

System.Windows.Forms.Application.ThreadExit - срабатывает при выходе из цикла сообщений System.Windows.Forms.Application.ApplicationExit - срабатывает, когда завершаются все циклы сообщений System.AppDomain.CurrentDomain.DomainUnload - Срабатывает, когда выходит домен, отличный от домена по умолчанию. System.AppDomain.CurrentDomain.ProcessExit - срабатывает при выходе из домена приложения по умолчанию System.AppDomain.CurrentDomain.UnhandledException - срабатывает при возникновении необработанного исключения, завершая работу приложения.

Только одно из событий DomainUnload или ProcessExit возможно для данного домена приложения, в зависимости от того, является ли он доменом по умолчанию (верхнего уровня) для процесса или был создан как поддомен (например, на веб сервер). Если приложение не знает, каким оно может быть (как в нашем случае), оно должно подписаться на оба, если оно хочет поймать фактическую выгрузку для себя. Кроме того, кажется, что UnhandledException (который по состоянию на .NET2.0 всегда является фатальным) может предотвратить два других события, так что это может быть третий случай для обработки. Эти три события должны работать для любого приложения .NET.

Существует предупреждение о том, что время выполнения для ProcessExit ограничено (около 4 секунд?), Поэтому, возможно, не удастся выполнить обширную "финальную" работу в этом обработчике событий. Это должно быть что-то, что можно сделать быстро.

События Application применяются только к приложениям WinForms (однако мы подозреваем, что они могут не применяться в приложениях с чистым WPF). Названия могут вводить в заблуждение, потому что они названы для их основного обычного использования, которое имеет определенные предположения. ThreadExit относится не к фактическому System.Threading.Thread, а скорее к циклу сообщений (Application.Run())) потока пользовательского интерфейса, а ApplicationExit аналогично относится к набору форм приложений в одном или нескольких потоках пользовательского интерфейса. Обычно, когда возвращается вызов Application.Run(), вызванный методом ввода потока, метод ввода быстро завершается, и сам поток затем заканчивается. И как только все потоки пользовательского интерфейса закрываются, приложение WinForms обычно все готово и завершает работу.

Другим заметным событием является событие System.Windows.Forms.Application.ThreadException. Цикл сообщений Windows может быть настроен на перехват исключений, возникающих при обработке сообщения, и отправку этого события, а не на то, чтобы они были неперехваченными (и, следовательно, фатальными) исключениями. Перехват этих исключений позволяет циклу сообщений (и тому потоку пользовательского интерфейса) продолжать работу (после прерывания текущего обработчика сообщений). В каждый момент времени для данного потока может быть только один подписчик на это событие (подписки перезаписывают любого предыдущего подписчика), и его необходимо настроить перед созданием любой формы и подпиской перед входом в цикл сообщений. См. Справку MSDN для этого события и System.Windows.Forms.Applicaton.SetUnhandledExceptionMode() для получения дополнительной информации.

...