正常进程退出时的.NET代码执行?

7
在C语言中有atexit函数,它可以注册一个函数,在正常进程终止时被调用,无论是通过exit(3)还是从程序的main()返回。Python也有类似的功能。.NET提供一种在正常进程终止时调用代码的方法吗?我知道有一些像DomainUnload和ProcessExit这样的东西,但至少据我所知,它们是不可靠的——要求应用程序是Windows Forms(或WPF应用程序)或其他某些内容。我正在为一个.dll编写代码,因此不能依赖于诸如包装try/catch之类的主程序函数操作。我的最终目标是执行一些文件清理(即刷新缓冲区并关闭)。如果可以调用一些非托管代码,例如win32api钩子或其他东西,我完全可以接受。

你可以尝试使用SetConsoleCtrlHandler的CTRL_CLOSE_EVENT事件。http://msdn.microsoft.com/en-us/library/windows/desktop/ms686016%28v=vs.85%29.aspx - user645280
1个回答

8
我不知道有没有直接的答案。
如果你想编写一个强大的DLL,你应该为几种情况做好准备:
1. 你的代码在.NET应用程序中托管,在默认的AppDomain中。(最简单的情况)
2. 你的代码在.NET应用程序中托管,在由主机代码创建的AppDomain中。
3. 你的代码在未托管的应用程序中托管(它托管CLR)。
第三种情况是最难处理的,因为CLR可能会被其主机禁用,所以托管代码将不再执行。
System.Windows.Forms.Application.ApplicationExit并不好用,因为它只适用于WinForm应用程序。
仅使用System.AppDomain.DomainUnload也不好用,因为它永远不会为默认AppDomain引发。
仅使用AppDomain.ProcessExit也不好用:如果你的代码托管在一个单独的AppDomain中,主机可能会卸载该AppDomain,因此事件将永远不会引发。
我会尝试覆盖大多数情况,使用类似以下的内容开始:
if (AppDomain.CurrentDomain.IsDefaultAppDomain())
    AppDomain.CurrentDomain.ProcessExit += MyTerminationHandler;
else
    AppDomain.CurrentDomain.DomainUnload += MyTerminationHandler;

请注意以下备注(来自MSDN):
所有ProcessExit事件处理程序的总执行时间是有限制的,就像进程关闭时所有终结器的总执行时间一样。默认值为两秒钟。非托管宿主可以通过使用OPR_ProcessExit枚举值调用ICLRPolicyManager :: SetTimeout方法来更改此执行时间。
上面的代码仍然没有涉及第三种情况。我知道有两种方法可以处理这种情况(以及前两种方法)
首先,您可以使用System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup方法,如下所示:
{
//  this goes at your code's entry point
    RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(MyExecutionCode, MyCleanupCode, null);
}
static void MyExecutionCode(object data) { /* your execution code here */}
static void MyCleanupCode(object data, bool exceptionThrown) { /* your cleanup code here */ }

其次,您可以利用 System.Runtime.ConstrainedExecution.CriticalFinalizerObject 类(在此处查看MSDN)通过继承它并将清理代码放在 finalizer 中来进行清理。这要求您的清理代码遵循 约束执行区域 指南。

我认为我要么选择CriticalFinalizerObject,要么使用Critical/SafeHandle。今天我刚刚偶然发现了这个,但是还没有时间实现/测试它,但我认为它应该提供我想要的功能。 - Wayne Werner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接