C#向C++ DLL传递SafeArray字符串数组仅获首字符,求无改DLL解法
解决C#调用C++ DLL时字符串仅读取首字符的问题
我来帮你分析下问题根源,然后给出不需要修改C++ DLL的解决方案:
问题核心原因
你在C#里把字符串数组封送成了UTF-16编码的BSTR类型SafeArray,但C代码里直接把这些BSTR当作ANSI char*处理——BSTR的每个字符占2字节,ASCII字符的第二个字节是0,strcpy读到第一个0就停止了,自然只能拿到首字符。而VB6调用正常,是因为VB6的字符串封送逻辑刚好适配了C对ANSI字符的处理。
直接解决方案(无需修改C++)
调整C#的DllImport声明,把SafeArray的子类型从VT_BSTR改成VT_LPSTR(ANSI字符串指针),同时补上你之前漏掉的C++函数第二个参数short NFlds(否则会导致栈不平衡):
[DllImport("Example.dll", CallingConvention = CallingConvention.StdCall)] public static extern int SendRequest( [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_LPSTR)] ref string[] fields, short NFlds );
调用代码也需要传入数组长度:
List<String> fields = new List<String>(); fields.Add("Test1"); fields.Add("Test2"); string[] fieldsArr = fields.ToArray(); int resultOfSendRequest = SendRequest(ref fieldsArr, (short)fieldsArr.Length);
为什么这个方案有效?
VT_LPSTR告诉.NET运行时,要把C#字符串转换成ANSI编码的char*指针,再放入SafeArray中;- C++里的
strcpy可以正常读取完整的ANSI字符串(每个字符占1字节,不会提前遇到终止符0); - 补上
NFlds参数是关键:你之前的C#导入函数和C++的函数签名不匹配,这会导致调用时栈溢出,必须对齐参数才能保证调用安全。
备选方案(针对特殊编码场景)
如果你的系统使用非默认ANSI编码,可以手动控制编码转换:
// 先将字符串转换成指定编码的字节数组(手动添加终止符) List<byte[]> byteFields = new List<byte[]>(); foreach (string s in fields) { byte[] bytes = Encoding.GetEncoding("GB2312").GetBytes(s + '\0'); byteFields.Add(bytes); } // 封送字节数组数组为VT_LPSTR类型的SafeArray [DllImport("Example.dll", CallingConvention = CallingConvention.StdCall)] public static extern int SendRequest( [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_LPSTR)] ref byte[][] fields, short NFlds );
不过第一种方案已经能覆盖绝大多数场景,是最简洁的解决方式。
内容的提问来源于stack exchange,提问作者Trax
相关产品推荐
相关产品推荐

