pinvoke - 将字符串[]作为out参数传递

时间:2013-10-09 13:43:14

标签: c# c++ arrays pinvoke

我无法使下面的p / invoke代码正常工作,请帮助,谢谢。

在c ++调用之后,

下面的顶点保持为null。我尝试使用IntPtr而不是string [],在c ++调用后IntPtr保持为0。

c ++代码

extern "C"  __declspec(dllexport)
float compute_similarity(char** vertices)
{       
  vertices = new char*[2];
  vertices[0] = new char[3];
  vertices[1] = new char[3];

  strcpy(vertices[0], "he");
  strcpy(vertices[1], "ha");

  return 1.01;
}

c#c​​ode

[DllImport("demo.dll", EntryPoint = "compute_similarity", 
    CallingConvention =  CallingConvention.Cdecl,   CharSet = CharSet.Ansi)]
static extern float compute_similarity(out string[] vertices);  
//also tried 'static extern float compute_similarity(out IntPtr vertices);'  

public string Func()
{
  string[] vertices; //also tried 'IntPtr vertices'
  float sim = compute_similarity(out vertices); 
  //break point here vertices stays null(or 0 for IntPtr)
  return sim.ToString();
}

1 个答案:

答案 0 :(得分:2)

我不认为可以通过这种方式正确完成,因为您无法指定P / Invoke在将其转换为托管字符串后必须使用delete[]调用释放内存。

但是,使用SAFEARRAY BSTRMarshalAs属性,您可能会有战斗机会。

extern "C"  __declspec(dllexport)
float compute_similarity(SAFEARRAY** vertices)
{
    SAFEARRAY *pArr = SafeArrayCreateVector(VT_BSTR, 0, 2);
    if(pArr != NULL)
    {
        LONG index = 0;
        BSTR bs = SysAllocString(L"he");
        SafeArrayPutElement(pArr, &index, bs);
        SysFreeString(bs);
        index = 1;
        bs = SysAllocString(L"ha");
        SafeArrayPutElement(pArr, &index, bs);
        SysFreeString(bs);
    }
    *vertices = pArr;
    return 1.01;
}
[DllImport("demo.dll", EntryPoint = "compute_similarity", CallingConvention =  CallingConvention.Cdecl)]
static extern float compute_similarity(
    [Out, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_BSTR)] out string[] vertices
);  

您可能仍然使用IntPtr(并在导出delete_strings函数时在C#端手动执行编组),但请记住,您的函数必须通过引用获取其char** ,或者它实际上无法修改它。