Reputation: 18521
I have the following c functions
opaque_struct* create() {}
void free(opaque_struct*) {}
Which I want to call using PInvoke:
[DllImport("test")]
public static extern IntPtr create ();
[DllImport("test")]
public static extern void free (IntPtr);
I guess this would work fine but I'm looking for a way to in the managed code explicitly state that "free" only takes IntPtr returned by "create" and avoid accidentally passing other IntPtr received from other functions.
The struct pointed at is opaque as far as all managed code is concerned.
It is not possible to extend IntPtr even If all I do is give it a new name, no extra properties.
Is there any way to make this typed IntPtr?
Upvotes: 3
Views: 1834
Reputation: 49013
When dealing with unmanaged memory, there is always the possibility of an "accident" per definition.
That said, what you could do is wrap your IntPtr
in a class, just like Microsoft did with their SafeHandle class and associated SafeFileHandle
, SafePipeHandle
...etc.
You could create your own SafeHandle
class (you can inherit from System.Runtime.InteropServices.SafeHandle
), and use it in your P/Invoke declarations:
[DllImport("test")]
public static extern MySafeHandle create ();
[DllImport("test")]
public static extern void free (MySafeHandle pointer);
Another benefit of SafeHandle
is that it implements IDisposable
and thus allows the use of the using
statement to ensure your free()
method is always called:
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
}
As you can see, it isn't even needed to call free()
manually, as it's done automatically when the SafeHandle
is disposed.
Upvotes: 6