Can I use SafeHandle instead of IntPtr?

Davio picture Davio · Aug 15, 2012 · Viewed 13.3k times · Source

I've searched the internet far and wide but didn't find a good explanation.

My question is pretty simple.

I have a DLL which has a function called Initialize and one of the parameters is a pointer that will receive a handle to be used with subsequent calls. Another parameter is a string which I will list for completeness. The signature I'm using is (in its simple form):

[DllImport(MyDll)]
static extern bool Initialize([In] string name, out IntPtr handle);

The signature in the DLL itself is written as: Initialize(LPTSTR name, HANDLE handle) with the comment "HANDLE: Pointer to a location that will receive the handle".

And subsequent calls are in the form of

[DllImport(MyDll)]
static extern bool DoSomething(IntPtr handle, uint randomParameter);

I have been reading about SafeHandle and I was wondering if I could use it to substite for my IntPtr handle. And if I can, how do I do it? Extending the abstract SafeHandle class isn't an issue, but can I directly substitute my IntPtr for SafeHandle (and use default Marshalling) or do I need to do something extra?

Answer

LBushkin picture LBushkin · Aug 15, 2012

You can find a more complete answer about the difference between SafeHandle and IntPtr here: IntPtr, SafeHandle and HandleRef - Explained

However, to summarize, IntPtr should be used where the argument is actually a machine-size pointer - SafeHandle should be used where the argument is actually a Win32 handle. These types are not generally interchangeable; the size of IntPtr will vary on different architectures (32 bits on x86 and 64 bits on x64 and amd64). NOTE: Under the covers I believe SafeHandle uses an IntPtr as well).

Also, unlike IntPtr, SafeHandle actually performs disposal of resources when a type is garbage collected. This ensures that system resources are not leaked when your program is running (although you should Dispose() of SafeHandle instances early when possible). Note that SafeHandle is actually abstract because there many different kinds of handles which require different approaches for proper disposal and handling.

In your specific case, you need to look at the documentation for the DLL you are calling. If it is a Win32 DLL, there may already be a SafeHandle type for it. If it's a third-party DLL, then you can roll your own SafeHandle implementation - assuming that in addition to Initialize() there is some version of Release() (or equivalent).

Some additional interesting tidbits about IntPtr vs SafeHandle can be found at:

Use SafeHandle to encapsulate native resources

SafeHandle Class Reference

SafeHandles and Critical Finalization