IntPtr、SafeHandle 和 HandleRef - 解释

Posted

技术标签:

【中文标题】IntPtr、SafeHandle 和 HandleRef - 解释【英文标题】:IntPtr, SafeHandle and HandleRef - Explained 【发布时间】:2010-10-06 07:32:59 【问题描述】:

如果不将我指向 MSDN,有人可以简明扼要地解释每一个的目的以及何时使用它们。 (IntPtr、SafeHandle 和 HandleRef)

【问题讨论】:

没什么。只是寻找每个的简短摘要,以确保我正确使用它们。如果我阅读 MSDN 和其他人的描述,我会更好地了解我所做的是否正确。 【参考方案1】:

IntPtr 只是一个简单的基于整数的结构,可以保存一个指针(即,在 32 位系统上为 32 位大小,在 64 位系统上为 64 位大小)。

SafeHandle 是一个用于保存 Win32 对象句柄的类 - 它有一个终结器,可确保在对象被 GC 时关闭句柄。 SafeHandle 是一个抽象类,因为不同的 Win32 句柄有不同的关闭方式。在引入SafeHandle 之前,IntPtr 用于保存 Win32 句柄,但确保它们被正确关闭并防止被 GC 是程序员的责任。

HandleRef 是一种确保在 P/Invoke 调用过程中未对非托管句柄进行 GC 的方法。如果没有HandleRef 之类的东西,如果您的托管代码在 P/Invoke 调用之后对句柄没有做任何事情,如果在 P/Invoke 调用期间运行 GC,它不会意识到句柄仍在使用中,并且可能GC它。我想(但我不确定也没有看过)SafeHandle 可能会使用HandleRef 作为其封装句柄管理的一部分。

【讨论】:

小幅修正。当您不希望在 PInvoke 期间对 托管 对象进行 GC 时,请使用 HandleRef。例如 class HWnd public IntPtr Handle; HWnd a = 新 HWnd(); B.SendMessage(a.Handle, ...); 另一个补充:SafeHandle 包括引用计数以防止句柄回收攻击。 谁能确认safehandle使用handleref?或者至少有类似的机制? @Assimilater 是的:机制类似。 HandleRef 和 SafeHandle 都受到 GC 保护,直到调用返回;并且两者都保护对象的终结器不运行和删除 IntPtr。 HandleRef 指向带有终结器的对象;而 SafeHandle 具有该终结器的对象。 考虑到这三个的结构,IntPtr 不能与SafeHandleSafeRef 交换,因为Safe* 类型都不是仅32/64 位,对吧?【参考方案2】:
HWnd a = new HWnd();
B.SendMessage(a.Handle, ...);

假设这是程序中对“a”的唯一引用,这相当于:

HWnd a = new HWnd();
IntPtr h = a.Handle;
// a is no longer needed and thus can be GC'ed
B.SendMessage(h, ...);

问题是当“a”被释放时,它会关闭句柄。如果在调用 SendMessage 之前或期间发生这种情况,则句柄将无效。

HandleRef 防止在程序使用 h 完成之前对“a”进行垃圾回收。

【讨论】:

以上是关于IntPtr、SafeHandle 和 HandleRef - 解释的主要内容,如果未能解决你的问题,请参考以下文章

无法将 ReleaseHandle 中的 SafeHandle 实例传递给本机方法

SafeHandle 中 invalidHandleValue 的作用是啥?

使用 SafeHandle 的约束与抽象类

safehandle 和析构函数

错误:ZLibStreamHandle 类型的 SafeHandle 或 CriticalHandle 未能正确释放

编组 Win32 结构时的安全句柄 (PROCESS_INFORMATION)