-1

I have the flollowing structure:

[StructLayout(LayoutKind.Sequential)]
public struct mystructure
{
    public Byte fieldA;
    public Byte fieldB;
    public UInt16 fieldC;
    public UInt32 fieldD;
}

Then, filling with data:

var obj = new mystructure()
{
    fieldA = 4
    ,
    fieldB = 0
    ,
    fieldC = 16
    ,
    fieldD = 9
};

And marshaling:

Int32 objsize = Marshal.SizeOf(typeof(mystructure));
Byte[] ret = new Byte[objsize];
IntPtr buff = Marshal.AllocHGlobal(objsize);
Marshal.StructureToPtr(obj, buff, true);
Marshal.Copy(buff, ret, 0, objsize);
Marshal.FreeHGlobal(buff);

I got this data layout in my ret variable:

[0]: 4
[1]: 0
[2]: 16
[3]: 0
[4]: 9
[5]: 0
[6]: 0
[7]: 0

All data are aligned at the beginning of your space, how do I align on the end? Note that it is different from using the [FieldOffset] atribute. I need the following result:

[0]: 4
[1]: 0
[2]: 0
[3]: 16
[4]: 0
[5]: 0
[6]: 0
[7]: 9

UPDATED - My solution

public static void LittleEndianToBigEndian<T>(Byte[] data, Int32 startOffset = 0) where T : struct
{
    LittleEndianToBigEndian(typeof(T), data, startOffset);
}

public static void LittleEndianToBigEndian(Type structType, Byte[] data, Int32 startOffset = 0)
{
    if (!structType.IsValueType || structType.IsEnum || structType.IsPrimitive)
        throw new ArgumentException("The conversion only supports struct types", "structType");

    var validFieldsRule = new Func<FieldInfo, Boolean>(f =>
        !f.IsStatic &&
        f.FieldType != typeof(String) &&
        f.FieldType != typeof(Byte) &&
        f.FieldType != typeof(SByte) &&
        (f.FieldType.IsArray || f.FieldType.IsValueType)
    );

    foreach (var field in structType.GetFields().Where(validFieldsRule))
    {
        var offset = Marshal.OffsetOf(structType, field.Name).ToInt32();
        var effectiveOffset = startOffset + offset;

        if (field.FieldType.GetFields().Any(validFieldsRule) && !field.FieldType.IsEnum)
        {
            LittleEndianToBigEndian(field.FieldType, data, effectiveOffset);
        }
        else if (field.FieldType.IsArray)
        {
            //to-do: deal with arrays!
        }
        else
        {
            Array.Reverse
                (
                    data
                    ,
                    effectiveOffset
                    ,
                    Marshal.SizeOf
                        (
                            field.FieldType.IsEnum ?
                                Enum.GetUnderlyingType(field.FieldType)
                                    :
                                field.FieldType
                        )
                );
        }
    }
}
  • 1
    What do you mean by "align on the end". Do you want big-endian (16,0) for UInt16? – Richard Schneider Jan 23 '15 at 01:03
  • https://stackoverflow.com/questions/2623761/marshal-ptrtostructure-and-back-again-and-generic-solution-for-endianness-swap/2624377#2624377 has a very general solution for your problem. – dbc Jan 23 '15 at 01:21

1 Answers1

2

Your question is about byte order not alignment. Byte order or endianness is about the weither or not he most-significant byte is first or last.

Marshal.StructurePtr uses the byte order of the underlaying CPU because it assumes you want to call an unmanaged function.

This may help you Marshalling a big-endian byte collection into a struct in order to pull out values

Basically you will have to create the byte array by hand. big endian is also known as network byte order. You can use ipaddress.hosttonetworkorder to get the correct format for ints and longs.

Community
  • 1
  • 1
Richard Schneider
  • 34,944
  • 9
  • 57
  • 73