我试图做出如何的字符串传递到并从C ++ DLL在C#中的绝对简单的小例子。
我的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。这似乎是它证明是对付最琐碎的事情,但我完全被卡住就可以了。当我试图做类似的实验功能“添加”那花了两个双打和返回的双重我没有问题。
你不能跨越互操作边界传递一个C ++ std::string
。您不能创建那些在您的C#代码之一。所以,你的代码不能正常工作。
您需要在互操作界面使用互操作友好的类型。例如,空终止字符数组。当你分配和释放在同一个模块在存储效果很好。所以,从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);
这是我喜欢最简单的方法 - 通过在一个字符串,并使用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");
}
}