c# - 以类型安全的方式编码(marshal) IntPtr

标签 c# pinvoke marshalling

我有以下c函数

opaque_struct* create() {}
void free(opaque_struct*) {}

我想使用 PInvoke 调用:

[DllImport("test")]
public static extern IntPtr create ();
[DllImport("test")]
public static extern void free (IntPtr);

我想这会很好用,但我正在寻找一种方法在托管代码中明确声明“free”只接受“create”返回的 IntPtr 并避免意外传递从其他函数接收的其他 IntPtr。

就所有托管代码而言,指向的结构是不透明的。

即使我所做的只是给它一个新名称,没有额外的属性,也无法扩展 IntPtr。

有什么方法可以使这种类型化的 IntPtr 成为可能吗?

最佳答案

在处理非托管内存时,根据定义总是存在“意外”的可能性。

就是说,您可以将 IntPtr 包装在一个类中,就像 Microsoft 对其 SafeHandle 所做的那样类和关联的 SafeFileHandleSafePipeHandle...等

您可以创建自己的 SafeHandle 类(您可以继承自 System.Runtime.InteropServices.SafeHandle),并在您的 P/Invoke 声明中使用它:

[DllImport("test")]
public static extern MySafeHandle create ();

[DllImport("test")]
public static extern void free (MySafeHandle pointer);

SafeHandle 的另一个好处是它实现了 IDisposable,因此允许使用 using 语句来确保您的 free( ) 方法总是被调用:

using (MySafeHandle ptr = create())
{
    // Use your ptr instance here
    // You can retrieve the IntPtr value itself using
    // ptr.DangerousGetHandle()

    // When you get out of the scope of the using(), the MySafeHandle
    // object will be disposed and ptr.ReleaseHandle() will be called.
    // Just add your call to free() in the overriden ReleaseHandle method
}

如您所见,甚至不需要手动调用 free(),因为它会在释放 SafeHandle 时自动完成。

关于c# - 以类型安全的方式编码(marshal) IntPtr,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9377101/

相关文章:

ruby-on-rails - Rails 2.3.14:如何序列化 ActionController::Request 对象?

c# - 将具有固定大小数组的 C++ 结构编码到 C# 中

c# - 使用自定义 JsonConverter 时无限转换循环

c# - 缓存对象集合的最佳方法。一起还是作为单独的元素?

c# - 如何在 .NET 中调用 DrawThemeTextEx

c# - 桌面添加新窗口时是否有触发事件

scala - jackson-module-scala (play) : registerModule(DefaultScalaModule): found DefaultScalaModule. 类型;需要 : databind. 模块

c# - 更快的字符串 GetHashCode(例如使用多核或 GPU)

c# - c#中的数据加密和 key 管理

.net - 如何将字符串数组转换为 .NET 中的 LPCWSTR 以传递给 Win32 API 函数?