开发者

Cannot marshal a struct that contains a union

I have a C++ struct that looks like this:

struct unmanagedstruct
{
    int开发者_JS百科             flags;
    union
    {
        int             offset[6];
        struct
        {
            float           pos[3];
            float           q[4];
        } posedesc;
    } u;
};

And I'm trying to Marshal it like so in C#:

[StructLayout(LayoutKind.Explicit)]
public class managedstruct {
    [FieldOffset(0)]
    public int flags;

    [FieldOffset(4), MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 6)]
    public int[] offset;

    [StructLayout(LayoutKind.Explicit)]
    public struct posedesc {
        [FieldOffset(0), MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 3)]
        public float[] pos;

        [FieldOffset(12), MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 4)]
        public float[] q;
    }

    [FieldOffset(4)]
    public posedesc pose;
}

However, when I try loading data into my struct only the first 3 elements of the offset array are there (the array's length is 3). I can confirm that their values are correct - but I still need the other 3 elements. Am I doing something obviously wrong?

I'm using these functions to load the struct:

private static IntPtr addOffset(IntPtr baseAddress, int byteOffset) {
    switch (IntPtr.Size) {
        case 4:
            return new IntPtr(baseAddress.ToInt32() + byteOffset);
        case 8:
            return new IntPtr(baseAddress.ToInt64() + byteOffset);
        default:
            throw new NotImplementedException();
    }
}

public static T loadStructData<T>(byte[] data, int byteOffset) {
    GCHandle pinnedData = GCHandle.Alloc(data, GCHandleType.Pinned);
    T output = (T)Marshal.PtrToStructure(addOffset(pinnedData.AddrOfPinnedObject(), byteOffset), typeof(T));
    pinnedData.Free();
    return output;
}

Loading example:

managedstruct mystruct = loadStructData<managedstruct>(buffer, 9000);

Let me know if you need more information.


I'm not 100% sure about this but I believe that the Union means that the same memory is used for both members. In the case of the C++ structure, an int[] or a posedesc structure. So the size of the structure will be sizeof(int) + sizeof(posedisc). Meaning, Union doesn't mean you'll have both an int[] and a posedisc you'll have shared memory that can be either of those types in C++ land but only one or the other in managed land.

So I think you probably need two managed structures, one that has offset and one that has posedisc. You can pick one or the other in your call to LoadStruct. Optionally you could create a byte[] field and have calculated properties that convert those bytes into the desired types.


A possible cause for problem might be the fact that in C++, int has a size that depends on the architecture.

In other words, in some circumstances, your offset array in the C++ struct may be actually an array of 64 bit values.

Now, in your C# struct, whenever you used the MarshalAs attribute, you do not specify the ArraySubType parameter.

According to the documentation, when you omit ArraySubType, the struct is supposed to be marshalled according to the type of the managed array, but maybe the fact that the offset array in the C++ struct is not spread accros 48 bytes instead of 24, is causing the problem you encountered.

My suggestion would be to try to change all int to long in the C++ struct to ensure the size is always the same, and also add the ArraySubType parameter in all your MarshalAs attributes for arrays.


Kinda late to the party, but my best guess is that your offset array gets overwritten by pos array when the marshaller reaches the field, and it will be the reference that gets overwritten, not the actual elements. Therefore, offset will always be of length 3 (and try GetType on it, it should return Single[]. This is what you get for overlapped references.).

So either you can delete q and set pos' size to 7, or you can use fixed arrays (although I'm not sure how it will get marshalled).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜