tags:

views:

571

answers:

1

I am trying to deserialize a structure, and I'm getting an AV exception in PtrToStructure. The only wrinkle is that this is a variable length structure, so I need to adjust the length before deserializing. Here's my code, is there anything obviously wrong? The structure contains only integer/short/byte arrays, nothing fancy.

the incoming data is 374 bytes, and I need to adjust it to match the 576 bytes data structure. Basically the incoming packet has a shorter last field than the max possible, which is normal.

public static ... FromByteArray(byte[] receivedData)
    {
        int rawsize = Marshal.SizeOf(typeof(MyPacket));
    // allocate a new buffer of the maximum size, to help deserialization
    byte[] newBuffer = new byte[rawsize]; 
    Array.Copy(receivedData, newBuffer, receivedData.Length);

    IntPtr buffer = Marshal.AllocHGlobal(rawsize);
    Marshal.Copy(newBuffer, 0, buffer, rawsize);

/// CRASHES ON NEXT LINE
    MyPacketDefinition def = (MyPacketDefinition ) Marshal.PtrToStructure(buffer, typeof(MyPacketDefinition ));   
    Marshal.FreeHGlobal(buffer);

    //...
}

My structure looks something like this:

 [StructLayout (LayoutKind.Explicit, Pack=1, Size=576, CharSet=CharSet.Ansi)]
 public struct MyPacket
    {

    [FieldOffset(0)]
    public System.Byte Type;

    .
    . // a few more INT/SHORT fields
    .

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
        [FieldOffset(28)]  public System.Byte[] Address;


        [MarshalAs(UnmanagedType.LPStr, SizeConst=64)]
        [FieldOffset(44)] public System.String Name;


        [MarshalAs(UnmanagedType.LPStr, SizeConst = 128)]
        [FieldOffset(108)] public System.String SystemData;


        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 340)]
        [FieldOffset(236)] public System.Byte[] Options;

}

With the last parameter (Option) being a variable length field of maximum 340 bytes (normally shorter)

A: 

I was able to get it to work using this method, as suggested by Franci in the comments (although I'm not sure if this is what he meant).

I do not know why the other way was raising an AV, I've used that method before with no issues.

    byte[] mem = new byte[sizeof(typeof(MyPacketDefinition))];
    Array.Copy(mem, receivedData, receivedData.Length);
    using (MemoryStream ms = new MemoryStream(mem))
    {
        using (BinaryReader br = new BinaryReader(ms))
        {
            byte[] buff = br.ReadBytes(Marshal.SizeOf(typeof(MyPacketDefinition )));

            GCHandle handle = GCHandle.Alloc(buff, GCHandleType.Pinned);
            try
            {
                MyPacketDefinition s = (MyPacketDefinition )Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(MyPacketDefinition ));
            }
            finally
            {
                handle.Free();
            }

        }
   }
Will I Am
That code doesn't make sense. You're using the sizeof operator on a Type which isn't allowed (I guess you meant Marshal.SizeOf instead). And you've reversed the arguments to Array.Copy so you're basically zeroing out receivedData. Even if you fix that the content of buff will always be identical to that of mem. I believe the problem with your original code was incorrectly using LPStr where it should have been ByValTStr.
Mattias S