C# marshaling of a struct with an array

arrays, c#, marshalling, runtime, struct

Solution

The `StructureToPtr` does only work with structures which contains value types only (int, char, float, other structs). `float[]` is a reference type and so you really get a kind of pointer (you can't really use it because it is a managed pointer). If you want to copy your array to a pinned memory you have to use one of the `Marshal.Copy` functions directly on your `s.a` float array.

Something like that. (I didn't really test it)

byte[] buffer = new byte[sizeof(float) * s.a.Length];
GCHandle gcHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);

and then

Marshal.Copy(s.a, 0, gcHandle.AddrOfPinnedObject(), s.a.Length);

Update

I have to correct myself. You can get also get what you want by declaring your struct in this way:

 [StructLayout(LayoutKind.Sequential)]
 public struct MyStruct
 {
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
     public float[] a;
 }

As you see you have to fix the size of the float array at design time.

Problem

Let's say that I have a struct similar to ``` public struct MyStruct { public float[] a; } ``` and that I want to instantiate one such struct with some custom array size (let's say 2 for this example). Then I marshal it into a byte array. ``` MyStruct s = new MyStruct(); s.a = new float[2]; s.a[0] = 1.0f; s.a[1] = 2.0f; byte[] buffer = new byte[Marshal.SizeOf(typeof(MyStruct))]; GCHandle gcHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned); try { Marshal.StructureToPtr(s, gcHandle.AddrOfPinnedObject(), false); for (int i = 0; i < buffer.Length; i++) { System.Console.WriteLine(buffer[i].ToString("x2")); } } finally { gcHandle.Free(); } ``` This gives me only 4 bytes in my byte[] and they look like a pointer value rather than the value of either 1.0f or 2.0f. I've searched around for ways to make this work, but all I've been able to find so far are similar examples where the struct array size is known ahead of time. Isn't there a way to do this?

Original source