When you call makeNewHandleOfA
, you own the returned instance, so you must release it.
When you call getHandleOfA
, you do not own the returned instance, but you still want to manage its lifecyle (ie: prevent the underlying native library from releasing it).
It means you basically want different Release strategies for those two use cases.
Option 1
With:
internal class MyOwnedSafeHandleA : MySafeHandleA
{
protected override bool ReleaseHandle()
{
releaseHandleToA(handle);
return true;
}
}
internal class MySafeHandleA : SafeHandle
{
private int refCountIncremented;
internal void IncrementRefCount(Action<MySafeHandleA> nativeIncrement)
{
nativeIncrement(this);
refCountIncremented++;
}
protected override bool ReleaseHandle()
{
while (refCountIncremented > 0)
{
releaseHandleToA(handle);
refCountIncremented--;
}
return true;
}
}
You can declare your DllImports like so:
[DllImport("somedll.dll")]
public extern MyOwnedSafeHandleA makeNewHandleOfA();
[DllImport("somedll.dll")]
private extern MySafeHandleA getHandleOfA(MySafeHandleB handleToB, int index);
[DllImport("somedll.dll")]
private extern void addRefHandleToA(MySafeHandleA handleToA);
Option 2
You could declare your SafeHandle like this:
internal class MySafeHandleA : SafeHandle
{
MySafeHandleA(IntPtr handle) : base(IntPtr.Zero, true)
{
SetHandle(handle);
}
protected override bool ReleaseHandle()
{
releaseHandleToA(handle);
return true;
}
}
And use it like so:
[DllImport("somedll.dll"]
private extern IntPtr getHandleOfA(MySafeHandleB handleToB, int index);
[DllImport("somedll.dll"]
private extern void addRefHandleToA(IntPtr ptr);
public MySafeHandleA _getHandleOfA(MySafeHandleB handleToB, int index)
{
IntPtr ptr = getHandleOfA(handleToB, index);
addRefHandleToA(ptr);
return new MySafeHandleA(ptr);
}