平台调用P-INVOKE高级篇(一)--(封送含有二维数组的结构体)

来源:互联网 发布:admaster数据分析岗 编辑:程序博客网 时间:2024/05/17 03:06

      对于结构体二维数组,看似简单,其实很复杂。很多人往往不知从何下手,在托管和非托管代码之间总是不能正确传递值。先用一个例子:

  struct Lable1  {

        BYTELabFilterChan0[4][256];

        BYTELabFilterChan1[4][256];      

   }

 

这是曾经有人这样在C#进行定义的:

 第一个:

[StructLayout(LayoutKind.Sequential)]

    public class Label1    {

        public byte[,]LabFilterChan0 = new byte[4, 256];

        public byte[,]LabFilterChan1 = new byte[4, 256];

    }

 

第二个:

public struct Label1{

    byte[,]LabFilterChan0 = newbyte[4,256];

    byte[,]LabFilterChan1 = new byte[4,256];

}

 

第三个:

public struct Label1{

    byte[4,256]LabFilterChan0 ;

    byte[4,256]LabFilterChan1 ;

}

咋一看,好像没什么问题!大家可以仔细看看,其实都有问题:

对于非托管和托管的结构体对应,关键就是两点:

1、两边的结构体大小要一致。

2、字节顺序要一致!

3、字符集。

其实第二点主要针对嵌套联合体来说的,没有嵌套联合体,一般按顺序字节方式即可:[StructLayout(LayoutKind.Sequential)]。对应嵌套联合体的结构体,将在下一篇进行讲解。  字符集比较好理解,就是Ansi和Unicode两种,即1个和2个字节。由于这个结构体没有包含字符串成员变量,所以,我们这里重点关注第一点!

对于简单类型的成员变量,如byte、short、int、float等,很容易跟C#的类型对应,MSDN专门有这个对应表,我这里不再重述。

回到这个例子,上面的三种转换错在哪里:

第一个:语法正确,内存空间8,而C++是1024!

第二个、第三个:C#语法就不允许,大家可以测试,看看报的什么语法错误,加深印象!

那么,正确做法是怎样呢?

第一种:拆分,也是最简单办法:

   [StructLayout(LayoutKind.Sequential)]

    public structByteStru    {

       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]

        public byte[]a;

    };

 

   [StructLayout(LayoutKind.Sequential)]

    public structLabel1    {

       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]

        publicByteStru[] LabFilterChan0 ;

       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]

        public ByteStru[] LabFilterChan1 ;

    };

 

第二种:合并,这个比较复杂:

  [StructLayout(LayoutKind.Sequential)]

    public structLabel1    {

       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]

        publicbyte[] LabFilterChan0 ;

        [MarshalAs(UnmanagedType.ByValArray,SizeConst = 1024)]

        publicbyte[] LabFilterChan1 ;

    };


这种办法,就把原来的二维数组,全部转为一个byte的一维数组,需要在使用做比较复杂处理:
    public static byte[] MashalSimpleTwoArrayToBytes<T>(T[][] arr)    {

        introw = arr.GetLength(0);

        intcol = arr.GetLength(1);

        inttypeSize=Marshal.SizeOf(typeof(T));

        inttotalLength=row*col*typeSize;

        //开辟一个Byte 数组

        byte[]allBuffuer = newbyte[totalLength];

        intstartIndex = 0;

        //然后依次把arr的数据拷贝到allBuffuer

        for(int i = 0; i < row; i++)

        {

            arr[i].CopyTo(allBuffuer, startIndex);

            startIndex+= typeSize * col;

        }

        returnallBuffuer;

   }