Working in C# with a native Dll, that uses opaque handles and internal reference counting, I have the following P/Invoke signatures (all decorated with DllImport attribute)
[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)
The meanings of these calls are are follows:
Get a pointer/handle to an opaque type A from an existing handle B. The internal reference count of the returned handle is unaffected.
Create a new handle of A. The internal reference count is pre-incremented, and the handle should be released by the client with function 4, otherwise a leak will occur.
Tell the dll to internally increase the reference count of a handle A. This allows us to be sure that the dll will not internally release a handle that we have acquired through function 1.
Tell the dll to decrease the ref count of a handle. Should be called if we have increased the ref count of a handle, or acquired it through function 2.
Perform some operation with the handle
I would like to replace the IntPtr with my own subclass of SafeHandle. When I acquire handles by creating new ones, the procedure is obvious; the handle's ref count is pre-incremented inside the dll, so I just override the Release function of SafeHandle, and call releaseHandleToA(handle). Using this new class 'MySafeHandle', I can change the P/Incvoke signatures above like so:
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)
There is an error here though: in function 1, the handle acquired has not had its refcount increased, so trying to release the handle would be an error.
So, perhaps I should always ensure getHandleOfA calls are paired with an immediate addRefHandleToA, like this:
[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;
}
Is this safe?
EDIT: Well, no it is clearly not safe, as addRefHandleToA(safeHandle); could fail. Is there a way I can make it safe?