19

I'm trying to create the following structure:

    [StructLayout(LayoutKind.Explicit, Size=14)]
    public struct Message
    {
        [FieldOffset(0)]
        public ushort X;
        [FieldOffset(2)]
        [MarshalAs(UnmanagedType.ByValArray, SizeConst=5)]
        private ushort[] Y;
        [FieldOffset(12)]
        public ushort Z;
    }

and I get the following error:

Could not load type 'Message' from assembly because it contains an object field at offset 4 that is incorrectly aligned or overlapped by a non-object field.

Does anyone know why this is causing an error?

Note: I can not use Pack because I'm working with the compact framework. Thanks.

SwDevMan81
  • 48,814
  • 22
  • 151
  • 184

2 Answers2

14

The CF Marshaler isn't so good at this type of thing and what you're attempting is unsupported. The problem is that it knows that the first element is unaligned, but it seems to not understand that each element in the array would also be unaligned.

You can see the behavior works in this example:

[StructLayout(LayoutKind.Explicit, Size = 14)]
public struct Message
{
    [FieldOffset(0)]
    public ushort X;

    [FieldOffset(2)]
    private ushort Y1;

    [MarshalAs(UnmanagedType.LPArray)]
    [FieldOffset(4)]
    private ushort[] Y2;

    [FieldOffset(12)]
    public ushort Z;
}

For this type of structure, I never let the marshaler try to handle each of the members anyway. The structure is small, so break out each individual item like this:

[StructLayout(LayoutKind.Explicit, Size = 14)]
public struct Message
{
    [FieldOffset(0)]
    public ushort X;

    [FieldOffset(2)]
    private ushort Y1;

    [FieldOffset(4)]
    private ushort Y2;

    [FieldOffset(6)]
    private ushort Y3;

    [FieldOffset(8)]
    private ushort Y4;

    [FieldOffset(10)]
    private ushort Y5;

    [FieldOffset(12)]
    public ushort Z;
}

or use a simulated "union" like this:

public struct Y
{
    public ushort a;
    public ushort b;
    public ushort c;
    public ushort d;
    public ushort e;
}

[StructLayout(LayoutKind.Explicit, Size = 14)]
public struct Message
{
    [FieldOffset(0)]
    public ushort X;

    [FieldOffset(2)]
    private Y Y;

    [FieldOffset(12)]
    public ushort Z;
}
ctacke
  • 66,480
  • 18
  • 94
  • 155
  • 1
    Ok, so the simplest answer is in your comment below: Arrays must be DWORD aligned in the CF – SwDevMan81 Aug 04 '09 at 21:24
  • @ctacke: Could you refer me to a reference that contains detailed information about the CF Marshaler (e.g. that arrays must be DWORD allgned)? – Odrade Aug 19 '09 at 19:56
  • @david: I don't know of one. All I know of the marshaler and it's capabilities (or lack thereof) is from meeting and conversations with the CF team, coupled with years of experience trying to get it to do what I want. – ctacke Aug 20 '09 at 06:07
4

The problem is occurring because your array is overlapping "X". ulong, in C#, is UInt64 (in C++, ulong is UInt32), so it's actually 8 bytes.

If you change your second FieldOffset to 8, or changed X to uint, this will go away.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • @Reed - Thanks, I changed it now to a ushort and I still get the error, is ushort 4 bytes? I've looked on msdn and sizeof(ushort) is 2, but I get the error. When I change the fieldoffset to 4, it works. – SwDevMan81 Jul 27 '09 at 19:33
  • 1
    My guess is now its an alignment problem, do I need to start the array on a 4 byte boundary? I cant find anything online – SwDevMan81 Jul 27 '09 at 19:36
  • 2
    Arrays must be DWORD aligned in the CF. See my answer for more details and potential workarounds. – ctacke Jul 27 '09 at 21:49
  • 1
    @ctacke: Yeah - the 4 byte alignment is the problem here... Forgot that limitation on CF. – Reed Copsey Jul 27 '09 at 23:58