【问题标题】:.NET code execution at normal process exit?.NET 代码在正常进程退出时执行?
【发布时间】:2013-05-21 15:06:16
【问题描述】:

C 中有atexit 函数,它

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

Python 也有类似的能力。

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

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

【问题讨论】:

标签: .net equivalent atexit


【解决方案1】:

据我所知,没有直截了当的答案。

如果你想写一个健壮的 DLL,你应该准备几个场景:

  1. 您的代码托管在默认 AppDomain 中的 .NET 应用程序中。 (琐碎的场景)
  2. 您的代码托管在 .NET 应用程序中,位于由宿主代码创建的 AppDomain 中。
  3. 您的代码托管在非托管应用程序(托管 CLR)中。

第 3 种情况最难处理,因为 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 方法来更改此执行时间。

上面的代码仍然无人看管第 3 个场景。 我知道有两种方法可以处理这种情况(以及前两种)

首先可以使用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 准则。

【讨论】:

  • 我认为要么使用CriticalFinalizerObject,要么使用Critical/SafeHandle。实际上,我今天只是偶然发现了这一点,但还没有时间实施/测试它,但我认为它应该提供我想要的。
猜你喜欢
  • 2018-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-28
  • 1970-01-01
  • 2016-05-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多