複雜結構體的傳遞
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);
|