Search code examples
c#c++arrayspinvokemarshalling

Marshal an array of structs in pInvoke


I have a struct like this in C#:

[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct MyStruct
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]
    public string StringValue;
    public uint IUintValue;
}

And a corresponding struct in native code

struct MyStruct
{
    char StringValue[17];
    ulong UintValue;
}

My goal is to pass an array of this structs from c# side to c++(native side) using pinvoke. Here is how I use it in c#

[DllImport(@"MyLibrary.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern int SendArray([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]ref MyStruct[] arr, int recordsCount);

and a calling code is:

var array = new MyStruct[10];
//initialize
SendArray(ref array, array.Length);

On native side I have the following function signature:

extern "C" __declspec(dllexport) int SendArray(MyStruct** Arr, int recordsCount);

And it appears o work only for the first element in array. On c++ side I get this array, but only first element is correctly marshaled. The rest of them appears to be trash.

Where is my mistake?


Solution

  • Your C++ code does not receive an array of structs. It receives an array of pointers to struct. Change the C++ code to be like so:

    int SendArray(MyStruct* Arr, int recordsCount);
    

    or perhaps

    int SendArray(MyStruct Arr[], int recordsCount);
    

    And then your p/invoke should be

    [DllImport(...)]
    public static extern int SendArray([In] MyStruct[] arr, int recordsCount);
    

    I am also suspicious of Pack=8. Are you quite sure?