从C#调用的C++中,返回一个长度先验未知的字符串

本文关键字:一个 字符串 未知 C++ 调用 返回 | 更新日期: 2023-09-27 18:28:16

我到处寻找问题的答案,但所有的解决方案都是不可接受的、不适用的和/或令人困惑的。

我需要将C++中实现的函数的字符串返回到C#中的调用代码。

返回的字符串需要作为参数而不是返回值返回,因为我需要为某些函数传递/返回多个字符串。字符串的长度各不相同,所以我不能只分配缓冲区等。

如有任何帮助,我们将不胜感激。

注:Justin和/或其他人发布和提到的解决方案不是我用例的解决方案。正如我在问题中所说,在调用C++代码之前,我不知道字符串的大小。我无法预先分配StringBuffer并将其传递给C++代码

从C#调用的C++中,返回一个长度先验未知的字符串

一种方法是将参数声明为ref IntPtr。因此:
static extern void DoSomething(ref IntPtr returnedString);

所以你调用它并得到一个字符串:

IntPtr pstr;
DoSomething(ref pstr);
string theString = Marshal.PtrToStringAnsi(pstr);

但是,重要的是要记住,返回的指针是由C++代码分配的。如果你想解除分配,你需要调用C++代码来完成

您可能还想了解Marshal.PtrToStringAuto和其他类似的函数。

还要注意,这会将数据从指针复制到字符串。如果你想在适当的位置引用字符串,你必须使用IntPtrMarshal类,或者深入研究不安全代码和指针的奇妙世界。

添加到Jim Michel的答案中,我将创建一个助手函数,如

String FromCppString(IntPtr a_Pointer)
{
    String result = Marshal.PtrToStringAnsi(a_Pointer);
    FreeCppString(a_Pointer);
    return result;
}

其中FreeCppString是从C++导出的另一个函数,可以适当地释放字符串。原始的c++函数只会根据需要分配尽可能多的字符串,并将它们放入参数中。C#函数将使用FromCppString()来提取它们。

使用平台提供的可移植(多编译器多语言)字符串,明确用于在不同语言实现的组件之间传递字符串——BSTR

在C++中,可以使用SysAllocStringSysAllocStringLen。P/invoke已经知道如何处理这些问题(转换为.NET字符串并调用SysFreeString),只要您使用正确的签名即可。

extern static void DoSomething([MarshalAs(UnmanagedType.BStr)] out String returnedString);

然后简单地称之为:

string theString;
DoSomething(out theString);

就是这样,不需要特殊的转换或清理,因为p/invoke处理了它

有关更多信息,请阅读有关p/invoke 中字符串处理的MSDN页面

注意:我想链接中没有一个例子是,在这种情况下,这是C++原型

void DoSomething(__out BSTR *s);