views:

920

answers:

2

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.

+1  A: 

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
@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
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
Arrays must be DWORD aligned in the CF. See my answer for more details and potential workarounds.
ctacke
@ctacke: Yeah - the 4 byte alignment is the problem here... Forgot that limitation on CF.
Reed Copsey
+2  A: 

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
Ok, so the simplest answer is in your comment below: Arrays must be DWORD aligned in the CF
SwDevMan81
@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
@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