6

I try parse a byte array to struct but it doesnt work with Sequential. The values are wrong in the Sequential struct but it work correct with Explicit struct? I need sequential the byte array have no fix length. The DwLength field is the size of Data field.

Values

  • MessageType 128 (Sequential 128)
  • DwLength 20 (Sequential 33554432)
  • Slot 0 (Sequential 0)
  • Seq 0 (Sequential 0)
  • Status 2 (Sequential 59)
  • Error 0 (Sequential 143)
  • ChainParameter 0 (Sequential 128)

Test Code

var bytes = new byte[] { 0x80, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x3B, 0x8F, 0x80, 0x01, 0x80, 0x4F, 0x0C, 0xA0, 0x00, 0x00, 0x03, 0x06, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x68 };

var result1 = GetStruct<RdrToPcDataBlock1>(bytes);
var result2 = GetStruct<RdrToPcDataBlock2>(bytes);

struct RdrToPcDataBlock Sequential

[StructLayout(LayoutKind.Sequential)]
public struct RdrToPcDataBlock1
{
    public byte MessageType;
    public int DwLength;
    public byte Slot;
    public byte Seq;
    public byte Status;
    public byte Error;
    public byte ChainParameter;
    [MarshalAs(UnmanagedType.ByValArray)]
    public byte[] Data;
}

struct RdrToPcDataBlock Explicit

[StructLayout(LayoutKind.Explicit)]
public struct RdrToPcDataBlock2
{
    [FieldOffset(0)]
    public byte MessageType;
    [FieldOffset(1)]
    public int DwLength;
    [FieldOffset(5)]
    public byte Slot;
    [FieldOffset(6)]
    public byte Seq;
    [FieldOffset(7)]
    public byte Status;
    [FieldOffset(8)]
    public byte Error;
    [FieldOffset(9)]
    public byte ChainParameter;
    [FieldOffset(10)]
    public byte Data;
}

GetStruct

public T GetStruct<T>(byte[] bytes)
{
    try
    {
        var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
        var item = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
        handle.Free();
        return item;
    }
    catch
    {
        return default(T);
    }
}
Michael Roland
  • 39,663
  • 10
  • 99
  • 206
live2
  • 3,771
  • 2
  • 37
  • 46
  • _"The values are wrong"_ -- please be more specific. _"Wrong"_, in what way? What result do you get? What result do you expect instead? Please provide a good [mcve] that reliably reproduces the problem, and explain the problem more precisely. Note also that `LayoutKind.Sequential` is subject to packing rules, so non-aligned fields may not wind up where you expect. (I don't have time to look it up now, but I'm not convinced that even if you can get `LayoutKind.Sequential` to work, you'll get the result you want, i.e. an array object at the end filled with the excess data.) – Peter Duniho Mar 08 '17 at 22:34
  • You will have to use a custom marshaller. Otherwise you can't deal with variable length arrays. Here's an example: http://stackoverflow.com/a/38884095/103959 – Jean-Bernard Pellerin Mar 08 '17 at 22:46

1 Answers1

7

When you do [StructLayout(LayoutKind.Sequential)] that is the same as doing [StructLayout(LayoutKind.Sequential, Pack=0)] which will use the default packing for the bitness of the process (4 for 32 bit and 8 for 64 bit). To get the behavior your want you need to explicitly say you don't want any padding by setting [StructLayout(LayoutKind.Sequential, Pack=1)]

UPDATE: You still are going to run in to problems with your variable length byte array. See the comment by Jean-Bernard Pellerin

You will have to use a custom marshaller. Otherwise you can't deal with variable length arrays. Here's an example: https://stackoverflow.com/a/38884095/103959

Community
  • 1
  • 1
Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431