16

For example, in the old .NET Framework 2.0 Source Code (Windows Forms, Visual Studio 2005 - Whidbey), the GetClientRect function was defined using HandleRef:

    [DllImport(ExternDll.User32, ExactSpelling=true, CharSet=CharSet.Auto)]
    public static extern bool GetClientRect(HandleRef hWnd, [In, Out] ref NativeMethods.RECT rect); 

In the new Windows API Code Pack (from Microsoft, 2009/2010) the same function is defined using IntPtr:

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool GetClientRect(IntPtr hwnd, ref CoreNativeMethods.RECT rect);

Actually HandleRef is not used in any of the Windows API Code Pack source files, while it was heavily used in the native methods signatures in the old .NET Framework source files.

TechAurelian
  • 5,561
  • 5
  • 50
  • 65
  • possible duplicate of [IntPtr, SafeHandle and HandleRef - Explained](http://stackoverflow.com/questions/526661/intptr-safehandle-and-handleref-explained) – Cody Gray - on strike Dec 02 '10 at 13:14
  • When possible use a SafeHandle so you get critical finalization and are don't need GC.KeepAlive. – CodesInChaos Dec 02 '10 at 13:38
  • @Cody Gray both that question, and the answers at the time I write this, do not really address the question actually being asked here - why has the MS source for the *same* functions changed from one to the other? – AakashM Dec 02 '10 at 20:43
  • @CodesInChaos, SafeHandle serves a different purpose to HandleRef and GC.KeepAlive. SafeHandle is a way to ensure a native handle is (eventually) released without terminating the process, even when really bad stuff happens. HandleRef and GC.KeepAlive are used to tell the GC that the object is still in use outside it's vision. – Brian Reichle Jul 10 '14 at 22:24
  • @BrianReichle When using a SafeHandle in native interop, the marshaller will keep the handle alive until the native function returns, removing the need for GC.KeepAlive in many situations. – CodesInChaos Jul 12 '14 at 06:18

3 Answers3

10

It's a bit fishy. HandleRef is not needed when handle values are stored in a SafeHandle derived object. Which the code pack declares, ZeroInvalidHandle, with several derived ones from it like SafeWindowHandle.

However, it doesn't actually use any of these SafeHandle classes anywhere. Not so sure if it really has to, a lot of the Vista and Win7 extensions are actually COM interfaces. Not the traditional handle based C API. They are kept alive through reference counts and are thus not subject to this kind of garbage collector mishap.

Personally I just never worry about this. Getting a class object collected while the API call is executing is a bug. It can happen just as easily a microsecond after the API call completed. Still a bug, just not one that makes the API call fail. Not so sure I'd actually want it to not fail, I'd much prefer an exception when I got a bug in my code. Microsoft needs to protect itself from this, they don't want to get the blame for the exception. I do.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
5

My guess is that the newer code samples use IntPtr merely because it's simpler to understand.

A quick glance through Reflector at the function signatures in the various NativeMethods classes found in the .NET Framework shows that the actual usage is pretty well split between the two.

I assume this is based on whether or not there is a need to prevent the object from being garbage collected prematurely (which is the primary advantage to using HandleRef). Also keep in mind that using HandleRef is unnecessary unless the handle that you're passing is to a managed object. Unmanaged objects will not get garbage collected.

Community
  • 1
  • 1
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • @Hans: That's true. The distinction I was trying to make involves objects like forms that, while not actually fully managed objects, are eligible for garbage collection and whose handles can potentially be invalidated if they are not referenced again in your code. If you've passed this handle to a p/invoke function in the meantime, this could create a problem. For unmanaged objects that you've created yourself, this isn't a problem because they will not be garbage collected. – Cody Gray - on strike Dec 02 '10 at 16:10
  • 1
    I know, your answer covers that. Just the last sentence is nonsense. – Hans Passant Dec 02 '10 at 16:26
3

IntPtr is just structure that wraps pointer. As for HandleRef MSDN says "Wrapping a handle with HandleRef guarantees that the managed object is not garbage collected until the platform invoke call completes." There is a chance that GC can finalize handle during P/Invoke if you don't do anything with it after P/Invoke call. So HandleRef looks more safe.

DReJ
  • 1,966
  • 15
  • 14
  • I don't really know what you mean by "wraps pointer." The important thing about `IntPtr` is that it's size is platform-specific (32-bits in 32-bit environments, 64-bits in 64-bit environments). It's commonly used to hold pointers or handles, but it doesn't *wrap* them. – Cody Gray - on strike Dec 02 '10 at 13:33
  • IntPtr is a structure, but actual pointer is inside and it depends on environment that's why I said it wraps. Maybe it's incorrect and "holds pointer" sounds better. I agree – DReJ Dec 02 '10 at 14:19