c# 与c++接口间调用时传递结构体

 复杂结构体的传递

1. 输出参数,结构体作为指针传出

 非托管部分代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

typedef struct

{

    char name[20];

    int age;

    double scores[32];

}Student;

 

//Class中包含结构体数组类型

typedef struct

{

    int number;

    Student stedents[50];

}Class;

 

JNAAPI int GetClass(Class *pClass,int len)

{

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

    {

        pClass[i].number = i;

        for(int j = 0; j< 50; j++)

        {

            //把name中的前20个字节用0代替

            memset(pClass[i].stedents[j].name, 0, 20);

            //给每个同学命名

            sprintf(pClass[i].stedents[j].name, "name_%d_%d", i, j);

            pClass[i].stedents[j].age = j % 2 == 0 ? 15:20;

        }//for

    }//for

 

    return 0;

}

  

上面DLL 的导出函数要求传递的参数为它自定义的Class结构体数组, 那么我们在C#调用它时也要自定义对应的结构体了,

我们可以定义为如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

[StructLayout(LayoutKind.Sequential)]

struct Student

{

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]

    public string name;

    public int age;

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

    public double[] scores;

}

[StructLayout(LayoutKind.Sequential)]

struct Class

{

    public int number;

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

    public Student[] students;

 

}

  需要注意的是,这2个结构体中的数组大小一定要跟C++中的限定一样大小哦,接下来如何使用这个API来正确的获取数据呢,大多数人可能想到像这样的处理方式:

1

2

3

4

Class myclass = new Class();

IntPtr ptr=Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Class)));

GetClass(ptr);

Marshal.FreeHGlobal(ptr);

  

没错,这样的处理是没问题的,但是我们的API的参数是Class数组,这种处理方式只是传递一个Class结构体参数,所以这种方式在这里就不太合适了,!

 那大家就想到先Class[] myclass = new Class[MaxClass]; 然后在用Marshal.AllocHGlobal 来获取myclass 数据的指针,

其实这样也是错的, 因为 Class结构中包含了,不能直接封送的Student结构,所以无论如何上面的想法是错误的!

那要怎么办呢,其实很简单,就是先分配一段非托管内存,并调用API后,再将非托管内容数据读取到托管结构体数据中!

 

示例演示代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

// 接口定义  

[DllImport("CSharpInvokeCpp_CppDemo.dll", CallingConvention = CallingConvention.Cdecl)]

public static extern int GetClass(IntPtr pv, int len);

//复杂结构体传递测试代码

int size = Marshal.SizeOf(typeof(Class)) * 50;

IntPtr pBuff = Marshal.AllocHGlobal(size);

CppDLL.GetClass(pBuff, 50);

 

Class[] pClass = new Class[50];

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

{

    IntPtr pr = new IntPtr(pBuff.ToInt64() + Marshal.SizeOf(typeof(Class)) * i);

    pClass[i] = (Class)Marshal.PtrToStructure(pr, typeof(Class));

}

Marshal.FreeHGlobal(pBuff);

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值