20

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?

Davio
  • 4,609
  • 2
  • 31
  • 58
  • What benefit does `SafeHandle` give you that just storing the `IntPtr` does not? – Scott Chamberlain Aug 15 '12 at 16:25
  • 4
    @ScottChamberlain - `SafeHandle` is `IDisposable` and ensures that resources referred to by the handle are released. `IntPtr` is simply a pointer-sized value that can be passed around - it has no disposal semantics. – LBushkin Aug 15 '12 at 16:31
  • Assuming you're allowed to fee the memory, unless you can de-allocate the pointer memory using `Marshal.FreeBSTR`, `Marshal.FreeCoTaskMem`, or `Marshal.FreeHGlobal`, I don't think that you can safely de-allocate the memory from C#. Using `IntPtr`, C# will not attempt to free any memory automatically. – Pooven Aug 15 '12 at 16:44

1 Answers1

16

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

Community
  • 1
  • 1
LBushkin
  • 129,300
  • 32
  • 216
  • 265
  • Surely `IntPtr` is 64 bits not 65? I made the edit--please revert and explain more (I'm prepared for this to be my "learn something new every day moment). – sblom Aug 15 '12 at 16:49
  • Well, creating my own SafeHandle implentation as I said is no big deal, there are plenty examples on it. What I would like to know is if I can use SafeHandle and IntPtr interchangeable, thus could I do: `static extern bool Initialize([In] string name, out SafeHandle)` instead of the current `static extern bool Initialize([In] string name, out IntPtr)`? – Davio Aug 15 '12 at 17:21
  • @sblom: Nope, that was just a typo on my part. Thanks for catching it. – LBushkin Aug 15 '12 at 17:56
  • In principle you should be able to use your custom `SafeHandle`-derivative in place of `IntPtr`. The interop marshaling system has special handling for `SafeHandles`. However, writing a correctly implemented handle class requires care. Read the remarks section under [SafeHandle Class Reference](http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.safehandle.aspx) as a starting point. – LBushkin Aug 15 '12 at 18:01