IntPtr,SafeHandle和HandleRef - 解释

时间:2009-02-08 23:36:46

标签: .net winapi interop

在没有指向MSDN的情况下,有人可以简明扼要地解释每个问题的目的以及何时使用它们。 (IntPtr,SafeHandle和HandleRef)

3 个答案:

答案 0 :(得分:49)

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

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

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

答案 1 :(得分:17)

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防止“a”在程序完成之前被垃圾收集。

答案 2 :(得分:1)

看起来SafeHandle确实包含了HandleRef的KeepAlive行为: Project Roslyn SafeHandle.cs http://referencesource.microsoft.com/#mscorlib/system/runtime/interopservices/safehandle.cs,743afbddafaea263

/*
  Problems addressed by the SafeHandle class:
  1) Critical finalization - ensure we never leak OS resources in SQL.  Done
     without running truly arbitrary & unbounded amounts of managed code.
  2) Reduced graph promotion - during finalization, keep object graph small
  3) GC.KeepAlive behavior - P/Invoke vs. finalizer thread ---- (HandleRef)
<...>
*/

但我不确定,看起来keepalive行为只能通过向构造函数提供false值来实现,构造函数只是将对象标记为无法终止,因此你必须手动调用SafeHandle的Dispose()来防止资源泄漏。我不对吗? 有人可以解释源代码,

是什么
private extern void InternalDispose();
private extern void InternalFinalize();