C导出带char*参数的DLL函数,C#导入调用问题咨询
问题分析与解决方案
首先,你的代码存在几个关键问题,咱们一步步拆解并修正:
1. 明显的笔误问题
你在DllImport中声明的函数是GetDllVersion,但在Main里调用的却是AltixDllVersion——这会直接导致编译错误,先把这个笔误改掉。
2. ref string的用法错误
C中的char*在这里是输出缓冲区,而C#的string是不可变类型,ref string会试图把托管字符串的内存地址传递给非托管代码。但CLR会保护托管字符串的内存,非托管代码直接写入会引发内存访问错误,完全不符合预期。
正确的做法是用StringBuilder,它是可变的字符缓冲区,在互操作时会被自动转换为非托管的char*,适合接收非托管代码的输出。
3. 调用约定的缺失
C语言编译的DLL默认使用cdecl调用约定,而C#的DllImport默认是stdcall——如果不明确指定调用约定,会导致栈不平衡,程序运行时崩溃。
正确实现代码
第一步:修正DLL导入声明
class DllSolderMask { // 指定字符集为Ansi(和C的char*匹配),调用约定为C默认的cdecl [DllImport("Dll.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern int GetDllVersion(StringBuilder version); }
第二步:正确调用函数
假设你的C函数要求调用者提供足够大的缓冲区(比如版本字符串不会超过256字符),可以这样写:
static void Main(string[] args) { // 预先分配足够大小的缓冲区 StringBuilder versionBuffer = new StringBuilder(256); // 调用DLL函数 int result = DllSolderMask.GetDllVersion(versionBuffer); // 这里需要根据C函数的返回值判断是否成功(比如返回0表示成功) Console.WriteLine(versionBuffer.ToString()); }
进阶:动态获取缓冲区大小
如果你的C函数支持传入NULL返回所需的缓冲区长度(很多DLL导出函数会这么设计),可以先调用一次获取长度,再分配精准的缓冲区:
static void Main(string[] args) { // 传入NULL获取所需缓冲区大小 int requiredSize = DllSolderMask.GetDllVersion(null); if (requiredSize > 0) { StringBuilder versionBuffer = new StringBuilder(requiredSize); int result = DllSolderMask.GetDllVersion(versionBuffer); Console.WriteLine(versionBuffer.ToString()); } else { Console.WriteLine("获取版本信息失败"); } }
内容的提问来源于stack exchange,提问作者IkuroSan
相关产品推荐
相关产品推荐

