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

在正常进程退出时执行.NET代码?,.net,equivalent,atexit,.net,Equivalent,Atexit,在C中有一个函数 函数通过退出(3)或从程序的main()返回,注册在正常进程终止时调用的给定函数 Python也有类似的功能 NET是否提供了在正常进程终止时调用代码的方法?我知道有些东西像DomainUnload和ProcessExit,但至少就我所知,它们是不可靠的-要么要求应用程序是Windows窗体(或WPF应用程序),要么是其他东西。我正在为一个.dll编写代码,所以我不能依赖于像破坏主程序函数这样的东西——用try/catch包装它 我的最终目标是执行一些文件清理(即刷新缓冲区并关

C
中有一个函数

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

Python也有类似的功能

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


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

据我所知,没有直接的答案

如果要编写健壮的DLL,应为以下几种情况做好准备:

  • 您的代码托管在默认AppDomain中的.NET应用程序中。(琐碎的场景)
  • 您的代码托管在.NET应用程序中,位于由主机代码创建的AppDomain中
  • 您的代码托管在非托管应用程序(托管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;
    
    但请注意以下注释():

    所有ProcessExit事件处理程序的总执行时间是有限的,就像所有终结器的总执行时间在进程关闭时是有限的一样。默认值为2秒。非托管主机可以通过使用OPR_ProcessExit枚举值调用ICLRPolicyManager::SetTimeout方法来更改此执行时间

    上面的代码仍然让第三个场景无人值守。 我知道有两种方法可以处理这种情况(包括前两种)

    首先,您可以使用
    System.Runtime.CompilerServices.RuntimeHelpers.executecodewithguarantedcleanup
    方法,如下所示:

    {
    //  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
    类()。这要求您的清理代码遵守指导原则。

    您可以尝试使用SetConsoleCtrlHandler的CTRL\u CLOSE\u事件。我想要么使用
    CriticalFinalizerObject
    ,要么使用
    Critical/SafeHandle
    。事实上,我今天偶然发现了这一点,但还没有时间实现/测试它,但我认为它应该提供我想要的。