例如,在旧的.NET Framework 2.0源代码(Windows窗体,Visual Studio 2005 - Whidbey)中, GetClientRect 函数是使用 HandleRef 定义的:
[DllImport(ExternDll.User32, ExactSpelling=true, CharSet=CharSet.Auto)]
public static extern bool GetClientRect(HandleRef hWnd, [In, Out] ref NativeMethods.RECT rect);
在新的Windows API代码包(来自Microsoft,2009/2010)中,使用 IntPtr 定义了相同的功能:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool GetClientRect(IntPtr hwnd, ref CoreNativeMethods.RECT rect);
实际上 HandleRef 未在任何Windows API Code Pack源文件中使用,而在旧.NET Framework源文件中的本机方法签名中大量使用。
答案 0 :(得分:9)
有点可疑。当句柄值存储在SafeHandle派生对象中时,不需要HandleRef。代码包声明了ZeroInvalidHandle,其中包含几个派生的,如SafeWindowHandle。
但是,它实际上并没有使用任何这些SafeHandle类。不确定它是否真的必须,很多Vista和Win7扩展实际上是COM接口。不是传统的基于句柄的C API。它们通过引用计数保持活跃,因此不会受到这种垃圾收集器事故的影响。
就个人而言,我从不担心这一点。在执行API调用时获取收集的类对象是一个错误。 API调用完成后,它可以很容易地发生微秒。仍然是一个错误,只是没有一个使API调用失败的错误。不太确定我真的希望它不会失败,当我的代码中出现错误时,我更喜欢异常。微软需要保护自己免受此事的侵害,他们不想为这个例外负责。我做。
答案 1 :(得分:3)
IntPtr 只是包装指针的结构。至于 HandleRef MSDN says“使用HandleRef包装句柄可确保在平台调用调用完成之前不会对托管对象进行垃圾回收。”如果在P / Invoke调用后你没有对它做任何事情,那么GC有可能在P / Invoke期间完成句柄。所以HandleRef看起来更安全。
答案 2 :(得分:3)
我的猜测是,较新的代码示例仅使用IntPtr
,因为它更容易理解。
快速浏览一下在.NET Framework中找到的各种NativeMethods
类中的函数签名处的Reflector,可以看出两者之间的实际用法是相当分开的。
我认为这取决于是否需要防止对象过早地被垃圾收集(primary advantage使用HandleRef
)。另请注意,除非您传递的句柄是托管对象,否则不必使用HandleRef
。非托管对象不会被垃圾收集。