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

2023-11-22

In Catexit函数,其中

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

Python 也有类似的功能。

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

我的最终目标是执行一些文件清理(即刷新缓冲区并关闭)。如果我可以调用一些非托管代码,例如win32api 挂钩或其他东西,我对此非常满意。


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

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

  1. 您的代码托管在默认 AppDomain 中的 .NET 应用程序中。 (琐碎的场景)
  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 class (请参阅此处的 MSDN)通过继承它并将清理代码放入终结器中。这要求您的清理代码遵守约束执行区域指导方针。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

.NET 代码在正常进程退出时执行? 的相关文章

随机推荐

  • findall/3 在其结果列表中创建新的、不相关的变量

    permutation A B C Z Z A B C Z A C B Z B A C Z B C A Z C A B Z C B A false 说得通 我可以研究以下的排列 A B C 并且该排列包含与中相同的元素 A B C 所以我对
  • 如何禁止两个相互冲突的选项

    有没有办法向 Python 的 ArgumentParser 指定两个可选标志发生冲突 arg parser add argument c clean action store true arg parser add argument d
  • CallExpression 和 MemberExpression 之间的区别

    有什么不同 我看了ECMAScript规范 但不明白 真正的代码示例会有很大帮助 如果你能解释这里的每一行那就太好了 MemberExpression PrimaryExpression FunctionExpression MemberE
  • 检测有向图中循环的最佳算法[关闭]

    Closed 这个问题是基于意见的 目前不接受答案 是否有一种有效的算法来检测有向图中的循环 我有一个有向图 表示需要执行的作业的时间表 作业是节点 依赖项是边 我需要检测该图中导致循环依赖的循环错误情况 Tarjan 的强连通分量算法 h
  • Pandas Dataframe / Numpy 数组“轴”定义中的歧义

    我对 python 轴的定义方式以及它们是否引用 DataFrame 的行或列感到非常困惑 考虑下面的代码 gt gt gt df pd DataFrame 1 1 1 1 2 2 2 2 3 3 3 3 columns col1 col2
  • JavaScript 中的 Console.log 输出

    Why do console log 00 and console log 01 在浏览器控制台中打印 0 和 1 而不是 00 和 01 console log 00 prints 0 console log 01 prints 1 co
  • Flex-box:将最后一行与网格对齐

    我有一个简单的弹性盒布局 其中包含如下容器 grid display flex flex flow row wrap justify content space between 现在我希望最后一行中的项目与另一行对齐 justify con
  • 如何将相同类型的多个参数传递给 jQuery Get

    我正在尝试使用 jQuery get 从网站获取一些数据 我需要设置2个相同类型的参数 q Some Text q Some other text jQuery 似乎用第二个实例覆盖 q 的第一个实例 并且仅发送 1 有什么办法解决这个问题
  • 适用于 iOS 的 WebDav 客户端库 [已关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 目前不接受答案 是否有适用于 iOS 的 WebDav 客户端实现 看一下WTclient
  • 当只需要一个字节时,为什么 Rust 使用两个字节来表示这个枚举?

    它似乎足够聪明 只为 A 使用一个字节 但不够聪明 为 B 使用一个字节 即使只有 8 8 64 种可能性 有什么方法可以让 Rust 解决这个问题 还是我必须手动实现更紧凑的布局 游乐场链接 allow dead code enum A
  • Python 3:gzip.open() 和模式

    https docs python org 3 library gzip html 我正在考虑使用gzip open 我有点困惑mode争论 模式参数可以是 r rb a ab w wb x 中的任何一个 或 xb 表示二进制模式 或 rt
  • 检测 32 位或 64 位 Windows

    我想检测当前的Windows操作系统是32位还是64位 如何用C 实现呢 我不需要处理器类型 我想要操作系统的位类型 这是因为您可以在 64 位处理器上安装 32 位操作系统 要调用的函数是IsWow64Process or IsWow64
  • 无会话的 Passport js 身份验证

    我是expressjs和passportjs的初学者 我使用护照和 GoogleStrategy 通过谷歌进行身份验证 使用下面的代码我有req user id 123456 in 用户 你好路由处理程序 但我想得到一些类似的没有会话支持的
  • 如何使用 iCloud 访问 Xcode 项目

    我最近购买了一台 MacBook Pro 我将用它来开发 iPhone 应用程序 我希望能够在 Macbook 和 iMac 之间传输 Xcode 项目 就像使用 iCloud 传输 Word 文档一样 有没有一种安全的方法可以做到这一点
  • 递归关系[关闭]

    很难说出这里问的是什么 这个问题模棱两可 含糊不清 不完整 过于宽泛或言辞激烈 无法以目前的形式合理回答 如需帮助澄清此问题以便重新打开 访问帮助中心 如何以最佳复杂度计算非常大的 n 例如 10 14 的 tribonacci 数 Tri
  • 帮助理解为什么我们的应用程序在Win7上弹出UAC对话框

    我们有一个 C 非托管应用程序 它似乎会导致 UAC 提示 似乎发生在Win7 而非 Vista 不幸的是 UAC dlg 是系统模式的 所以我无法附加调试器来检查代码所在的位置 并且在 msdev 下运行 我们使用的是 2008 以提升模
  • C中的任意长度字符串

    我需要对字符串进行一些操作 例如在某些位置添加字母 我不知道它的大小是多少 这取决于输入 如何定义字符串而不指定其大小 我希望它能够适应我放入其中的任何内容 为什么我不能只传递一个空的char 到一个方法 编译器不允许这样做 根据答案 我明
  • 如何避免Java编译中的“Method Too Large”错误?

    我有一个用 bigloo 方案功能语言编写的解析器 我需要将其编译成 java 类 整个解析器被编写为单个函数 不幸的是 这导致 JVM 编译器抛出 方法太大 警告 然后给出 localvar 中的远标签 错误 有什么可能的方法可以避免这个
  • 对于鼻子测试类使用 __init__(self) 而不是 setup(self) 有缺点吗?

    Running nosetests s for class TestTemp def init self print init self even 0 def setup self print setup self odd 1 def te
  • .NET 代码在正常进程退出时执行?

    In C有atexit函数 其中 atexit 函数注册给定的函数 以便在正常进程终止时通过 exit 3 或通过从程序的 main 返回来调用 Python 也有类似的功能 NET 是否提供了在正常进程终止时调用代码的方法 我知道有些事情