EugenOS
EugenOS

Reputation: 31

Marshalling array field in union-like structure

I'm trying to create union like structure with byte[] field. So next type declaration causes an error in runtime:

    [StructLayout(LayoutKind.Explicit)]
public struct Int64ByteArr
{
    [FieldOffset(0)]
    public UInt64 u64;
    [FieldOffset(0)]
    public Int64 s64;
    [FieldOffset(0), MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]        
    public byte[] bytes;
}

when calling a function which uses variable of that type, program causes exception with that description:

Необработанное исключение типа "System.TypeLoadException" в System.Windows.Forms.dll Дополнительные сведения: Не удалось загрузить тип "Int64ByteArr" из сборки "ChalengeCalc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", так как он содержит поле объекта со смещением 0, которое неверно выровнено или перекрыто полем, не представляющим объект.

translation to english: unhandled exception of type "System.TypeLoadException" in System.Windows.Forms.dll ) Additional information: Failed to load type "Int64ByteArr" from "ChalengeCalc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" Assembly cause it contains field of object with oaffset 0, which is incorrectly aligned of overflowed by field which not presenting an object

also i try this variant:

    [StructLayout(LayoutKind.Sequential)]
public struct ByteArr8
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
    public byte[] bytes;
    public Byte this[int idx]
    {
        get
        {
            if (idx < 0 || idx > 7) return 0;
            return bytes[idx];
        }
        set
        {
            if (idx < 0 || idx > 7) return;
            bytes[idx] = value;
        }
    }
}
[StructLayout(LayoutKind.Explicit)]
public struct Int64ByteArr
{
    [FieldOffset(0)]
    public UInt64 u64;
    [FieldOffset(0)]
    public Int64 s64;
    [FieldOffset(0)]
    public ByteArr8 bytes;
}

It hangs with the same exception. So there is a question: "how to?"

Upvotes: 0

Views: 364

Answers (1)

Dmitry Egorov
Dmitry Egorov

Reputation: 9650

In your particular case you may marshal the byte array field only and provide getters/setters for the others:

[StructLayout(LayoutKind.Sequential)]
struct Int64ByteArr
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
    public byte[] bytes;
    public UInt64 u64
    {
        get { return BitConverter.ToUInt64(bytes, 0); }
        set { bytes = BitConverter.GetBytes(value); }
    }
    public Int64 s64
    {
        get { return BitConverter.ToInt64(bytes, 0); }
        set { bytes = BitConverter.GetBytes(value); }
    }
}

Note: inspired by David Heffernan's comment to this question.

In general case you would have to use custom marshaling, I believe.

Upvotes: 1

Related Questions