Marshalling C Struct with array of structures in i

2019-02-27 17:18发布

问题:

I referred the similar questions in this forum but didn't get the solution for my problem.

I have been struggling with marshaling problem for a while. I have a structure that contains an array of another structure, The platform is Win CE. I am using Visual Studio 2008 and .NET CF 3.5.

The code:

C Structures:

 struct dot11Rate
 {
    unsigned int rate;
    unsigned char mode; 
 };

 typedef struct my_supported_rates
 {
    unsigned short n_rates;
    struct dot11Rate srates[36];
    unsigned char  isSet;
    unsigned char no_of_HTStreams;
 }MY_SUPPORTED_DATA_RATES;

Size of the struct MY_SUPPORTED_DATA_RATES is 296 bytes in C

This is my attempt to convert it into a C# struct:

C# Converted:

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct dot11Rate
    {
        public uint rate;
        public byte mode; /* HT=1, non-HT=0*////
    };

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    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;
    };

Here I am getting the size as 304 bytes using Marshal.SizeOf(my_supported_rates);

I have tried the following things without any success:

  • Adding and removing various attrubute elements in MarshalAs attribute in my_supported_rates struct such as ArraySubType = UnmanagedType.Struct
  • I have Intptr with required data and I tried to convert ptr to the struct using the code my_supported_rates = (my_supported_rates) Marshal.PtrToStructure(ptr,my_supported_rates.GetType());. But proper conversion is not happend.
  • Some other suggestions on blogs and StackOverflow which didn't prove useful to me

回答1:

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.