我正在尝试制作绝对最简单的最小例子,说明如何在C#中向C ++ DLL传递字符串。
我的C ++看起来像这样:
using std::string;
extern "C" {
string concat(string a, string b){
return a + b;
}
}
标题为
using std::string;
extern "C" {
// Returns a + b
__declspec(dllexport) string concat(string a, string b);
}
我的C#是
[DllImport("*****.dll", CallingConvention = CallingConvention.Cdecl)]
static extern string concat(string a, string b);
}
我称之为: Console.WriteLine(concat(“a”,“b”));
但这会产生System.AccessViolationException。这似乎是处理最琐碎的事情,但我完全坚持下去。当我尝试使用“添加”功能进行类似的实验,该功能需要两个双打并且返回一个双重而没有问题。
答案 0 :(得分:58)
您无法跨互操作边界传递C ++ std::string
。您无法在C#代码中创建其中一个。所以你的代码永远不会工作。
您需要在互操作边界使用互操作友好类型。例如,以null结尾的字符数组。当您在同一模块中分配和释放内存时,这很有效。因此,将数据从C#传递到C ++时很简单。
<强> C ++ 强>
void foo(const char *str)
{
// do something with str
}
<强> C#强>
[DllImport("...", CallingConvention = CallingConvention.Cdecl)
static extern void foo(string str);
....
foo("bar");
在另一个方向,您通常希望调用者分配缓冲区,被调用者可以写入:
<强> C ++ 强>
void foo(char *str, int len)
{
// write no more than len characters into str
}
<强> C#强>
[DllImport("...", CallingConvention = CallingConvention.Cdecl)
static extern void foo(StringBuilder str, int len);
....
StringBuilder sb = new StringBuilder(10);
foo(sb, sb.Capacity);
答案 1 :(得分:0)
这是我最简单的方法-传入一个字符串,然后使用lambda来获取响应
C#
[DllImport(@"MyDLL.dll", EntryPoint ="Foo", CallingConvention = CallingConvention.StdCall)]
public static extern void Foo(string str, ResponseDelegate response);
...
Foo("Input", s =>
{
// response is returned in s - do what you want with it
});
C ++
typedef void(_stdcall *LPEXTFUNCRESPOND) (LPCSTR s);
extern "C"
{
__declspec(dllexport) void __stdcall Foo(const char *str, LPEXTFUNCRESPOND respond)
{
// Input is in str
// Put your response in respond()
respond("HELLO");
}
}