C#调用C++ DLL返回字符串乱码问题求助
解决C#调用C++ DLL返回俄文字符串的编码乱码问题
问题场景
C#调用C++编写的DLL获取俄文返回字符串时出现乱码,两种尝试均有问题:
- 初始配置
CharSet = CharSet.Unicode,输出截断乱码:РАЗВОРОТ(듹翼 - 改为
CharSet = CharSet.Ansi并将C++端wstring转string后,内容完整但编码异常:Р РђР—Р’РћР РћРў(1, 1.1, 1.2, 1.3, 1.4)Р РђР—Р’РћР РћРў(1, 2.1, 2.2, 2.3, 2.4)
原C++导出代码
extern "C" __declspec(dllexport) Dll_NIRS_API void realize(char*) void realize(char* buf) { // ... 业务逻辑 wstring full_text; // 对full_text的操作 char* fill = (char*)(full_text.c_str()); strcpy(buf, fill); }
原C#调用代码
[DllImport("dll_name.dll", CharSet = CharSet.Unicode)] public static extern void realize(StringBuilder text); // 调用逻辑 StringBuilder text = new StringBuilder(100); realize(text); textBox4.Text = text.ToString();
解决方案
方案一:宽字符(UTF-16)直接匹配(推荐)
C++端使用wchar_t作为参数类型,和C#的Unicode字符集直接匹配,避免编码转换:
修改后C++代码
extern "C" __declspec(dllexport) void realize(wchar_t* buf) { wstring full_text = L"РАЗВОРОТ(1, 1.1, 1.2, 1.3, 1.4)\nРАЗВОРОТ(1, 2.1, 2.2, 2.3, 2.4)"; // 用wcscpy复制宽字符,替代strcpy wcscpy(buf, full_text.c_str()); }
C#调用代码(仅调整缓冲区容量)
[DllImport("dll_name.dll", CharSet = CharSet.Unicode)] public static extern void realize(StringBuilder text); // 调用时给足够大的缓冲区,确保容纳所有字符(含换行) StringBuilder text = new StringBuilder(200); realize(text); textBox4.Text = text.ToString();
说明:wstring本质是UTF-16编码的宽字符,和C#字符串的编码一致,直接用wcscpy复制不会出现编码错位或截断。
方案二:UTF-8编码中转
如果必须用char*导出,C++端将宽字符转成UTF-8编码的单字节字符串,C#接收后再转成UTF-16字符串:
修改后C++代码
#include <codecvt> #include <locale> extern "C" __declspec(dllexport) void realize(char* buf, int bufSize) { wstring full_text = L"РАЗВОРОТ(1, 1.1, 1.2, 1.3, 1.4)\nРАЗВОРОТ(1, 2.1, 2.2, 2.3, 2.4)"; // 将宽字符转成UTF-8编码的string std::wstring_convert<std::codecvt_utf8<wchar_t>> converter; std::string utf8_text = converter.to_bytes(full_text); // 确保缓冲区足够,防止溢出 if (utf8_text.size() + 1 <= bufSize) { strcpy(buf, utf8_text.c_str()); } }
C#调用代码
[DllImport("dll_name.dll", CharSet = CharSet.Ansi)] public static extern void realize(StringBuilder text, int bufSize); // 调用逻辑 int bufSize = 256; // 预留足够空间 StringBuilder text = new StringBuilder(bufSize); realize(text, bufSize); // 将接收的UTF-8字节转成正确字符串 byte[] utf8Bytes = Encoding.Default.GetBytes(text.ToString()); string result = Encoding.UTF8.GetString(utf8Bytes); textBox4.Text = result;
说明:UTF-8是通用编码,能正确存储俄文字符,避免Ansi编码因区域设置不同导致的乱码。
方案三:增加缓冲区长度校验
不管用哪种方案,都建议在C++函数中返回字符串长度,或传入缓冲区大小避免截断:
C++代码
extern "C" __declspec(dllexport) int realize(wchar_t* buf, int bufSize) { wstring full_text = L"РАЗВОРОТ(1, 1.1, 1.2, 1.3, 1.4)\nРАЗВОРОТ(1, 2.1, 2.2, 2.3, 2.4)"; int textLength = full_text.size(); if (bufSize > textLength) { wcscpy(buf, full_text.c_str()); return textLength; // 返回实际字符长度 } return -1; // 缓冲区不足,返回错误标记 }
C#调用代码
[DllImport("dll_name.dll", CharSet = CharSet.Unicode)] public static extern int realize(StringBuilder text, int bufSize); // 调用逻辑 int bufSize = 200; StringBuilder text = new StringBuilder(bufSize); int resultLength = realize(text, bufSize); if (resultLength != -1) { textBox4.Text = text.ToString(); } else { // 处理缓冲区不足的情况,比如提示或增大缓冲区 }
内容的提问来源于stack exchange,提问作者Daria
相关产品推荐
相关产品推荐

