从c ++函数返回字符串到VB .Net

时间:2011-11-08 11:10:05

标签: c++ vb.net pinvoke

我试图从VB.Net代码调用C ++函数,它使用P / Invoke返回字符串,但它只返回单个字符。

C函数声明

  extern "C" __declspec(dllexport) LPSTR Get_GetDescription(HANDLE)

C函数定义

  LPSTR Get_GetDescription(HANDLE resultBreakDown){
    return LPSTR(((CalcBreakDown*)resultBreakDown)->GetDescription().c_str()); 
}

VB.Net代码

    <DllImport("FeeEngineDll.dll", CallingConvention:=CallingConvention.Cdecl)> _
    Public Shared Function Get_GetDescription(ByVal resultBreakDown As IntPtr, ByVal indexSubs As Integer, ByVal indexLine As Integer) As <MarshalAsAttribute(LPStr)> String
    End Function

返回类型或编组有问题吗?

1 个答案:

答案 0 :(得分:4)

extern "C" __declspec(dllexport) LPSTR Get_GetDescription(HANDLE)

返回这样的指针是相当危险的,因为不清楚谁拥有记忆,因此谁应该负责释放它。

在VB代码中创建缓冲区并将其传递到可以memcpy的值的DLL中会更安全。所以我们可以重写C ++方面:

extern "C" __declspec(dllexport) void Get_GetDescription(HANDLE, LPSTR)

void Get_GetDescription(HANDLE resultBreakDown, LPSTR buffer){
    memcpy(buffer,
           ((CalcBreakDown*)resultBreakDown)->GetDescription().c_str(),
           ((CalcBreakDown*)resultBreakDown)->GetDescription().length()+1); 
}

然后按如下方式重做VB代码:

<DllImport("FeeEngineDll.dll", CharSet:=CharSet.Ansi, CallingConvention:=CallingConvention.Cdecl)> _
Public Shared Sub Get_GetDescription(ByVal resultBreakDown As IntPtr, <MarshalAs(UnmanagedType.LPStr)> ByVal szFilename As StringBuilder)
End Sub

我已将CharSet:=CharSet.Ansi添加到DllImport。你的C ++代码不是使用unicode字符,而VB可能是,所以最好指定,你可能不需要把它放进去,但我喜欢把这些东西弄清楚。

注意使用StringBuilder而不是String因为字符串在VB中是不可变的。最后,您需要注意在字符串构建器中为描述分配足够的空间:

Dim buffer As StringBuilder = New StringBuilder(512)

您可以通过在VB代码中使用大量数字来执行此操作,就像我刚刚完成的那样。但是,如果您的C ++代码复制的字符多于您分配的字符数,则会导致问题。

其他更好的选择是将缓冲区大小传递给C ++代码,以便它知道允许写入多少,或者在C ++代码中有一个get size函数,可用于确定多少应该为缓冲区分配空间。