如何在C#中编组wstring *?

时间:2017-05-09 15:26:12

标签: c# c++ marshalling intptr

我在C ++,_ GetFileList中有一个函数,我试图将一个字符串列表/数组返回给C#代码。我没有和wstring *或任何其他类型结婚,这就是我找到的例子,但是我试图让它返回一个列表/数组而不仅仅是一个字符串。我如何编组这个在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以及结构,但似乎无法正确使用语法。

1 个答案:

答案 0 :(得分:2)

你不是。 P / Invoke只能处理与C兼容的函数签名,这意味着指针必须是普通的数据,而不是完整的C ++类。

如果您可以重写C ++代码,请将其更改为调用SysAllocString并返回BSTR,这是OS提供的字符串类型,用于在以不同语言编写的组件之间进行数据交换。 P / invoke已经具有接收BSTR的所有正确魔力,只需在p / invoke声明中使用C#string类型。

如果您无法更改C ++签名,则必须将其包装起来。要么使用C ++ / CLI,它可以处理C ++类和.NET,要么使用标准C ++并创建并返回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