How to pin a pointer to managed object in C#?
Asked Answered
P

2

11

Unmanaged code calls my functions. In first function I should pass back pointer to my managed object. Sometimes later some of my other functions get called with that same pointer as one of parameters . I should dereference it and use it to perform some calculations and then if it is not needed dispose of it. To cut the story short I need to pin that object so that GC won't move it til I dispose of it. How to do that in C# ? Thanks in advance.

Parsimonious answered 31/7, 2011 at 12:57 Comment(2)
Post some code, preferably a minimal, complete example.Woodpecker
Don't pin. The unmanaged code has no use for the pointer. So don't pass a pointer, pass a 'handle'. Say, an index in a static List<>. Now you can simply retrieve the managed reference in the callback from the handle value.Aphid
B
10

To pin an object in C#, you can use GCHandle.Alloc method with second parameter GCHandleType.Pinned. Object remains pinned until GCHandle instance is released using GCHandle.Free method.

Blanc answered 31/7, 2011 at 13:16 Comment(2)
It works like a charm when you use GCHandle.Aloc(object value) and cast it to IntPtr.Parsimonious
@apaka: GCHandle.Alloc(object_value, GCHandleType.Pinned) + GCHandle.AddrOfPinnedObject.Blanc
A
2

(Circa 2022, Dotnet 6)

The other answer doesn't work for managed objects. At runtime it will fail. Here is code that will do as requested.

public static class Pin
{

    /// <summary>
    /// use to obtain raw access to a managed object.  allowing pinning.
    /// <para>
    /// Usage:<code>fixed (byte* data = [AND_OPERATOR]GetRawObjectData(managed)){  }</code>
    /// </para>
    /// </summary>
    public static ref byte GetRawObjectData(object o)
    {
        //usage:  fixed (byte* data = &GetRawObjectData(managed)) { }
        return ref new PinnableUnion(o).Pinnable.Data;
    }

    [StructLayout(LayoutKind.Sequential)]
    sealed class Pinnable
    {
        public byte Data;
    }

    [StructLayout(LayoutKind.Explicit)]
    struct PinnableUnion
    {
        [FieldOffset(0)]
        public object Object;

        [FieldOffset(0)]
        public Pinnable Pinnable;

        public PinnableUnion(object o)
        {
            System.Runtime.CompilerServices.Unsafe.SkipInit(out this);
            Object = o;
        }
    }
}
Archicarp answered 30/1, 2022 at 18:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.