16

例如,在旧的 .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);

实际上,在任何 Windows API 代码包源文件中都没有使用HandleRef,而在旧的 .NET Framework 源文件中的本机方法签名中大量使用了它。

4

3 回答 3

10

这有点鱼腥味。当句柄值存储在 SafeHandle 派生对象中时,不需要 HandleRef。代码包声明了 ZeroInvalidHandle,其中有几个派生的,例如 SafeWindowHandle。

但是,它实际上并没有在任何地方使用这些 SafeHandle 类。不确定是否真的需要,很多 Vista 和 Win7 扩展实际上是 COM 接口。不是传统的基于句柄的 C API。它们通过引用计数保持活动状态,因此不会受到这种垃圾收集器事故的影响。

就我个人而言,我只是从不担心这个。执行 API 调用时收集类对象是一个错误。它可以在 API 调用完成的微秒内轻松发生。仍然是一个错误,只是不是导致 API 调用失败的错误。不太确定我是否真的希望它不会失败,当我的代码中有错误时,我更喜欢异常。微软需要保护自己免受这种情况的影响,他们不想因异常而受到指责。我愿意。

于 2010-12-02T16:04:30.383 回答
5

我的猜测是,使用较新的代码示例IntPtr仅仅是因为它更易于理解。

快速浏览一下 Reflector 在NativeMethods.NET Framework 中找到的各种类中的函数签名表明,实际用法在两者之间得到了很好的划分。

我认为这是基于是否需要防止对象过早地被垃圾收集(这是使用的主要优点HandleRef)。另请记住,HandleRef除非您传递的句柄是托管对象,否则使用是不必要的。非托管对象不会被垃圾回收。

于 2010-12-02T13:26:12.640 回答
3

IntPtr只是包装指针的结构。至于HandleRef MSDN“用 HandleRef 包装句柄可以保证托管对象在平台调用调用完成之前不会被垃圾收集。” 如果在 P/Invoke 调用后不对其进行任何处理,GC 有可能在 P/Invoke 期间完成句柄。所以 HandleRef 看起来更安全。

于 2010-12-02T13:17:12.567 回答