2

i have a struct define as:

[StructLayout(LayoutKind.Sequential,CharSet = CharSet.Ansi,Pack = 1)]
internal struct Message
{
    [MarshalAs(UnmanagedType.U1, SizeConst = 1)]
    public byte age;
    [MarshalAs(UnmanagedType.U2, SizeConst = 2)]
    public ushort length;
    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1,SizeConst = 502)]
    public byte[] data;
}

payload received via udp,when received byte[],need to be converted to struct. data length specified as 502,but actually it should be the length member value indicating the data length,if remove the SizeConst attr, the code will throw Marshal exception at Marshal.SizeOf(typeof(T)).

public static T ToStruct<T>(this byte[] buf)
{
    var lth = Marshal.SizeOf(typeof(T));
    if (lth > buf.Length) return default(T);
    var ptr = Marshal.AllocHGlobal(lth);
    Marshal.Copy(buf, 0, ptr, lth);
    var structure = Marshal.PtrToStructure(ptr, typeof(T));
    Marshal.FreeHGlobal(ptr);
    return (T)structure;
}

exception info:

System.ArgumentException: Type 'Itms.Agent.IotBox.TieTa.Entity.Message' cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed.

i know this is very simple to handle in c/c++, but C# doesn't have a similar approach. any help?

7
  • Are you sure you don't have another Message class? Is T really the class defined above? Because it seems to be working fine. Commented Dec 18, 2018 at 12:53
  • I'm wondering if this kind of functionality should be programmed using generics; I would at least expect a type specific override. Personally I think the length should not be part of the structure; it is required at the data level, but at a logic level you just have the array, which already has a size. Commented Dec 18, 2018 at 12:54
  • 1
    @MaartenBodewes: I don't think this is so uncommon if you need to do a lot of struct marshaling. What would be the difference between type specific methods? But a better question is if OP actually needs to use struct marshaling at all, which I doubt. Commented Dec 18, 2018 at 12:57
  • 1
    Yeah, just parsing the binary would be better; error handling and such. UDP packets should fit memory fine. Commented Dec 18, 2018 at 13:04
  • 1
    I agree.. I highly doubt there's a need to marshal like this. I can't think of any... By the time you do the allocations manually here you could have just parsed it manually to a normal struct. That said.. I guess I don't see any problem with marshalling either so I hope the question gets a proper answer. Commented Dec 18, 2018 at 13:19

1 Answer 1

1

when received byte[],need to be converted to struct. data length specified as 502,but actually it should be the length member value indicating the data length

that's too complex for simple marshal operations. You'll probably have to serialize/deserialize manually, i.e. something like:

byte[] payload = ...
var age = payload[0];
var len = (payload[1] << 8) | payload[2]; // invert depending on endianness
byte[] data = len == 0 ? Array.Empty<byte>() : new byte[len];
Buffer.BlockCopy(payload, 3, data, len);
var msg = new Message(age, len, data);

This would mean you could remove all the attributes, as you're not using any marshalling features. Also... the length field seems kinda redundant, since it is simply duplicating the array's length.

Sign up to request clarification or add additional context in comments.

1 Comment

thank you reply.yes, I can only do this for now.this problem has troubled me for a long time,as for why need length field,because this is actually a network protocol. i hope that C# can do this task in the same way as c/c++. for parsing by offset, it is easy to make mistakes and not easy to expand.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.