2013-10-09 42 views
1

我无法得到下面的p/invoke代码工作,请帮助,谢谢。pinvoke - 传递一个字符串[]作为参数

下面的顶点在C++调用后保持为空。我试过使用IntPtr而不是string [],IntPtr在C++调用后保持为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#代码

[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(); 
} 
+0

无法看到您的C++代码的问题。我复制/粘贴它,并替换传递参数与本地字符**,它为我工作得很好。你如何调用函数compute_similarity()? (你传递给它的是什么?) –

+1

这段代码不能可靠地从C++调用,当你从C#调用它时,它不会变得更好。调用者*有*调用delete []来获取释放数组的内存。这有时可以从C++起作用,你需要相当的运气并仔细控制DLL和客户端代码所使用的编译器版本。它保证不能从C#工作,它不知道如何调用C++ delete []运算符。你得到0是因为你的C++代码不好,vertices参数应该是char ***。 –

+0

首先让你的函数适用于C++客户端。它看起来像你需要char *** - 伟大的设计! –

回答

2

我不认为它能够正确做到这样,因为你没有指定的P/Invoke必须释放内存的方式在将其转换为托管字符串后调用delete[]

但是,的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(和做手工的C#侧封送处理,而导出delete_strings功能),但请记住,你的函数必须接受它的char**通过引用,或者它实际上不能修改它。

相关问题