我有一个第三方库,其中有一个类,其中构造函数采用std::wstring
。
构造函数由头文件中的第三方定义:
Something(const std::wstring &theString);
我的头文件包含:
extern "C" __declspec(dllexport) ThirdParty::Something* createSomething(const std::wstring &theString);
我的实现是这样的:
ThirdParty::Something* Bridge::createSomething(const std::wstring &theString) {
return new ThirdParty::Something(theString);
}
现在我的C#示例程序中有:
[DllImport("Bridge.dll", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Unicode)]
public static extern IntPtr createSomething(StringBuilder theString);
当我现在尝试将其称为:
IntPtr ip = createSomething(new StringBuilder("foo"));
我得到AccessViolationException
。当我使用String
代替StringBuilder
时,我会获得SEHException
。
我错过了什么或做错了什么?
编辑当我在return 0
函数中createSomething
时,我在使用StackImbalanceException
时得到String
。
答案 0 :(得分:2)
我不相信.Net marshaller开箱即可支持C ++ ABI。
您需要将.Net字符串封送到wchar_t*
,然后在本机端创建std::wstring
。
或者你可以使用C ++ / CLI(假设msvc)为你调解两个(通过marshal_as
),它理解.Net字符串并有编组来编组std::wstring
。 Microsoft提供了几个标准编组程序,请参阅他们的overview here。
我的经验一般是在这些情况下C ++ / CLI存根更整洁,更容易(这里你的里程会有所不同),否则你可以尝试为第三方库提供一个简单的C风格的API你。
您的示例代码提示可能已由您控制的Bridge
段代码。考虑尽可能简单地保持网桥中的接口(内置类型,POD等),它应该简化第三方库的集成。
值得注意的是,如果你要链接第三方的C ++库,那就是使用相同的编译器,设置,调用约定和运行时等。做,否则你仍然会遇到ABI问题。为外部库提供导出C ++接口(包括STL)并不总是一个好主意。
基本上有几种方法可以将这些代码链接在一起,你必须选择一个适合所用工具链的方法。
答案 1 :(得分:2)
在DLL接口边界处拥有STL类是非常脆弱和高度约束,例如,您必须注意DLL及其客户端都是使用相同的 C ++编译器版本,带有相同的开关,与CRT的相同的风格链接等。 而且,它在本机C ++和C#之间“开箱即用”。
对于C ++和.NET互操作,我建议您使用 C ++ / CLI 在本机C ++代码组件和.NET C#代码之间构建桥接层。
如果您选择这样做,要在本机C ++代码(例如使用std::wstring
)和.NET代码(使用.NET的托管String
)之间编组字符串,您可以使用由微软并在此处列出:
例如,要从.NET托管字符串转换为本机C ++ std::wstring
,您可能希望使用以下代码:
#include <string>
#include <msclr\marshal_cppstd.h>
System::String^ managedString = "Connie";
std::wstring nativeString
= msclr::interop::marshal_as<std::wstring>(managedString);
答案 2 :(得分:-1)
解决方案更简单,更简单!我刚忘了__stdcall
,需要使用wchar_t
。
我的标题条目现在看起来像:
extern "C" __declspec(dllexport) ThirdParty::Something* __stdcall createSomething(wchar_t* theString);
实施也是如此:
ThirdParty::Something* __stdcall Bridge::createSomething(wchar_t* theString) {
std::wstring theWString = std::wstring(theString);
return new ThirdParty::Something(theWString);
}
现在我可以传递String
和StringBuilder
s。