Pinned GCHandle Wrapper

The GCHandle type is useful when passing a memory address to an unmanaged function (without using unsafe code). In most cases, you will want to allocate it as GCHandleType.Pinned so that the garbage collector doesn’t move the data in memory while native code is using it. As per the documentation, “This prevents the garbage collector from moving the object and hence undermines the efficiency of the garbage collector. Use the Free method to free the allocated handle as soon as possible.”

It would be nice to use the ‘using’ statement with GCHandle to (a) ensure that Free is always called, and (b) clearly mark the scope of the GCHandle and limit its lifetime. Unfortunately, GCHandle does not implement IDisposable, but it’s straightforward to write a wrapper struct that does:

public struct PinnedGCHandle : IDisposable
{
    public PinnedGCHandle(object obj)
    {
        m_handle = GCHandle.Alloc(obj, GCHandleType.Pinned);
    }

    public void Dispose()
    {
        if (m_handle.IsAllocated)
            m_handle.Free();
    }

    public IntPtr Pointer
    {
        get { return m_handle.AddrOfPinnedObject(); }
    }

    public static implicit operator IntPtr(PinnedGCHandle handle)
    {
        return handle.Pointer;
    }

    readonly GCHandle m_handle;
}

As well as a Pointer property, this type supports implicit conversion to IntPtr so that it can be easily passed to a native method typed as taking an IntPtr:

byte[] bytes = new byte[100];
using (PinnedGCHandle hBytes = new PinnedGCHandle(bytes))
    NativeMethods.SomeNativeMethod(hBytes, bytes.Length);

Full source code for this post is in PinnedGCHandle.cs.

Posted by Bradley Grainger on May 13, 2010