P/Invoke各种总结(六、C#与C++结构体的交互)
C#在和C++进行交互时,有时候会需要传递结构体。
做一些总结,避免大家在用的时候踩坑。
一般情况
例如我们在C++里定义了一个struct_basic结构体
1 struct struct_basic 2 { 3 WORD value_1; 4 LONG value_2; 5 DWORD value_3; 6 UINT value_4; 7 BOOL value_5; 8 };
这种情况在C#里调用,只需要注意数据类型对应就行了
在C#里定义如下
1 struct struct_basic 2 { 3 public ushort value_1; 4 public int value_2; 5 public uint value_3; 6 public uint value_4; 7 public bool value_5; 8 }
使用导出函数来测试一下
1 extern "C" __declspec(dllexport) void get_basic(struct_basic basic); 2 3 extern "C" __declspec(dllexport) void get_basic(struct_basic basic) 4 { 5 basic.value_1 = 1; 6 basic.value_2 = 2; 7 basic.value_3 = 3; 8 basic.value_4 = 4; 9 basic.value_5 = FALSE; 10 }
在C#中调用
[DllImport("lib.dll")] public static extern void get_basic(ref struct_basic basic); static void Main(string[] args) { struct_basic basic = new struct_basic(); get_basic(ref basic); Console.WriteLine($"{basic.value_1} {basic.value_2} {basic.value_3} {basic.value_4} {basic.value_5}"); }
输出结果如下:
包含字符串的情况
C++
1 struct struct_advanced 2 { 3 WORD id; 4 CHAR message[256]; 5 };
这种需要使用MarshalAsAttribute特性来指示如何在托管代码与非托管代码之间封送数据。
UnmanagedType.ByValTStr表示 结构中大小固定的字符串
SizeConst可以指定字符数组的大小
说明:
如果未指定CharSet,默认使用的是Ansi(char)。
Unicode为w_char。
C#
1 [StructLayout(LayoutKind.Sequential,CharSet=CharSet.Unicode)] 2 struct struct_advanced 3 { 4 public ushort id; 5 6 [MarshalAs(UnmanagedType.ByValTStr,SizeConst =256)] 7 public string message; 8 };
使用导出函数测试
C++
1 extern "C" __declspec(dllexport) void get_advanced(struct_advanced* advanced); 2 3 extern "C" __declspec(dllexport) void get_advanced(struct_advanced* advanced) 4 { 5 advanced->id = 101; 6 lstrcpyW(advanced->message, L"HelloWorld"); 7 }
在C#中调用
1 class Program 2 { 3 [DllImport("lib.dll")] 4 public static extern void get_advanced(ref struct_advanced advanced); 5 6 static void Main(string[] args) 7 { 8 struct_advanced advanced = new struct_advanced(); 9 get_advanced(ref advanced); 10 Console.WriteLine($"{advanced.id} {advanced.message}"); 11 } 12 }
输出结果: