3

I have this struct definition:

public struct ChangedByte
{
    public byte R;
    public byte G;
    public byte B;
    public int x;
    public int y;
}

I have created a:

List<ChangedByte> testme = new List<ChangedByte>();

(and added items to it)

I convert this to an Array:

ChangedByte[] alpha = testme.ToArray();

I have this function I found with a similar question on SO:

byte[] StructureToByteArray(object obj)
{
    int len = Marshal.SizeOf(obj);
    byte[] arr = new byte[len];
    IntPtr ptr = Marshal.AllocHGlobal(len);
    Marshal.StructureToPtr(obj, ptr, true);
    Marshal.Copy(ptr, arr, 0, len);
    Marshal.FreeHGlobal(ptr);
    return arr;
}

I call it like this:

byte[] test = StructureToByteArray(alpha);

I get the error:

Type 'new_encoder.Form1+ChangedByte[]' cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed.

I would like to convert a list of objects into a byte array (and possibly avoid serialization as it tends to bulk up the size of the array)

Can it be done?

ADDITIONAL:

I have tried amending the Struct to this:

public struct ChangedByte
{
    [MarshalAs(UnmanagedType.LPWStr)]
    public byte R;
    [MarshalAs(UnmanagedType.LPWStr)]
    public byte G;
    [MarshalAs(UnmanagedType.LPWStr)]
    public byte B;
    [MarshalAs(UnmanagedType.LPWStr)]
    public int x;
    [MarshalAs(UnmanagedType.LPWStr)]
    public int y;
}

but still the same error.

3
  • 1
    So, haven't tested it myself, but you might take a look at MarshalAs-Attribute. Here's a very similar question: social.msdn.microsoft.com/Forums/vstudio/en-US/… hope it helps Commented Jan 31, 2015 at 14:26
  • @Dominik hi, thanks for posting. I gave it a go but same error. It is possible I have not understood the info.. Thanks for the link :) Commented Jan 31, 2015 at 14:37
  • LPWStr is for strings, it doesn't make sense to apply it to int or byte fields Commented Jan 31, 2015 at 17:38

2 Answers 2

2

In this case since you aren't only converting a struct, but an array of structs, you will need to loop through your array and convert each item. Use pointer arithmetic to move through your buffer and add the items.

public static byte[] StructureArrayToByteArray(ChangedByte[] objs)
{
    int structSize = Marshal.SizeOf(typeof(ChangedByte));
    int len = objs.Length * structSize;
    byte[] arr = new byte[len];
    IntPtr ptr = Marshal.AllocHGlobal(len);
    for (int i = 0; i < objs.Length; i++ ) {
        Marshal.StructureToPtr(objs[i], ptr + i*structSize, true);
    }
    Marshal.Copy(ptr, arr, 0, len);
    Marshal.FreeHGlobal(ptr);
    return arr;
}
Sign up to request clarification or add additional context in comments.

4 Comments

Hi, your answer made sense and I implemented it but I got the same error on this line: int structSize = Marshal.SizeOf(typeof(ChangedByte));
Is the error slightly different, e.g. what Type does it say it is this time that is causing the trouble?
Oh yes I see that error now when I add [MarshalAs(UnmanagedType.LPWStr)] to the struct. Without those attributes, I did not get that compile error. Does it work for you without those attributes or is it not marshalling correctly in that case?
Hi, thanks for your continued interest. This is message: Type 'new_encoder.Form1+ChangedByte' cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed.
2

You can use the following methods:

static byte[] ArrayToBytes<T>(T[] array) where T : struct
{
    IntPtr ptr = IntPtr.Zero;
    try
    {
        int len = Marshal.SizeOf(typeof(T));
        int totalLen = array.Length * len;
        ptr = Marshal.AllocHGlobal(len);
        for (int i = 0; i < array.Length; i++)
        {
            Marshal.StructureToPtr(array[i], ptr + i * len, false);
        }
        var bytes = new byte[totalLen];
        Marshal.Copy(ptr, bytes, 0, totalLen);
        return bytes;
    }
    finally
    {
        if (ptr != IntPtr.Zero)
            Marshal.FreeHGlobal(ptr);
    }
}

static T[] ArrayFromBytes<T>(byte[] bytes) where T : struct
{
    IntPtr ptr = IntPtr.Zero;
    try
    {
        int len = Marshal.SizeOf(typeof(T));
        int count = bytes.Length / len;
        ptr = Marshal.AllocHGlobal(bytes.Length);
        Marshal.Copy(bytes, 0, ptr, bytes.Length);
        T[] array = new T[count];
        for (int i = 0; i < count; i++)
        {
            array[i] = Marshal.PtrToStructure<T>(ptr + i * len);
        }
        return array;
    }
    finally
    {
        if (ptr != IntPtr.Zero)
            Marshal.FreeHGlobal(ptr);
    }
}

And use them like this:

byte[] test = ArrayToBytes(alpha); // serialize
ChangedByte[] alpha2 = ArrayFromBytes<ChangedByte>(test); // deserialize

5 Comments

Hi, thanks for your answer. I implemented it and got the same error on this line: int len = Marshal.SizeOf(typeof(T));
Hi, I get a different error when I remove this attributes on the fields in the Struct, I get an access violation..
@AndrewSimpson, I tried it with your ChangedByte struct, and it worked fine for me... Try adding the [StructLayout(LayoutKind.Sequential)] attribute to the struct
Hi - thanks. I knew I was missing something. Thanks :)
@Thomas, Good job. I've modified ArrayFromBytes method such as From 'array[i] = Marshal.PtrToStructure<T>(ptr + i * len);' To 'array[i] = (T)Marshal.PtrToStructure(ptr + i * len, typeof(T));'

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.