I couldn't get the below p/invoke code working, please help, thanks.
vertices below stays as null after the c++ call. I've tried to use IntPtr instead of string[], IntPtr stays as 0 after c++ call.
c++ code
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# code
[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();
}
I don't think it can be done properly this way, because you have no way of specifying that P/Invoke must free the memory with delete[]
calls after converting it to managed strings.
However, with a SAFEARRAY
of BSTR
s and the MarshalAs
attribute, you may have a fighting chance.
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
);
Of you may still use IntPtr
(and do the marshaling manually on the C# side, while exporting a delete_strings
function), but remember that your function must take its char**
by reference, or it can't actually modify it.