Passing Array into Unmanaged Code for Modification I have an array allocated in C# which I am passing into unmanaged code to be modified. The following code works, but I am not sure if there are any other more 'correct' or 'efficient' methods that I am not aware of.

Code.c

extern "C" {
    class MyObject
    {
    public:
        int32_t X;
    };

    __declspec(dllexport) void ArrayTest(MyObject* a, int length);

    void ArrayTest(MyObject* a, int length)
    {
        for (int i = 0; i &lt; length; i++)
        {
            a[i].X = i + 1;
        }
    }
}


Code.cs

class Program
{
    [StructLayout(LayoutKind.Sequential)]
    public struct MyObject
    {
        public Int32 X;
    }

    [DllImport(@"MyDll.dll", CallingConvention = CallingConvention.Cdecl)]
    public extern static void ArrayTest(IntPtr objects, int length);

    static void Main(string[] args)
    {
        var objects = new MyObject[3];

        var handle = GCHandle.Alloc(objects, GCHandleType.Pinned);
        var ptr = GCHandle.ToIntPtr(handle);

        ArrayTest(ptr, objects.Length);

        for (int i = 0; i &lt; objects.Length; i++)
        {
            var offset = Marshal.SizeOf&lt;MyObject&gt;() * i;

            objects[i] = Marshal.PtrToStructure&lt;MyObject&gt;(IntPtr.Add(ptr, offset));
        }
    }
}
You must definitely call handle.Free() when finished using it so GC can do the cleaning.



Note that GCHandle.Alloc(objects, GCHandleType.Pinned); only works for structs with pure primitive or to be more precise: blittable types. String fields etc. must be handled differently.



A little optimization:

You repeatedly calculate this 


  var offset = Marshal.SizeOf&lt;MyObject&gt;() * i;


Instead you can calculate offset once:

var offset = Marshal.Sizeof&lt;MyObject&gt;();


and in the loop do:

ptr = IntPtr.Add(ptr, offset);




If you are willing/allowed to run in unsafe mode you can do:

unsafe public void RunUnsafe()
{
  var objects = new MyObject[3];

  var handle = GCHandle.Alloc(objects, GCHandleType.Pinned);
  var ptr = GCHandle.ToIntPtr(handle);

  ArrayTest(ptr, objects.Length);
  MyObject* pobj = (MyObject*)ptr;

  for (int i = 0; i &lt; objects.Length; i++, pobj++)
  {
    Console.WriteLine((*pobj).X);
  }

  handle.Free();
}




If you are entitled to modify the signature of ArrayTest, you can changed it to:

    public extern static void ArrayTest([In, Out] MyObject[] objects, int length);


The [In, Out] attributes determines that the array should be marshaled both ways so that ArrayTest can work on the provided instances in the array [In], and changes made in ArrayTest are reflected in the objects when the function returns [Out].

Then your method can be simplified to:

  var objects = new MyObject[3];

  ArrayTest(objects, objects.Length);

  foreach (var obj in objects)
  {
    Console.WriteLine(obj.X);
  }