You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 05:55:19