C# 引用C/C++ DLL之常见类型转换

C#引用C/C++ DLL系列再水最后一篇……

整体思路:需要考虑这个数据在c语言内存中是如何存储的。当变量在C/C++ dll中所占的内存长度等于C#变量所占内存长度,基本可以直接转换。复杂的类型,如数组、结构体,可以通过Intptr进行接收,再获取对应地址的内存然后转换。

在实际应用中,需注意申请内存的合理释放避免内存泄露和异常崩溃,还需注意C/C++的变量长度可能在不同平台(windows/linux)下有不同的定义。

常见 C/C++ 数据类型 C# 接收使用的数据类型
int int
float float
double double
struct Intptr
char* IntPtr
int* Intptr

int*

1
2
3
4
5
6
7
8
9
int* GetIntArray(int len, int* array)
{
for (int i = 0; i < len; i++)
{
printf("idx:%d, val:%d\r\n", i, array[i]);
array[i] = array[i] + 1;
}
return array;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[DllImport("CDll.dll", EntryPoint = "GetIntArray")]
private static extern IntPtr GetIntArray(int len, IntPtr array);

public static void TestDllImport()
{
int[] array = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
IntPtr ptr_GetIntArray = Marshal.AllocHGlobal(array.Length * 4);
Marshal.Copy(array, 0, ptr_GetIntArray, 10);
IntPtr ptr_res = GetIntArray(10, ptr_GetIntArray);
Marshal.Copy(ptr_res, array, 0, 10);
foreach (var t in array)
Console.WriteLine(t);
}

char*

1
2
3
4
5
char* GetStr()
{
char * str= "hello world\0";
return str;
}
1
2
3
4
5
6
7
8
9
10
[DllImport("CDll.dll", EntryPoint = "GetStr")]
private static extern IntPtr GetStr();

public static void TestDllImport()
{
IntPtr ptr = GetStr();
string str = Marshal.PtrToStringAnsi(ptr);
Console.WriteLine(str);
}

struct

1
2
3
4
5
6
7
8
9
10
typedef struct _Par_ {
int a;
int b;
}_Par;

int AddPar(_Par* p)
{
return p->a + p->b;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct _Par
{
public int a;
public int b;
}

[DllImport("CDll.dll", EntryPoint = "AddPar")]
private static extern int AddPar(IntPtr par);

public static void TestDllImport()
{

_Par par = new _Par { a = 7, b = 8 };
IntPtr parP = Marshal.AllocHGlobal(Marshal.SizeOf(par));
Marshal.StructureToPtr(par, parP, true);
int res2 = AddPar(parP);
Console.WriteLine(res2);

}

源码下载