Marshal C++ struct array into C#


Question

I have the following struct in C++:

#define MAXCHARS 15

typedef struct 
{
    char data[MAXCHARS];
    int prob[MAXCHARS];
} LPRData;

And a function that I'm p/invoking into to get an array of 3 of these structures:

void GetData(LPRData *data);

In C++ I would just do something like this:

LPRData *Results;
Results = (LPRData *)malloc(MAXRESULTS*sizeof(LPRData));
GetData( Results );

And it would work just fine, but in C# I can't seem to get it to work. I've created a C# struct like this:

public struct LPRData
{

    /// char[15]
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)]
    public string data;

    /// int[15]
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)]
    public int[] prob;
}

And if I initialize an array of 3 of those (and all their sub-arrays) and pass it into this:

GetData(LPRData[] data);

It returns with success, but the data in the LPRData array has not changed.

I've even tried to create a raw byte array the size of 3 LPRData's and pass that into a function prototype like this:

GetData(byte[] data);

But in that case I will get the "data" string from the very first LPRData structure, but nothing after it, including the "prob" array from the same LPRData.

Any ideas of how to properly handle this?

1
28
10/9/2008 5:27:02 PM

Accepted Answer

I would try adding some attributes to your struct decloration

[StructLayout(LayoutKind.Sequential, Size=TotalBytesInStruct),Serializable]
public struct LPRData
{
/// char[15]
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)]
public string data;

/// int[15]
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)]
public int[] prob;
}

*Note TotalBytesInStruct is not intended to represent a variable

JaredPar is also correct that using the IntPtr class could be helpful, but it has been quite awhile since I have used PInvoke so I'm rusty.

25
10/9/2008 5:54:03 PM

One trick when dealing with pointers is to just use an IntPtr. You can then use Marshal.PtrToStructure on the pointer and increment based on the size of the structure to get your results.

static extern void GetData([Out] out IntPtr ptr);

LPRData[] GetData()
{
    IntPtr value;
    LPRData[] array = new LPRData[3];
    GetData(out value);
    for (int i = 0; i < array.Length; i++)
    {
        array[i] = Marshal.PtrToStructure(value, typeof(LPRData));
        value += Marshal.SizeOf(typeof(LPRData));
    }
    return array;
}

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon