以类型安全的方式制定IntPtr

时间:2012-02-21 11:51:27

标签: 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?

1 个答案:

答案 0 :(得分:6)

在处理非托管内存时,每个定义都可能出现“意外”。

那就是说,你可以做的就是将你的IntPtr包装在一个课堂上,就像微软对他们的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处置时自动完成。