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

C#与C++间无法正常传递加密文本,求问题定位与修复方案

问题根源与修复方案

你的问题核心是C++ DLL和C#调用之间的字符集不匹配,再加上C++代码里的几个细节错误,导致输入输出无法同时正常工作。我来一步步拆解问题,然后给你可行的修复方案:


先分析为什么会出现双向矛盾

你的C++函数参数是混合字符集的:输入是const char*(ANSI单字节),输出是wchar_t*(Unicode双字节),但C#的DllImport只能全局设置一种CharSet,这就必然导致一边匹配、另一边乱码:

  • 当CharSet=Ansi时:C#的string会被转成char*(输入正常),但输出的StringBuilder会按ANSI解析wchar_t*数据,双字节被拆成单字节,自然只显示错误字符;
  • 当CharSet=Unicode时:C#的string会被转成wchar_t*,但C++函数接收的是char*,双字节数据被当成单字节解析,输入自然乱码,而输出的StringBuilder按Unicode处理wchar_t*,所以输出正常。

除此之外,你的C++代码还有两个关键错误:

  1. 冗余且危险的字符串转换:把char*转成wchar_t*再转回std::string,完全没必要,还会破坏非ANSI字符的编码;
  2. swprintf调用错误:直接把加密后的宽字符串当成格式字符串传入,swprintf会把字符串里的%等字符当成格式占位符解析,导致输出乱码甚至崩溃,正确的用法应该是传入L"%s"作为格式字符串。

推荐修复方案(统一Unicode+Base64编码)

加密后的二进制数据不适合直接用宽字符串存储(可能包含非法Unicode字节),而且为了支持多语言字符,推荐统一使用Unicode字符集,同时将加密结果转成Base64字符串(二进制转ASCII,避免编码问题)。

1. 修改C++ DLL代码

#include <windows.h>
#include <string>
#include <vector>

// 假设你已实现以下函数
std::string encrypt(const std::string& plaintext, const std::string& key, const std::string& iv);
std::string base64_encode(const std::string& data);

extern "C" __declspec(dllexport) void aes_crypter(const wchar_t* string_in, wchar_t* string_out, size_t out_buffer_size) {
    // 1. 将输入宽字符串转成UTF-8字节流(适合加密处理,支持全语言)
    int utf8_len = WideCharToMultiByte(CP_UTF8, 0, string_in, -1, nullptr, 0, nullptr, nullptr);
    if (utf8_len == 0) {
        string_out[0] = L'\0';
        return;
    }
    std::vector<char> utf8_buf(utf8_len);
    WideCharToMultiByte(CP_UTF8, 0, string_in, -1, utf8_buf.data(), utf8_len, nullptr, nullptr);
    std::string plaintext(utf8_buf.data());

    // 2. 执行AES加密
    std::string encrypted_data = encrypt(plaintext, "abcdefghijklmnopqrstuvwxyz123412", "612345601234512");

    // 3. 二进制加密结果转Base64字符串(避免二进制数据的编码冲突)
    std::string base64_result = base64_encode(encrypted_data);

    // 4. Base64字符串转回宽字符串输出
    int wide_len = MultiByteToWideChar(CP_UTF8, 0, base64_result.c_str(), -1, nullptr, 0);
    if (wide_len == 0) {
        string_out[0] = L'\0';
        return;
    }
    // 确保不超出缓冲区大小
    wide_len = wide_len > out_buffer_size ? out_buffer_size : wide_len;
    MultiByteToWideChar(CP_UTF8, 0, base64_result.c_str(), -1, string_out, wide_len);
    string_out[out_buffer_size - 1] = L'\0'; // 强制添加终止符,防止溢出
}

2. 修改C#调用代码

using System;
using System.Runtime.InteropServices;
using System.Text;

class AESHelper {
    [DllImport("simpleAES.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
    private static extern void aes_crypter(string string_in, StringBuilder string_out, int out_buffer_size);

    public static string EncryptString(string input) {
        const int BufferSize = 4096;
        var resultBuilder = new StringBuilder(BufferSize);
        aes_crypter(input, resultBuilder, BufferSize);
        return resultBuilder.ToString();
    }
}

临时快速修复(最小改动)

如果你暂时不想重构加密逻辑,只需要解决当前调用问题,可以做两处小修改:

  1. 修正C++里的swprintf调用:
    swprintf(string_out, 4096, L"%s", output_crypt); // 添加L"%s"作为格式字符串
    
  2. 把C++函数的输入参数改成const wchar_t*,统一用Unicode:
    extern "C" __declspec(dllexport) void aes_crypter(const wchar_t* string_in, wchar_t* string_out) {
        std::wstring ws(string_in);
        std::string str(ws.begin(), ws.end());
        auto encr = encrypt(str, X_KEY, X_PSS);
        std::wstring widestr(encr.begin(), encr.end());
        swprintf(string_out, 4096, L"%s", widestr.c_str());
    }
    
  3. C#调用保持CharSet=Unicode:
    [DllImport("simpleAES.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
    private static extern void aes_crypter(string string_in, StringBuilder string_out);
    

注意:这种临时方案只适合输入是ASCII字符的场景,非ASCII字符会丢失,长期来看还是推荐用UTF-8+Base64的方案。

内容的提问来源于stack exchange,提问作者Samuel Hardson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:08:14