如何在 C# 中编组 wstring *?
How do I marshal a wstring * in C#?
我在 C++ 中有一个函数 _GetFileList,我试图将 return list/array 个字符串转换为 C# 代码。我没有嫁给 wstring *
或任何其他类型,这就是我找到的示例的做法,但我试图将它变成 return 一个 list/array 而不仅仅是一个单个字符串。我如何将其编组为在 C# 端有多个字符串?
C++代码:
extern "C" __declspec(dllexport) wstring * __cdecl _GetFileList(int &size){
std::list<wstring> myList;
//Code that populates the list correctly
size = myList.size();
wstring * arr = new wstring[size];
for( int i=0;i<size;i++){
arr[i] = myList.front();
myList.pop_front();
}
return arr;
}
我在 C# 中这样调用它:
[DllImport(@"LinuxDirectory.Interface.dll")]
private static extern IntPtr _GetFileList(ref int size);
public bool GetFileList() {
int size = 0;
IntPtr ptr = _GetFileList( ref size );
//WHAT DO I DO HERE TO GET THE LIST OF STRINGS INTO SOMETHING I CAN READ?
}
我试过使用 Marshal.PtrToStringUni、Marshal.PtrToStringAnsi 和结构一,但似乎无法获得正确的语法。
你不知道。 P/Invoke 只能处理与 C 兼容的函数签名,这意味着指针必须指向普通旧数据,而不是完整的 C++ 类。
如果可以重写 C++ 代码,将其更改为调用 SysAllocString
和 return 一个 BSTR
,其中 OS 提供的字符串类型用于数据交换在用不同语言编写的组件之间。 P/invoke 已经拥有接收 BSTR
的所有正确魔法,只需在 p/invoke 声明中使用 C# string
类型。
如果不能更改 C++ 签名,则必须将其包装。要么使用 C++/CLI,它可以处理 C++ 类 以及 .NET,要么使用标准 C++ 并创建 return 一个 BSTR
,从 std::wstring
复制数据.
对于多个字符串,您可以使用 OS 提供的数组类型 (SAFEARRAY),它能够在内部携带 BSTR 并且再次与语言无关。或者使用适当的(不会自然出现在数据中的)分隔符来连接和拆分可能会更容易。
这里有一些非常棒的信息:https://msdn.microsoft.com/en-us/magazine/mt795188.aspx
运行 .NET Framework(Microsoft 实现,在 Windows 上),您可以使用助手 类:
#include <windows.h>
#include <atlbase.h>
#include <atlsafe.h>
#include <string>
extern "C" __declspec(dllexport) LPSAFEARRAY GetFileList()
{
std::vector<std::wstring> myList;
//Code that populates the list correctly
size = myList.size();
CComSafeArray<BSTR> sa(size);
int i=0;
for( auto& item : myList ) {
CComBSTR bstr(item.size(), &item[0]);
sa.SetAt(i++, bstr.Detach()); // transfer ownership to array
}
return sa.Detach(); // transfer ownership to caller
}
在 C# 端,p/invoke 处理所有问题:
[DllImport("NativeDll.dll"),
return:MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)]
public static extern string[] GetFileList();
你的问题表明你可能在 Linux。不幸的是,我找到的文档似乎说 Mono 的 p/invoke 根本不知道如何处理可变大小的数组。所以你不得不手工做所有事情,包括释放(你问题中的代码泄漏 new wstring[size]
——C# 完全不知道如何调用 C++ delete[]
运算符)。看看 Mono.Unix.UnixMarshal.PtrToStringArray
.
我在 C++ 中有一个函数 _GetFileList,我试图将 return list/array 个字符串转换为 C# 代码。我没有嫁给 wstring *
或任何其他类型,这就是我找到的示例的做法,但我试图将它变成 return 一个 list/array 而不仅仅是一个单个字符串。我如何将其编组为在 C# 端有多个字符串?
C++代码:
extern "C" __declspec(dllexport) wstring * __cdecl _GetFileList(int &size){
std::list<wstring> myList;
//Code that populates the list correctly
size = myList.size();
wstring * arr = new wstring[size];
for( int i=0;i<size;i++){
arr[i] = myList.front();
myList.pop_front();
}
return arr;
}
我在 C# 中这样调用它:
[DllImport(@"LinuxDirectory.Interface.dll")]
private static extern IntPtr _GetFileList(ref int size);
public bool GetFileList() {
int size = 0;
IntPtr ptr = _GetFileList( ref size );
//WHAT DO I DO HERE TO GET THE LIST OF STRINGS INTO SOMETHING I CAN READ?
}
我试过使用 Marshal.PtrToStringUni、Marshal.PtrToStringAnsi 和结构一,但似乎无法获得正确的语法。
你不知道。 P/Invoke 只能处理与 C 兼容的函数签名,这意味着指针必须指向普通旧数据,而不是完整的 C++ 类。
如果可以重写 C++ 代码,将其更改为调用 SysAllocString
和 return 一个 BSTR
,其中 OS 提供的字符串类型用于数据交换在用不同语言编写的组件之间。 P/invoke 已经拥有接收 BSTR
的所有正确魔法,只需在 p/invoke 声明中使用 C# string
类型。
如果不能更改 C++ 签名,则必须将其包装。要么使用 C++/CLI,它可以处理 C++ 类 以及 .NET,要么使用标准 C++ 并创建 return 一个 BSTR
,从 std::wstring
复制数据.
对于多个字符串,您可以使用 OS 提供的数组类型 (SAFEARRAY),它能够在内部携带 BSTR 并且再次与语言无关。或者使用适当的(不会自然出现在数据中的)分隔符来连接和拆分可能会更容易。
这里有一些非常棒的信息:https://msdn.microsoft.com/en-us/magazine/mt795188.aspx
运行 .NET Framework(Microsoft 实现,在 Windows 上),您可以使用助手 类:
#include <windows.h>
#include <atlbase.h>
#include <atlsafe.h>
#include <string>
extern "C" __declspec(dllexport) LPSAFEARRAY GetFileList()
{
std::vector<std::wstring> myList;
//Code that populates the list correctly
size = myList.size();
CComSafeArray<BSTR> sa(size);
int i=0;
for( auto& item : myList ) {
CComBSTR bstr(item.size(), &item[0]);
sa.SetAt(i++, bstr.Detach()); // transfer ownership to array
}
return sa.Detach(); // transfer ownership to caller
}
在 C# 端,p/invoke 处理所有问题:
[DllImport("NativeDll.dll"),
return:MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)]
public static extern string[] GetFileList();
你的问题表明你可能在 Linux。不幸的是,我找到的文档似乎说 Mono 的 p/invoke 根本不知道如何处理可变大小的数组。所以你不得不手工做所有事情,包括释放(你问题中的代码泄漏 new wstring[size]
——C# 完全不知道如何调用 C++ delete[]
运算符)。看看 Mono.Unix.UnixMarshal.PtrToStringArray
.