65.9K
CodeProject is changing. Read more.
Home

Pinned Object

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (13 votes)

Feb 11, 2007

CPOL

1 min read

viewsIcon

65433

A helper class for working with structures that need to be pinned to prevent the GC from moving them.

Introduction

This article describes a very short helper class to work with unmanaged memory that must be pinned to prevent the garbage collector from moving it. This is a particular requirement when working with the Win32 API's asynchronous I/O methods, which I found myself doing when implementing a USB device interface.

There is no download; simply copy the code from this article--please do not remove the copyright.

The Code

There really isn't much to this code:

  • It uses generics to internally cast the unmanaged memory to the desired managed type.
  • The class maintains an instance of the managed structure.
  • The constructor pins this structure and initializes a pointer suitable for working with Win32 API methods.
  • The ManagedObject property is used to return a managed object that references the unmanaged memory and to copy the managed object to the unmanaged memory. One caveat is that the managed object must be a structure suitable for use with the Marshal class.
  • The Pointer property is used to return the address of the unmanaged memory.
  • The destructor disposes of the unmanaged memory.
  • The class implements IDisposable, so that you can use this class in a "using" block as well.

Here's the code:

// (c) 2007 Marc Clifton
using System;
using System.Runtime.InteropServices;

namespace Clifton.Tools.Interop
{
  /// <summary>
  /// A helper class for pinning a managed structure so that it is suitable for
  /// unmanaged calls. A pinned object will not be collected and will not be moved
  /// by the GC until explicitly freed.
  /// </summary>
  public class PinnedObject<T> : IDisposable where T : struct
  {
    protected T managedObject;
    protected GCHandle handle;
    protected IntPtr ptr;
    protected bool disposed;

    public T ManangedObject
    {
      get 
      {
        return (T)handle.Target;
      }
      set
      {
        Marshal.StructureToPtr(value, ptr, false);
      }
    }

    public IntPtr Pointer
    {
      get { return ptr; }
    }

    public PinnedObject()
    {
      handle = GCHandle.Alloc(managedObject, GCHandleType.Pinned);
      ptr = handle.AddrOfPinnedObject();
    }

    ~PinnedObject()
    {
      Dispose();
    }

    public void Dispose()
    {
      if (!disposed)
      {
        handle.Free();
        ptr = IntPtr.Zero;
        disposed = true;
      }
    }
  }
}

Example

Using Unsafe Pointers In C#

This example illustrates manipulating a PinnedObject using C++ style pointer syntax within an unsafe code block. The code illustrates:

  • Assigning a new structure to the pinned object (testing the ManagedObject setter)
  • Getting the pointer and manipulating the structure via the pointer (testing the Pointer getter)
  • Getting the structure (testing the ManagedObject getter)
using System;

using Clifton.Tools.Interop;

namespace pintest
{
  public struct TestStruct
  {
    public int a;
  }

  public static class Test
  {
    public static void Main()
    {
      PinnedObject<TestStruct> pin = new PinnedObject<TestStruct>();
      TestStruct ts = new TestStruct();
      ts.a = 1;
      pin.ManangedObject = ts;

      unsafe
      {
        TestStruct* p = (TestStruct*)pin.Pointer;
        ++p->a;
      }

    Console.WriteLine(pin.ManangedObject.a);
    }
  }
}

Conclusion

A simple class but hopefully you will find it useful for the strong type management and functionality that it encapsulates.