Click here to Skip to main content
Licence CPOL
First Posted 11 Feb 2007
Views 25,505
Bookmarked 20 times

Pinned Object

By Marc Clifton | 11 Feb 2007
A helper class for working with structures that need to be pinned to prevent the GC from moving them.

1
2 votes, 14.3%
2

3
2 votes, 14.3%
4
10 votes, 71.4%
5
4.80/5 - 14 votes
2 removed
μ 4.50, σa 1.91 [?]

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Marc Clifton

Architect
Interacx
United States United States

Member
Marc is the creator of two open source projets, MyXaml, a declarative (XML) instantiation engine and the Advanced Unit Testing framework, and Interacx, a commercial n-tier RAD application suite.  Visit his website, www.marcclifton.com, where you will find many of his articles and his blog.
 
Marc lives in Philmont, NY with his son Ian.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralPinning copy of the structure PinmemberLesheniuk6:04 2 Mar '07  
GeneralRe: Pinning copy of the structure PinsupporterMarc Clifton6:18 2 Mar '07  
Questionfixed statement Pinmemberrvpilot11:48 13 Feb '07  
AnswerRe: fixed statement PinsupporterMarc Clifton12:06 13 Feb '07  
rvpilot wrote:
How does your helper compare to the 'fixed (...) { ... }' statement and in what situation would you use one instead of the other ?

 
That's a good question and I should have addressed it in the article. The "fixed" statement is useful when you are pinning something for the lifetime of the code within the "fixed" block. My pinned object is useful especially in a threaded scenario when you read or write some data asynchronously and later come back and work with the data or write out more data.
 
So, basically, anytime you need an object pinned beyond the lifetime of a "fixed" block, would be when to use a different mechanism, such as the PinnedObject to pin the object.
 
Marc
 

Thyme In The Country

People are just notoriously impossible. --DavidCrow
There's NO excuse for not commenting your code. -- John Simmons / outlaw programmer
People who say that they will refactor their code later to make it "good" don't understand refactoring, nor the art and craft of programming. -- Josh Smith


GeneralRe: fixed statement Pinmemberrvpilot12:14 13 Feb '07  
GeneralTesting PinmemberLuc Pattyn13:07 12 Feb '07  
GeneralRe: Testing PinsupporterMarc Clifton14:28 12 Feb '07  
GeneralMy .NET 1.1 approach, without generics PinmemberLuc Pattyn12:27 12 Feb '07  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web04 | 2.5.120210.1 | Last Updated 11 Feb 2007
Article Copyright 2007 by Marc Clifton
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid