.net - 为什么使用 FinalReleaseComObject 而不是 ReleaseComObject?

标签 .net com interop

我知道基本区别为 ReleaseComObject仅将某些计数器减一和 FinalReleaseComObject将其减小到零。

所以我通常听到的是,调用FinalReleaseComObject因为这样你就确定 COM 对象真的被释放了。

但这让我想知道,这个柜台有道理吗?如果你总是调用 FinalReleaseComObject,你是不是破坏了这个机制? .如果在您调用 ReleaseComObject 之前该计数器不是一个,可能没有原因吗?

什么可能导致它不应该高于一?

提前致谢。

PS:我的 COM 经验只包括使用 Excel 互操作。不确定这个问题是否是该域的本地问题(即在 Office Interop 之外,FinalReleaseComObject 不经常使用)。

更新 1

article丹提到谈论使用 ReleaseComObject当你完成时。据我了解article ,这是正常的方式。我认为,如果您始终如一地这样做,它应该可以正常工作。在对 article 的评论中作者建议有人调用ReleaseComObject在一个循环中直到它真正被释放(article 是从 2006 年开始的,所以这类似于调用 FinalReleaseComObject )。但他也表示这可能很危险。

If you really want to the RCW to call Release() at a particular point in the code, you can call ReleaseComObject() in a loop until the return value reaches zero. This should ensure the RCW will call Release(). However, if you do that, be warned, when the other managed references try to use that RCW, it will cause an exception."



这让我相信总是调用 FinalReleaseComObject 确实不是一个好主意。 ,因为您可能会在其他地方导致异常。正如我现在所看到的,只有在绝对确定可以的情况下才应该调用它。

不过,我在这方面的经验很少。我不知道我怎么能确定。如果计数器在不应该增加的时候增加,解决这个问题不是更好吗?如果是这样,那么我会说FinalReleaseComObject与其说是最佳实践,不如说是一种技巧。

最佳答案

一些序言...

运行时可调用包装器 (RCW) 仅在其包装的非托管 COM 接口(interface)上调用 IUnknown.AddRef 一次。但是,RCW 还维护对 RCW 本身的托管引用数量的单独计数。调用 Marshal.ReleaseComObject 会减少托管引用的这种单独计数。当托管引用的计数达到零时,RCW 会在非托管 COM 接口(interface)上调用一次 IUnknown.Release。

Marshal.FinalReleaseComObject 通过一次调用将托管引用计数归零,因此立即调用封装的非托管 IUnknown.Release 方法(假设托管引用计数尚未为零)。

那么为什么 Marshal.ReleaseComObject 和 Marshal.FinalReleaseComObject 都有呢?调用 Marshal.FinalReleaseComObject 只是避免了编写一个循环来重复调用 Marshal.ReleaseComObject 直到它返回 0,当你希望表明你已经 真的完成使用 COM 对象 现在 .

为什么使用 Marshal.ReleaseComObject 或 Marshal.FinalReleaseComObject?我知道有两个原因:

首先是确保被包装的 COM 对象使用的非托管资源(例如文件句柄、内存等)在调用非托管 IUnknown.Release() 方法后尽快被释放。

第二个是确保调用非托管 IUnknown.Release() 方法的线程在您的控制之下,而不是终结器线程。

如果不调用这些 Marshal 方法中的任何一个,RCW 的终结器最终将在 RCW 被垃圾回收后的某个时间调用非托管 IUnknown.Release() 方法。

有关确凿的详细信息,请参阅 Visual C++ 团队博客条目 Mixing deterministic and non-deterministic cleanup

关于.net - 为什么使用 FinalReleaseComObject 而不是 ReleaseComObject?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1827059/

相关文章:

com - 在 Windows7 上,regsvr32 不会写入 HKCR\CLSID

arrays - 将 C 字符数组转换为字符串

c# - 替换作为属性/公共(public)字段检索的对象列表中的元素

powershell - 如何在 PowerShell 中查询 .pdb 文件?

c++ - 当注册表中不存在 CLSID 时如何查找 DLL

c# - p/invoke C函数返回指向结构的指针

c# - 如何获取outlook联系人的头像?

c# - 加密名称

c# - 如何在Winform中显示欢迎画面?

c# - 另一个 DeflateStream 解压问题(使用 using 和内存流)