我们终于找到了更多关于此的信息(但到那时我的机器已经重建并且在我未注册的个人资料中丢失了 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
事件是可能的,这取决于它是进程的默认(顶级)域还是被创建为子域(例如,在 Web 服务器上)。如果一个应用程序不知道它可能是哪个(如我们的例子),它需要订阅这两者,如果它想为自己捕获实际的卸载。此外,似乎UnhandledException
(从 .NET2.0 开始总是致命的)可能会阻止其他两个事件,因此这可能是第三种需要处理的情况。这三个事件应该适用于任何 .NET 应用程序。
需要注意的是,执行时间ProcessExit
是有限的(大约 4 秒?),因此可能无法在该事件处理程序中进行广泛的“最终”工作。它需要是可以快速完成的事情。
这些Application
事件仅适用于 WinForms 应用程序(但我们怀疑它们可能不适用于纯 WPF 应用程序)。命名可能会产生误导,因为它们是根据具有某些假设的最基本的正常用法来命名的。 ThreadExit
与 UI 线程的实际消息循环无关,System.Threading.Thread
而是与消息循环 ( Application.Run()
)) 相关,并且ApplicationExit
类似地与一个或多个 UI 线程上的应用程序表单的集合有关。通常,一旦调用Application.Run()
返回,从线程的入口方法调用,入口方法很快结束,然后线程本身结束。一旦所有 UI 线程都退出,WinForms 应用程序通常会全部完成并退出。
另一个值得注意的事件是System.Windows.Forms.Application.ThreadException
事件。可以将 Windows 消息循环配置为捕获处理消息时发生的异常并发送此事件,而不是让它们成为未捕获(因此是致命的)异常。捕获这些异常允许消息循环(以及该 UI 线程)继续运行(在中止当前消息处理程序之后)。对于给定的线程,在任何时候都只能有一个订阅者(订阅会覆盖任何以前的订阅者),并且必须在创建和订阅任何表单之前配置它,然后再进入消息循环。System.Windows.Forms.Applicaton.SetUnhandledExceptionMode()
有关此事件和更多信息,请参阅 MSDN 帮助。