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); }
|
源码下载