从C#调用的C++中,返回一个长度先验未知的字符串
本文关键字:一个 字符串 未知 C++ 调用 返回 | 更新日期: 2023-09-27 18:28:16
我到处寻找问题的答案,但所有的解决方案都是不可接受的、不适用的和/或令人困惑的。
我需要将C++
中实现的函数的字符串返回到C#
中的调用代码。
返回的字符串需要作为参数而不是返回值返回,因为我需要为某些函数传递/返回多个字符串。字符串的长度各不相同,所以我不能只分配缓冲区等。
如有任何帮助,我们将不胜感激。
注:Justin和/或其他人发布和提到的解决方案不是我用例的解决方案。正如我在问题中所说,在调用C++代码之前,我不知道字符串的大小。我无法预先分配StringBuffer并将其传递给C++代码
ref IntPtr
。因此:
static extern void DoSomething(ref IntPtr returnedString);
所以你调用它并得到一个字符串:
IntPtr pstr;
DoSomething(ref pstr);
string theString = Marshal.PtrToStringAnsi(pstr);
但是,重要的是要记住,返回的指针是由C++代码分配的。如果你想解除分配,你需要调用C++代码来完成
您可能还想了解Marshal.PtrToStringAuto
和其他类似的函数。
还要注意,这会将数据从指针复制到字符串。如果你想在适当的位置引用字符串,你必须使用IntPtr
和Marshal
类,或者深入研究不安全代码和指针的奇妙世界。
添加到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++中,可以使用SysAllocString
或SysAllocStringLen
。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);