Marshalling complex struct to c#

空扰寡人 提交于 2019-12-19 10:52:14

问题


i'm still struggeling to marshal a quite complex struct from c++ to c#.

The struct in c++ is the following:

typedef struct {
    DWORD Flags;                    
    DWORD TimeCode;                 
    DWORD NodeMoving;   
    Matrix NodeRots[NUM_GYROS];
    Vector Position;                
    DWORD ContactPoints;            
    float channel[NUM_CHANNELS];
} Frame;

Vector:

typedef struct {
    union {
        struct {
            float x, y, z;
        };
        float Array[3];
    };
} Vector;

Matrix:

typedef struct {
    union {
        struct {
            float xx, xy, xz;       //This row is the right vector
            float yx, yy, yz;       //This row is the up vector
            float zx, zy, zz;       //This row is the forward vector
        };
        float Array[3][3];          //[row][col]
    };
} Matrix;

And here is what I have in c#:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public unsafe struct Matrix
    {
        public float xx;
        public float xy;
        public float xz;
        public float yx;
        public float yy;
        public float yz;
        public float zx;
        public float zy;
        public float zz;    
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public unsafe struct Vector{
        public float x;
        public float y;
        public float z; 
    }


    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public unsafe struct Frame{
        public uint Flags;                  
        public uint TimeCode;                   
        public uint NodeMoving;             
        public fixed byte NodeRots[NUM_GYROS];
        public Vector Position;             
        public uint ContactPoints;          
        public fixed float channel[CHANNEL_ARRAY_SIZE];


        public unsafe float[] Channel
        {
            get
            {
                fixed (float* ptr = channel)
                {
                    float[] array = new float[CHANNEL_ARRAY_SIZE];

                    Marshal.Copy((IntPtr)ptr, array, 0, CHANNEL_ARRAY_SIZE);
                    return array;
                }
            }
        }

        public unsafe Matrix[] nodeRots{
            get{
                fixed (byte* ptr = NodeRots){
                    IntPtr ptr2 = (IntPtr)ptr;
                    Matrix[] array = new Matrix[NUM_GYROS];
                    for (int i = 0; i < array.Length; i++)
                    {
                        array[i] = (Matrix)Marshal.PtrToStructure(ptr2, typeof(Matrix));
                        IntPtr oldptr = ptr2;
                        ptr2 = new IntPtr(oldptr.ToInt32() + Marshal.SizeOf(typeof(Matrix)));
                    }
                    return array;
                }
            }
        }

the values Flags, TimeCode, NodeMoving, and NodeRots of the Frame struct are already passed correctly. The Members Position, ContactPoints and channel aren't marshalled correctly. I assume I have to do something with the Position Member, but I don't really know whats the mistake exactly.


回答1:


I have already told you. You can't use fixed byte as an universal solution to problems.

This

public fixed byte NodeRots[NUM_GYROS];

must be

public fixed Matrix NodeRots[NUM_GYROS];

Then this:

Marshal.Copy((IntPtr)ptr, array, 0, CHANNEL_ARRAY_SIZE)

must be

Marshal.Copy((IntPtr)ptr, array, 0, CHANNEL_ARRAY_SIZE * sizeof(float));

Then for the nodeRots getter you don't really need the Marshal.PtrToStructure, because your struct can be marshaled directly.

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public unsafe struct Frame
{
    public uint Flags;
    public uint TimeCode;
    public uint NodeMoving;
    public fixed float nodeRots[NUM_GYROS * 9];
    public Vector Position;
    public uint ContactPoints;
    public fixed float channel[CHANNEL_ARRAY_SIZE];

    public unsafe float[] Channel
    {
        get
        {
            fixed (float* ptr = channel)
            {
                float[] array = new float[CHANNEL_ARRAY_SIZE];

                Marshal.Copy((IntPtr)ptr, array, 0, CHANNEL_ARRAY_SIZE * sizeof(float));
                return array;
            }
        }
    }

    public unsafe Matrix[] NodeRots
    {
        get
        {
            fixed (float* ptr = nodeRots)
            {
                Matrix[] array = new Matrix[NUM_GYROS];

                for (int i = 0, y = 0; i < array.Length; i++, y += 9)
                {
                    array[i].xx = ptr[y + 0];
                    array[i].xy = ptr[y + 1];
                    array[i].xz = ptr[y + 2];

                    array[i].yx = ptr[y + 3];
                    array[i].yy = ptr[y + 4];
                    array[i].yz = ptr[y + 5];

                    array[i].zx = ptr[y + 6];
                    array[i].zy = ptr[y + 7];
                    array[i].zz = ptr[y + 8];
                }

                return array;
            }
        }
    }
}


来源:https://stackoverflow.com/questions/30464437/marshalling-complex-struct-to-c-sharp

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!