Marshal C++ Struct Array into C#

Marshal C++ struct array into C#

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.

C# marshaling of a struct with an array

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.

Marshalling C Struct with array of structures in it

Your translations look good to me. Running on desktop rather than CE I find that, for these types

[StructLayout(LayoutKind.Sequential)]
public struct dot11Rate
{
public uint rate;
public byte mode;
};

[StructLayout(LayoutKind.Sequential)]
public struct my_supported_rates
{
public ushort n_rates;
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 36)]
public dot11Rate[] srates;
public byte isSet;
public byte no_of_HTStreams;
};

that

Marshal.SizeOf(typeof(my_supported_rates)) == 296

So it would seem to be something odd in the CE pinvoke marshaller. You might need to force the hand of the marshaller by doing this:

[StructLayout(LayoutKind.Explicit, Size=296)]
public struct my_supported_rates
{
[FieldOffset(0)]
public ushort n_rates;
[FieldOffset(4)]
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 36)]
public dot11Rate[] srates;
[FieldOffset(292)]
public byte isSet;
[FieldOffset(293)]
public byte no_of_HTStreams;
};

That is, if LayoutKind.Explicit and FieldOffset are supported on CE.

If they are not supported then you'll need to marshal by hand. You are looking for Marshal.AllocHGlobal and then Marshal.ReadByte, Marshal.ReadInt16 and so on.

Marshaling Struct Array with Strings Between c# and c++. Strings are empty

Turns out the problem was on the C++ side and all the marshaling stuff was correct. Thanks for the tip Hans.

Marshalling struct with embedded struct array to unmanaged code

It is possible. Just declare explicit struct type for your error items:

[StructLayout(LayoutKind.Sequential)]
struct ErrorDescriptor
{
Byte etype;
Uint32 edata;
}

[StructLayout(LayoutKind.Sequential)]
struct EIBUF
{
Uint16 buftype;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 33)]
ErrorDescriptor[] error;
}


Related Topics



Leave a reply



Submit