将 C# 字符串传递给 C++ 并将 C++ 结果(字符串、字符 * .. 无论如何)传递给 C#

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2179270/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-07 00:09:05  来源:igfitidea点击:

Pass C# string to C++ and pass C++ result (string, char*.. whatever) to C#

c#c++stringinterop

提问by Smjert

I tried different things but i'm getting mad with Interop.

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

(here the word string is not referred to a variabile type but "a collection of char"): I have an unmanaged C++ function, defined in a dll, that i'm trying to access from C#, this function has a string parameter and a string return value like this:

(这里的字符串不是变量类型,而是“字符集合”):我有一个非托管 C++ 函数,定义在一个 dll 中,我试图从 C# 访问它,这个函数有一个字符串参数和像这样的字符串返回值:

string myFunction(string inputString)
{
}

What should be string in C++ side? and C# one? and what parameters need DllImport for this?

C++端的字符串应该是什么?和 C# 之一?什么参数需要 DllImport 来实现?

采纳答案by Scott Saad

What I've found to work best is to be more explicit about what's going on here. Having a string as return type is probably not recommended in this situation.

我发现最有效的是更明确地说明这里发生的事情。在这种情况下可能不建议使用字符串作为返回类型。

A common approach is to have the C++ side be passed the buffer and buffer size. If it's not big enough for what GetString has to put in it, the bufferSize variable is modified to indicate what an appropriate size would be. The calling program (C#) would then increase the size of the buffer to the appropriate size.

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

If this is your exported dll function (C++):

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

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

Matching C# would be the following:

匹配 C# 如下:

void GetString( StringBuilder buffer, ref int bufferSize );

So to use this in C# you would then do something like the following:

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

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

回答by Mike Marshall

The only good way that I know of doing this is to write a .NET C++ wrapper class using Managed C++ Extensions, and within the .NET C++ object call your native C++ code. There are functions in the managed extensions to convert a System.String to a char* or any other type of unmanaged string.

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

Basically you create a .NET class using C++ and expose it from an assembly, and internally to that assembly you can call your native C++ code. The other way is to add a pure C function to your C++ code using P/Invoke and then call your C code from C# and have your C function call your C++ code. This will work, but I tend to try to use managed code as much as possible.

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

回答by Franci Penov

The biggest problem with passing strings from C++ back to C# is the memory allocation. The GC should be able to know how to cleanup the memory allocated for this string. Since C# has extensive COm interop support, it does know about COM BSTRs and how to allocate and deallocate these. Thus the easiest way to do this would be to use BSTRon the C++ side and stringon the C# side.

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

Note, using BSTRs does not imply that your function has to be expose through COM.

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

回答by Hans Passant

The "string" return value is the problem. The P/Invoke marshaller is going to call CoTaskMemFree() on the pointer you return. That's not going to work well unless you used CoTaskMemAlloc() in your C/C++ code to allocate the string buffer. Which is a fairly unusual thing to do.

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

The best solution is to allow the caller of your code to pass a pointer to a buffer and the buffer length to you as arguments. That way all memory allocation happens on one side. Scott showed you how to do this.

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

回答by TripleS

I had to convert a unicode C# string to a multibyte representation in order to convert to char* in c++ (this is partial one way solution)

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

I found the following very useful

我发现以下非常有用

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

Marshal.FreeHGlobal(stPtr); 

This may be inefficient and not in C# manner, I'm new to C#.

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