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

时间:2013-05-21 15:06:16

标签: .net equivalent atexit

C中有atexit函数,

  

atexit()函数通过exit(3)或从程序的main()返回来注册在正常进程终止时调用的给定函数。

Python具有类似的功能。

.NET是否提供了在正常进程终止时调用代码的方法?我知道有一些像DomainUnloadProcessExit这样的东西,但至少据我所知,这些都是不可靠的 - 要么应用程序是Windows窗体(或WPF应用程序),要么其他。我正在为.dll编写代码,所以我不能依赖于像主程序函数那样的东西 - 将它包装在try / catch中。

我的最终目标是执行一些文件清理(即刷新缓冲区并关闭)。如果我可以调用一些非托管代码,例如一个win32api钩子什么的,我完全没问题。

1 个答案:

答案 0 :(得分:7)

我知道没有直截了当的答案。

如果你想编写一个健壮的DLL,你应该为几种情况做好准备:

  1. 您的代码托管在.NET应用程序中的默认AppDomain中。 (琐碎的场景)
  2. 您的代码托管在.NET应用程序中,由主机代码创建的AppDomain中。
  3. 您的代码托管在非托管应用程序中(托管CLR)。
  4. 第三种情况是最难处理的,因为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;
    

    但请注意以下注释(from 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类(see MSDN here)。这需要您的清理代码遵守Constrained Execution Region指南。