将C#字符串传递给C ++并将C ++结果(字符串,字符*等)传递给C#

我尝试了不同的东西,但我对Interop很生气。

(这里的单词string不是指变量类型,而是“char的集合”):我有一个非管理的C ++函数,在dll中定义,我试图从C#访问,这个函数有一个字符串参数和一个字符串返回值,如下所示:

string myFunction(string inputString) { } 

C ++方面应该是什么字符串? 和C#one? 什么参数需要DllImport呢?

我发现最好的方法是更清楚地了解这里发生了什么。 在这种情况下,可能不建议将字符串作为返回类型。

一种常见的方法是让C ++端传递缓冲区和缓冲区大小。 如果它不足以让GetString放入其中,则修改bufferSize变量以指示适当的大小。 然后,调用程序(C#)将缓冲区的大小增加到适当的大小。

如果这是您导出的dll函数(C ++):

 extern "C" __declspec void GetString( char* buffer, int* bufferSize ); 

匹配C#将如下:

 void GetString( StringBuilder buffer, ref int bufferSize ); 

因此,要在C#中使用它,您将执行以下操作:

 int bufferSize = 512; StringBuilder buffer = new StringBuilder( bufferSize ); GetString( buffer, ref bufferSize ); 

我知道这样做的唯一好方法是使用Managed C ++ Extensions编写.NET C ++包装类,并在.NET C ++对象中调用您的本机C ++代码。 托管扩展中有一些函数可以将System.String转换为char *或任何其他类型的非托管字符串。

基本上,您使用C ++创建.NET类并从程序集中公开它,并在内部到该程序集,您可以调用本机C ++代码。 另一种方法是使用P / Invoke将纯C函数添加到C ++代码中,然后从C#调用C代码并让C函数调用C ++代码。 这将工作,但我倾向于尝试尽可能多地使用托管代码。

将字符串从C ++传递回C#的最大问题是内存分配。 GC应该能够知道如何清理为此字符串分配的内存。 由于C#具有广泛的COm互操作支持,因此它确实了解COM BSTR以及如何分配和释放这些。 因此,最简单的方法是在C ++端使用BSTR ,在C#端使用string

注意,使用BSTR并不意味着您的函数必须通过COM公开。

“字符串”返回值是问题所在。 P / Invoke marshaller将在你返回的指针上调用CoTaskMemFree()。 除非您在C / C ++代码中使用CoTaskMemAlloc()来分配字符串缓冲区,否则这不会很好。 这是一件相当不寻常的事情。

最好的解决方案是允许代码的调用者将指向缓冲区的指针和缓冲区长度作为参数传递给您。 这样所有内存分配都在一方发生。 斯科特告诉你如何做到这一点。

我必须将unicode C#字符串转换为多字节表示,以便在c ++中转换为char *(这是部分单向解决方案)

我发现以下内容非常有用

 string st; IntPtr stPtr = Marshal.StringToHGlobalAnsi(st); // Do your thing in C++ Marshal.FreeHGlobal(stPtr); 

这可能是低效的,而不是C#方式,我是C#的新手。