2

I've read several topics about but I still can't understand the real limitation of not being able to convert this structure to byte array easily:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct B {
  public int b_a;
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct A {
  public int sizeB;

  [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]
  public B[] b;
}

I'm writing a TCP communication program so I want to build my S2C packets in a struct and then send them as byte[] so I'm looking for the cheapest and fastest way to achieve this.

I have already tried Marsheling in many ways but there is always some exception in Marshal.SizeOf().

In this example I get the following error: "[...] cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed."

Struct initialization eg.:

A a = new A();
B[] b = new B[5];

a.sizeB = 5;
a.b = b;

Marshal.SizeOf(a);
2
  • I assume you are trying to call Marshall.SizeOf(a) which is never going to work unless your array is a fixed length. Commented Mar 11, 2019 at 1:00
  • @Jerry Yes it isn't and it can't be fixed length Commented Mar 11, 2019 at 1:40

1 Answer 1

2

You don't have the same control for low level memory access like you would C or C++. You will need to do some manual work when you have an array of undefined length in C#.

Here are a couple ways of accomplishing that.

struct B
{
    public int b_a;
}

struct A
{
    public int sizeB;

    public B[] b;
}

The first being a BinaryWriter. This can be faster if your structure does not have a lot of fields.

static byte[] ConvertToByte(A a)
{
    using (var ms = new MemoryStream())
    using (var writer = new BinaryWriter(ms))
    {
        writer.Write(a.sizeB);

        foreach (var b in a.b)
            writer.Write(b.b_a);

        return ms.ToArray();
    }
}

The other to use marshalling like you were but explicitly looping through the array.

static byte[] ConvertToByte(A a)
{
    var bStructSize = Marshal.SizeOf<B>();
    var size = bStructSize * a.b.Length;

    var arr = new byte[size + 4];

    var ptr = Marshal.AllocHGlobal(size);

    for (int i = 0; i < a.b.Length; i++)
        Marshal.StructureToPtr(a.b[i], ptr + i * bStructSize, true);

    Marshal.Copy(ptr, arr, 4, size);

    Array.Copy(BitConverter.GetBytes(a.sizeB), arr, 4);

    return arr;
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.