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

通过P/Invoke从C#向C++传递字符串的问题求助

问题根源与解决方案

你遇到的核心问题是:C++的std::wstring是标准库的自定义类类型,而.NET的P/Invoke机制只能直接处理POD(Plain Old Data)类型或COM兼容类型。直接将C#的ref string与C++的std::wstring&绑定,会因为内存布局、内存管理机制完全不匹配,导致调用失败、内存损坏甚至程序崩溃。

下面给你两种最实用的解决方案,你可以根据现有代码结构选择:


方案1:改用C风格宽字符串(最推荐,无额外依赖)

这种方式直接用P/Invoke原生支持的wchar_t*作为参数,避免C++类类型的跨语言绑定问题。

调整后的C++代码

头文件:

namespace NMSP {
    extern "C" {
        // 传入缓冲区指针和缓冲区大小,确保写入不会溢出
        __declspec(dllexport) int MyCPPMethod(wchar_t* StrCode, size_t bufferSize);
    }
}

源文件:

#include <cstring>

__declspec(dllexport) int NMSP::MyCPPMethod(wchar_t* StrCode, size_t bufferSize) {
    const wchar_t* result = L"12345";
    // 使用wcscpy_s保证安全,避免缓冲区溢出
    if (bufferSize > wcslen(result)) {
        wcscpy_s(StrCode, bufferSize, result);
    }
    return 1;
}

对应的C#代码

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

class NativeMethods
{
    [DllImport(@"MyExternal.dll", CharSet = CharSet.Unicode)]
    static extern int MyCPPMethod(StringBuilder strCode, int bufferSize);
}

// 调用示例
var codeBuffer = new StringBuilder(256); // 预先分配足够大的缓冲区
int returnValue = NativeMethods.MyCPPMethod(codeBuffer, codeBuffer.Capacity);
string finalCode = codeBuffer.ToString();

为什么用StringBuilder? 因为C#的string是不可变的,底层内存由CLR管理;而StringBuilder会分配一块可修改的原生内存缓冲区,正好匹配C++端wchar_t*的写入需求。


方案2:通过BSTR做中间适配(兼容现有std::wstring代码)

如果你不想修改原有的std::wstring版本方法,可以封装一个适配层,用COM兼容的BSTR类型作为跨语言传递的桥梁(.NET对BSTR有原生的内存管理支持)。

调整后的C++代码

#include <comutil.h>
#include <string>
#pragma comment(lib, "comsuppw.lib") // 链接COM辅助库

namespace NMSP {
    // 原有的std::wstring方法保持不变
    int MyCPPMethod(std::wstring &StrCode) {
        StrCode = L"12345";
        return 1;
    }

    // 对外导出的适配方法,用BSTR传递字符串
    extern "C" {
        __declspec(dllexport) int MyCPPMethodWrapper(BSTR* outStr);
    }

    __declspec(dllexport) int MyCPPMethodWrapper(BSTR* outStr) {
        std::wstring tempStr;
        int result = MyCPPMethod(tempStr);
        // 将std::wstring转换为BSTR,由.NET负责释放内存
        *outStr = SysAllocString(tempStr.c_str());
        return result;
    }
}

对应的C#代码

using System.Runtime.InteropServices;

class NativeMethods
{
    [DllImport(@"MyExternal.dll", CharSet = CharSet.Unicode)]
    static extern int MyCPPMethodWrapper([MarshalAs(UnmanagedType.BStr)] out string strCode);
}

// 调用示例
int returnValue = NativeMethods.MyCPPMethodWrapper(out string finalCode);

内存管理说明:SysAllocString分配的BSTR内存,.NET的Marshal会在out string参数销毁时自动释放,不需要你手动调用SysFreeString。


内容的提问来源于stack exchange,提问作者Dave Gahan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:12:18