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

标签 c++ vb.net pinvoke

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

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

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

最佳答案

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

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

在您的 VB 代码中创建缓冲区并将其传递到 DLL 中会更安全,在 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++ 代码中使用获取大小函数来确定有多少应为缓冲区分配空间。

关于c++ - 从 C++ 函数返回字符串到 VB .Net,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8049478/

相关文章:

c# - 如何在 C# 中存储从 C++ 函数返回的 uint8_t* 变量?

c++ - OpenCL的enqueueWriteBuffer导致__memcpy_sse2_unaligned segmentation fault

c++ - 使用C++查找直线中的第三个点

vb.net - 如何在 vb.net 中备份 ms access 数据库?

.net - 用自定义异步计时器类替换 Threading.Timer?

c# - 如何将结构编码为指向结构的指针?

c++ - 在容器中存储模板化派生类

c++ - 如何在堆上使用 vector 分配矩阵

c# - 如何使用 LINQ 批量查找/匹配和更新记录?

c# - "P/Invoke entry points should exist"应该是正确的入口点