C# 封装 C++的dll
C# 的程序引用C++的dll时,首先要保证两者基于的平台一致,比如都是x64,或者都是x86的程序,否者两者之间不能直接调用,然后,要保证两者的数据类型可以相互识别,相互通用。在此重点介绍几个常用的数据转换。
- C++的char* 和 char[] 数组,对应到C#的string 类型
- C++的Handle 类型,一般是一个很大的整数,C#可以使用 IntPtr
- 对于指针类型的要使用ref
- C++中的结构体,可以在C#中声明同样名称的结构体,但是要进行一定的设置
- 使用StructLayout 特性设置结构体,当有char时,要设置 CharSet = CharSet.Ansi
- 使用string时,要使用 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)] 特性修饰,并分配与原c++中的char数组相同大小的内存
使用DllImportAttribute(string dllPath) 来构造C++的同名函数,此特性有几个常用字段
- CharSet 指示如何向方法传送字符串参数,并控制名称重整
- None 与 Ansi具有相同的行为
- Ansi 以单字节的形式封装传送字符串
- Auto针对操作系统自动封装字符串
- Unicode 以双字节的形式封送字符串
- CallingConvention 指示入口点的调用规则
- Cdecl 调用方清理堆栈
- StdCall 被调用方清理堆栈
- ThisCall 第一个参数是this指针
- Winapi 默认平台调用约定
结构体与函数举例
结构体举例1:
C++结构体 struct SGP_ANALYTIC_TEMP { int rule_id; char rule_name[50]; float max_temp; }; C#对应的结构体声明 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct SGP_ANALYTIC_TEMP { public int rule_id = 0; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)] public string rule_name="123"; public float max_temp = 0;//最高温度值 }
结构体举例2:结构体中嵌套结构体,此时对于结构体数组,也要使用MarshalAs指定类型,并分配内存
C++结构体 struct SGP_GENERAL_INFO { int range_num;//测温范围数量 SGP_RANGE range[3];//测温范围 char vl_rtsp_url[50];//可见光主码流rtsp地址 }; C++ 函数类型 int SGP_GetGeneralInfo(SGP_HANDLE handle, SGP_GENERAL_INFO *output); C# 对应的结构体 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct SGP_GENERAL_INFO { public int range_num ;//测温范围数量 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public SGP_RANGE[] range;//测温范围 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)] public string vl_sub_rtsp_url;//可见光辅码流rtsp地址 } C# 函数类型 [DllImport(sdkPath, EntryPoint = "SGP_GetGeneralInfo", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern int SGP_GetGeneralInfo(IntPtr handle, ref SGP_GENERAL_INFO output);
遇到的问题
问题1 :
在引入DLL中的方法时,有时会出现以下错误报告:“在使用托管代码调用非托管代码时,发生“ 对 PInvoke 函数的调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配。请检查 PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配。
解决方法:
在DllImport时添加 CallingConvention = CallingConvention.Cdecl 即调用方清理堆栈,注意,当调用的C++dll还依赖其他dll时,需要把所调用的dll文件都放在一起,否则会抛出 System.DllNotFoundException的异常
问题2:

解决方法:
主要是由于Dll编译的平台和调用它的工程的平台不一致导致的,可都统一打到X64平台下编译
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)