使用 dllexport 传递 std::string

Passing std::string with dllexport

本文关键字:string std 传递 dllexport 使用      更新时间:2023-10-16

我正在尝试建立某种C++"桥接",以将一端的非托管C++ dll(无需修改其代码(连接到使用 DllImport 进行各种导入的 C# 包装器。

我能够使用 char 指针将 C# 字符串传递给我的桥,但接收 Dll 需要接收 std::string,所以我尝试了std::string(foo);但没有运气,它总是被转换为奇怪的字符。

结构如下:

C# 包装器

[DllImport(@"Bridge.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void initDetector(string foo, int something = 0);

C++桥

extern "C" __declspec(dllexport) void initCppClass(char* foo, int something)
{
    std::string bar = std::string(foo);
    std::cout << bar << std::endl; //Returns "foo"
    instance = new CppClass(bar, something);
}

C++ 导入的 DLL(不允许在此处更改代码(

CppClass::CppClass(std::string foo, int something)
{
    std::cout << foo << std::endl; //Returns garbage
}

请注意,此构造函数仅用于演示目的,因为我无法公开原始代码。

我最初尝试将 char* 直接传递给构造函数,但这也没有用。我在这里缺少什么吗?

我认为问题是不同的字符串编码。

尝试在 C# 中添加CharSet = CharSet.Ansi,如下所示:

[DllImport(@"Bridge.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]

但是,请阅读该C++ dll API 的文档。许多C++代码,特别是如果是跨平台代码,都需要 UTF8 编码的字符串。如果是这种情况,请将网桥更改为

extern "C" __declspec(dllexport) void initCppClass(const wchar_t* foo, int something)

并编写代码将字符串从 UTF16 编码的 C 指针转换为 UTF8 编码的 std::string,有关示例,请参阅此答案。

更新:另一个可能的原因是不同的 STL 或不同的 CRT。当您跨 DLL 边界传递 std::string 或任何其他 STL 对象对象时,您必须使用相同的编译器和相同版本,相同的构建设置(例如,在 VC++ 中,std::string 内存布局在调试和发布版本之间有所不同(,并且两个 DLL 必须动态链接到 CRT,例如 Multi-threaded DLL (/MD)