Pinned Object






4.67/5 (13 votes)
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.