【问题标题】:Can I use SafeHandle instead of IntPtr?我可以使用 SafeHandle 代替 IntPtr 吗?
【发布时间】:2012-08-11 23:21:04
【问题描述】:

我已经在互联网上进行了广泛的搜索,但没有找到很好的解释。

我的问题很简单。

我有一个 DLL,它有一个名为 Initialize 的函数,其中一个参数是一个指针,它将接收用于后续调用的句柄。另一个参数是一个字符串,为了完整起见,我将列出它。我使用的签名是(以简单的形式):

[DllImport(MyDll)]
static extern bool Initialize([In] string name, out IntPtr handle);

DLL 本身的签名写成:Initialize(LPTSTR name, HANDLE handle) 并带有注释“HANDLE:指向将接收句柄的位置的指针”。

而后续调用的形式为

[DllImport(MyDll)]
static extern bool DoSomething(IntPtr handle, uint randomParameter);

我一直在阅读有关SafeHandle 的信息,我想知道是否可以用它来代替我的 IntPtr 句柄。如果可以,我该怎么做?扩展抽象的 SafeHandle 类不是问题,但我可以直接用我的 IntPtr 替换 SafeHandle(并使用默认编组)还是需要做一些额外的事情?

【问题讨论】:

  • SafeHandle 给您带来什么好处,而仅存储 IntPtr 没有?
  • @ScottChamberlain - SafeHandleIDisposable 并确保释放句柄引用的资源。 IntPtr 只是一个可以传递的指针大小的值 - 它没有处理语义。
  • 假设您可以使用内存,除非您可以使用Marshal.FreeBSTRMarshal.FreeCoTaskMemMarshal.FreeHGlobal 取消分配指针内存,我认为您不能安全地使用从 C# 中取消分配内存。使用IntPtr,C# 将不会尝试自动释放任何内存。

标签: c# pinvoke marshalling handle


【解决方案1】:

您可以在此处找到有关SafeHandleIntPtr 之间区别的更完整答案:IntPtr, SafeHandle and HandleRef - Explained

然而,总而言之,IntPtr 应该用在参数实际上是一个机器大小的指针 - SafeHandle 应该用在参数实际上是一个 Win32 句柄的地方。这些类型通常不可互换; IntPtr 的大小会因不同的架构而异(x86 上为 32 位,x64 和 amd64 上为 64 位)。注意:在幕后我相信SafeHandle 也使用IntPtr

另外,与IntPtr 不同,SafeHandle 实际上是在一个类型被垃圾回收时执行资源处置。这可确保在您的程序运行时不会泄漏系统资源(尽管您应该尽可能早地使用 Dispose() of SafeHandle 实例)。请注意,SafeHandle 实际上是抽象的,因为有许多不同种类的句柄需要不同的方法来正确处理和处理。

在您的具体情况下,您需要查看您正在调用的 DLL 的文档。如果它是一个 Win32 DLL,那么它可能已经有一个 SafeHandle 类型。如果它是第三方 DLL,那么您可以推出自己的 SafeHandle 实现 - 假设除了 Initialize() 之外还有一些版本的 Release()(或等效版本)。

有关 IntPtr 与 SafeHandle 的一些其他有趣的花絮可以在以下位置找到:

Use SafeHandle to encapsulate native resources

SafeHandle Class Reference

SafeHandles and Critical Finalization

【讨论】:

  • IntPtr 肯定是 64 位而不是 65 位?我进行了编辑——请恢复并解释更多(我已准备好让这成为我的“每天学习新事物的时刻)。
  • 好吧,正如我所说,创建我自己的 SafeHandle 实现没什么大不了的,有很多例子。我想知道的是我是否可以使用 SafeHandle 和 IntPtr 互换,因此我可以这样做:static extern bool Initialize([In] string name, out SafeHandle) 而不是当前的static extern bool Initialize([In] string name, out IntPtr)
  • @sblom:不,这只是我的一个错字。感谢收看。
  • 原则上您应该能够使用您的自定义SafeHandle-derivative 代替IntPtr。互操作封送系统对SafeHandles 有特殊处理。但是,编写正确实现的句柄类需要小心。阅读SafeHandle Class Reference下的备注部分作为起点。
猜你喜欢
  • 2010-10-06
  • 2017-09-09
  • 2022-01-23
  • 2015-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多