views:

1456

answers:

4

Without pointing me to MSDN, could someone give a concise, clear explanation of the purpose of each of these and when to use them. (IntPtr, SafeHandle and HandleRef)

A: 

IntPtr is just a standard 32bit pointer to a memory location of some type of object. It's used frequently by external calls to the native Win32 DLLs.

Chris Marisic
Firstly, the size depends on the platform. Secondly, it's just an integer sized the same as the platform bit-ness; it has no special "pointer" meaning inherently attached to it. Memory pointers can be conveniently exposed as `IntPtr` though because of its variable size, as are WinAPI handles (which are also 32 or 64 bit wide depending on platform).
romkyns
/Shrug, I disagree with the DV's because my answer is still completely factual and I even specifically said Win32 DLLs.
Chris Marisic
+7  A: 

IntPtr is just a simple integer-based struct that can hold a pointer (ie., 32 bit size on 32-bit systems, 64-bit size on 64-bit systems).

SafeHandle is a class that is intended to hold Win32 object handles - it has a finalizer that makes sure that the handle is closed when the object is GC'ed. SafeHandle is an abstract class because different Win32 handles have different ways they need to be closed. Prior to the introduction of SafeHandle, IntPtr was used to hold Win32 handles, but ensuring that they were properly closed and prevented from being GC'ed was the responsibility of the programmer.

HandleRef is a way to make sure that an unmanaged handle is not GC'ed when you're in the middle of a P/Invoke call. Without something like HandleRef, if your managed code doesn't do anything with the handle after the P/Invoke call, if the GC were run during the P/Invoke call it would not realize that the handle was still in use and might GC it. I imagine (but I'm not sure and haven't looked) that SafeHandle might use HandleRef as part of its management of the encapsulated handle.

Michael Burr
Minor correction. Use HandleRef when you don't want a *managed* object GC'ed during PInvoke.e.gclass HWnd { public IntPtr Handle; }HWnd a = new HWnd();B.SendMessage(a.Handle, ...); <-- a could be GC'ed in PInvokeB.SendMessage(new HandleRef(a, a.Handle)) <-- now a cannot be GC'ed in PInvoke
Ifeanyi Echeruo
+2  A: 
HWnd a = new HWnd();
B.SendMessage(a.Handle, ...);

a could be GC'ed in PInvoke B.SendMessage

I don't understand this, I'm using .NET since version 1.0 and was always thinking a would not be GC'ed before the method where a is defined returns, the minimum that what I would expect is that a is not GC'ed until SendMessage returns, it just don't make sense to me. Where is this behaviour of the GC documented?

Yes, I don't get it too.
devoured elysium
http://blogs.msdn.com/cbrumme/archive/2003/04/19/51365.aspx explains how and why `a` can get GC'd here in more detail (though still requires an understanding of what gets GCd and when). Also, you shouldn't post questions in the "Answer" box.
romkyns
A: 
HWnd a = new HWnd();
B.SendMessage(a.Handle, ...);

Assuming this is the only reference to "a" in the program, this is equivalent to:

HWnd a = new HWnd();
IntPtr h = a.Handle;
// a is no longer needed and thus can be GC'ed
B.SendMessage(h, ...);

The problem is that when "a" is disposed, it will close the handle. If this happens before or during the call to SendMessage, the handle will be invalid.

HandleRef prevents "a" from being garbage collected before the program is done with h.

Ryan