将复杂结构编组到 C#

Posted

技术标签:

【中文标题】将复杂结构编组到 C#【英文标题】:Marshalling complex struct to c# 【发布时间】:2015-05-26 16:47:25 【问题描述】:

我仍在努力将一个相当复杂的结构从 c++ 编组到 c#。

c++中的结构如下:

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

矢量:

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

矩阵:

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;

这是我在 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;
                
            
        

Frame 结构的值 Flags、TimeCode、NodeMoving 和 NodeRots 已经正确传递。成员职位、联系点和渠道未正确编组。我想我必须对职位成员做点什么,但我真的不知道到底是什么错误。

【问题讨论】:

NodeRots 是从哪里来的?不应该是矩阵吗? 或至少Num_Gyros * 9 * 4 我认为它应该,但是当我将它声明为固定矩阵时,我得到一个编译错误:DLLHelper.Frame.nodeRots':固定大小缓冲区类型必须是以下之一:bool、byte、short , int, long, char, sbyte, ushort, uint, ulong, float 或 double 【参考方案1】:

我已经告诉过你了。您不能将fixed byte 用作问题的通用解决方案。

这个

public fixed byte NodeRots[NUM_GYROS];

必须

public fixed Matrix NodeRots[NUM_GYROS];

然后这个:

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

必须

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

那么对于nodeRots getter,您实际上并不需要Marshal.PtrToStructure,因为您的结构可以直接编组。

[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;
            
        
    

【讨论】:

我无法将 NodeRots 声明为固定矩阵,因为我收到编译错误:DLLHelper.Frame.nodeRots':固定大小缓冲区类型必须是以下之一:bool、byte、short、int、 long、char、sbyte、ushort、uint、ulong、float 或 double @user1643687 对...再试一次。修改为固定的 float[] 数组,并更改了 NodeRots 属性 @xanatos 也许你可以帮我解决我刚刚问的问题? ***.com/questions/30592485/…

以上是关于将复杂结构编组到 C#的主要内容,如果未能解决你的问题,请参考以下文章

创建要在 C# 中编组的 C++ Dll 的最佳实践 [关闭]

将具有枚举成员的非托管结构编组到 c#

如何将 C 指针编组到 C# 结构数组

将 C++ 结构编组到 C# 类时出现 AccessViolationException

将具有 int* 成员的 C++ 结构编组到 C#

将包含 int 和 int[] 的结构从 C# 编组到 C++