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

發佈了30 篇原創文章 · 獲贊 29 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章