Note that there are some explanatory texts on larger screens.

plurals
  1. POCorrect use of SafeHandles in this P/Invoke use case
    text
    copied!<p>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)</p> <pre><code>[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) </code></pre> <p>The meanings of these calls are are follows:</p> <ol> <li><p>Get a pointer/handle to an opaque type A from an existing handle B. The internal reference count of the returned handle is unaffected.</p></li> <li><p>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.</p></li> <li><p>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.</p></li> <li><p>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.</p></li> <li><p>Perform some operation with the handle</p></li> </ol> <p>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:</p> <pre><code>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) </code></pre> <p>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.</p> <p>So, perhaps I should always ensure getHandleOfA calls are paired with an immediate addRefHandleToA, like this:</p> <pre><code>[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; } </code></pre> <p>Is this safe?</p> <p>EDIT: Well, no it is clearly not safe, as addRefHandleToA(safeHandle); could fail. Is there a way I can make it safe? </p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload