.NET code execution at normal process exit?

后端 未结 1 435
深忆病人
深忆病人 2021-01-05 16:02

In C there is the atexit function, which

The atexit() function registers the given function to be called at normal process termination, e

相关标签:
1条回答
  • 2021-01-05 16:45

    There is no straight-forward answer that I know of.

    If you want to write a robust DLL, you should prepare for several scenarios:

    1. Your code is hosted in a .NET application, in the default AppDomain. (the trivial scenario)
    2. Your code is hosted in a .NET application, in an AppDomain created by the host's code.
    3. Your code is hosted in an unmanaged application (which hosts the CLR).

    The 3rd scenario is the hardest to deal with, since the CLR can be disabled by its host, so managed code won't execute anymore.

    System.Windows.Forms.Application.ApplicationExit is no good since it only applies to WinForm applications.

    System.AppDomain.DomainUnload by itself is no good since it is never raised for the default AppDomain.

    AppDomain.ProcessExit by itself is no good: if your code is hosted in a separate AppDomain, the host might unload that AppDomain, so the event will never raise.

    I'd start by trying to cover most cases, using something like:

    if (AppDomain.CurrentDomain.IsDefaultAppDomain())
        AppDomain.CurrentDomain.ProcessExit += MyTerminationHandler;
    else
        AppDomain.CurrentDomain.DomainUnload += MyTerminationHandler;
    

    But do notice the following remark (from MSDN):

    The total execution time of all ProcessExit event handlers is limited, just as the total execution time of all finalizers is limited at process shutdown. The default is two seconds. An unmanaged host can change this execution time by calling the ICLRPolicyManager::SetTimeout method with the OPR_ProcessExit enumeration value.

    The above code still leaves the 3rd scenario unattended. There are two methods I know of for dealing with that scenario (along with the first two)

    First, you can use the System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup method, as follows:

    {
    //  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 */ }
    

    Second, you can utilize the System.Runtime.ConstrainedExecution.CriticalFinalizerObject class (see MSDN here) by inheriting it and putting your cleanup code in the finalizer. This requires your cleanup code to adhere to the Constrained Execution Region guidelines.

    0 讨论(0)
提交回复
热议问题