在 C# 中使用使用不透明句柄和内部引用计数的本机 Dll,我有以下 P/Invoke 签名(全部用 DllImport 属性装饰)
[DllImport("somedll.dll"]
public extern IntPtr getHandleOfA(IntPtr handleToB, int index); //(1)
public extern IntPtr makeNewHandleOfA(); //(2)
public extern void addRefHandleToA(IntPtr handleToA); //(3)
public extern void releaseHandleToA(IntPtr handleToA); //(4)
public extern void doSomethingWithHandle(IntPtr handleToA) //(5)
这些调用的含义如下:
从现有句柄 B 获取指向不透明类型 A 的指针/句柄。返回的句柄的内部引用计数不受影响。
新建一个A的句柄,内部引用计数是预先递增的,这个句柄应该由客户端用函数4释放,否则会发生泄漏。
告诉 dll 在内部增加句柄 A 的引用计数。这使我们可以确保 dll 不会在内部释放我们通过函数 1 获得的句柄。
告诉 dll 减少句柄的引用计数。如果我们增加了句柄的引用计数,或者通过函数 2 获取它,则应该调用它。
使用句柄执行一些操作
我想用我自己的 SafeHandle 子类替换 IntPtr。当我通过创建新句柄来获取句柄时,过程很明显;句柄的引用计数在 dll 中是预先递增的,所以我只是重写了 SafeHandle 的 Release 函数,并调用 releaseHandleToA(handle)。使用这个新类“MySafeHandle”,我可以像这样更改上面的 P/Incvoke 签名:
public extern MySafeHandleA getHandleOfA(MySafeHandleB handleToB, int index); //(1)
public extern MySafeHandleA makeNewHandleOfA(); //(2)
public extern void addRefHandleToA(MySafeHandleA handleToA); //(3)
public extern void releaseHandleToA(MySafeHandleA handleToA); //(4)
public extern void doSomethingWithHandle(MySafeHandleA handleToA) //(5)
但是这里有一个错误:在函数 1 中,获取的句柄没有增加其引用计数,因此尝试释放句柄将是错误的。
所以,也许我应该始终确保 getHandleOfA 调用与立即 addRefHandleToA 配对,如下所示:
[DllImport("somedll.dll"]
private extern MySafeHandleA getHandleOfA(MySafeHandleB handleToB, int index); //(1)
[DllImport("somedll.dll"]
private extern void addRefHandleToA(MySafeHandleA handleToA); //(3)
public MySafeHandleA _getHandleOfA(MySafeHandleB handleToB, int index)
{
var safehandle = getHandleOfA(handleToB, index);
addRefHandleToA(safeHandle);
return safeHandle;
}
这安全吗?
编辑:好吧,不,这显然不安全,因为 addRefHandleToA(safeHandle); 可能会失败。有什么办法可以让它安全吗?