CppMonster
CppMonster

Reputation: 1296

How to properly marshal unmanaged arrays in c# without unsafe

I have unmanaged structure:

typedef struct 
 {
    char  a[48];
    BYTE  b;
    BYTE  c;
    BYTE  d;            
    BYTE  e;            
    BYTE  f;
    BYTE  x;
    char  y[32];
    char  z[128][32];
  }SOMELIKE_STRUCT

I tried to marshal it as it was written in another threads in StackOverflow:

    [StructLayout(LayoutKind.Explicit, Pack = 1)]
    public struct SOMELIKE_STRUCT
    {
        [FieldOffset(0)]
        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 48)]
        public byte[] a;
        [FieldOffset(48)]
        public byte b;
        [FieldOffset(49)]
        public byte c;
        [FieldOffset(50)]
        public byte d;
        [FieldOffset(51)]
        public byte e;
        [FieldOffset(52)]
        public byte f;
        [FieldOffset(53)]
        public byte x;
        [FieldOffset(54)]
        [MarshalAs(UnmanagedType.ByValArray, ArraySubType=UnmanagedType.U1, SizeConst = 32)]
        public byte[] y;
        [FieldOffset(86)]
        [MarshalAs(UnmanagedType.ByValArray, ArraySubType=UnmanagedType.Struct, SizeConst = 128)]
        public STRUCT[] z;
    }

[StructLayout(LayoutKind.Explicit, Pack = 1)]
    public struct STRUCT
    {
        [FieldOffset(0)]
        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 32)]
        public byte[] name;
    }

I have exception:

System.TypeLoadException was unhandled Additional information: Could not load type 'SOMELIKE_STRUCT' from assembly 'ConsoleApplication2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it contains an object field at offset '54' that is incorrectly aligned or overlapped by a non-object field.

  1. Exception shows when I create this struct with new:

    SOMELIKE_STRUCT l = new SOMELIKE_STRUCT();

  2. Exception shows when I will create class (when step into constructor) using that structure (before create instance of that structure)

Upvotes: 3

Views: 2072

Answers (2)

CppMonster
CppMonster

Reputation: 1296

Structures and tables contained in struct have to be placed at address being multiple of word (4/8 bytes for x86/x64).

Upvotes: 1

Chris
Chris

Reputation: 5515

Can't quite figure out what's going on here as your definitions seems correct.

Changing the layout to sequential and removing the manual field offsets seems to work:

[StructLayout( LayoutKind.Sequential, Pack = 1 )]
public struct SOMELIKE_STRUCT
{
    [MarshalAs( UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 48 )]
    public byte[] a;
    public byte b;
    public byte c;
    public byte d;
    public byte e;
    public byte f;
    public byte x;
    [MarshalAs( UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 32 )]
    public byte[] y;
    [MarshalAs( UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 128 )]
    public STRUCT[] z;
}

[StructLayout( LayoutKind.Sequential, Pack = 1 )]
public struct STRUCT
{
    [MarshalAs( UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 32 )]
    public byte[] name;
}

Checking the size with Marshal.SizeOf gives 4182 bytes, and checking the resulting layout with Marshal.OffsetOf gives the same offsets as in your original code. I'm sure someone else here can elaborate on why this is happening.

Upvotes: 3

Related Questions