本文探讨C#与C/C++之间的跨语言交互方案,重点解析PInvoke机制在实际开发中的应用。通过具体案例演示数据类型映射、指针传递及结构体交互等核心操作。
跨语言调用主要采用两种方案:基于C++/CLI的中间层封装和直接PInvoke调用。由于Mono框架对C++/CLI的兼容性限制,本文聚焦于PInvoke技术实现,适用于需跨平台支持的场景。
关键注意事项:C/C++导出函数必须使用extern "C"声明,以确保符号名称一致。以下通过具体示例说明各类数据交互方式:
1. 基础数据类型映射
不同语言的数据类型存在字节差异,例如C/C++的long对应C#的int,char需用byte表示。通过以下对照表可明确转换关系:
| C/C++类型 | C#类型 | 大小 |
|---|---|---|
| short | short | 2B |
| int | int | 4B |
| long | int | 4B |
| bool | bool | 1B |
| char | byte | 1B |
| wchar_t | char | 2B |
| float | float | 4B |
| double | double | 8B |
2. 字符串传递示例
C++端定义导出函数:void __stdcall OutputString(wchar_t* text);
C#端通过DllImport声明:[DllImport("MyDll.dll")] extern static void OutputString(char* text);
调用时需使用fixed语句固定字符串内存地址:
unsafe { fixed(char* p = &"Hello".ToCharArray()[0]) { OutputString(p); } }
3. 指针交互实践
C++函数示例:void __stdcall ModifyValue(int* val);
C#调用方式:[DllImport("MyDll.dll")] extern static void ModifyValue(int* val);
数组传递需确保内存固定:fixed(int* arr = &intArray[0]) { ProcessArray(arr, length); }
4. 函数指针传递
C#委托定义:public delegate void CallbackHandler(int param);
C++函数声明:typedef void (__stdcall *CallbackFunc)(int);
通过DllImport注入回调:[DllImport("MyDll.dll")] extern static void RegisterCallback(CallbackHandler callback);
5. 结构体交互
C#结构体需添加[StructLayout(LayoutKind.Sequential)]特性:struct Point3D { public float X, Y, Z; }
C++对应结构体定义:struct Point3D { float X, Y, Z; };
传递示例:[DllImport("MyDll.dll")] extern static void ProcessPoint(Point3D point);
完整实现包含DLL导出配置、内存管理及跨语言数据校验等细节,具体代码示例可参考以下结构:
#define API_EXPORT __declspec(dllexport)
EXTERN_C API_EXPORT int CalculateSum(int x, int y);
EXTERN_C API_EXPORT void ProcessData(int* buffer, int size);
EXTERN_C API_EXPORT void SetCallback(void (__stdcall *cb)(int));
[DllImport("NativeLib.dll")]
extern static int CalculateSum(int a, int b);
[DllImport("NativeLib.dll")]
extern static void ProcessData(int* data, int count);