从C ++函数返回字符串到VB .Net [英] return string from c++ function to VB .Net

查看:119
本文介绍了从C ++函数返回字符串到VB .Net的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图从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

返回类型或编组是否存在问题?

解决方案

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可能会使用unicode字符,因此最好指定这一点,您可能不需要将其放入,但我想使这些内容明确.

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

Dim buffer As StringBuilder = New StringBuilder(512)

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

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

I am trying to call C++ function from VB.Net code which returns string using P/Invoke, but it is returning only single character.

C function Declaration

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

C function Definition

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

VB.Net Code

    <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

Is there any problem with return type or Marshalling?

解决方案

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

Returning a pointer like this is rather dangerous, as it is not clear who owns the memory and thus who should take responsibility for freeing it.

It would be safer to create the buffer in your VB code and pass it into the DLL where the value can be memcpy'ed in. So we could rewrite the C++ side like:

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); 
}

And then redo the VB code as follows:

<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

I have added CharSet:=CharSet.Ansi to the DllImport. Your C++ code is not using unicode characters, whereas VB probably will be, so best specify that, you probably don't need to put it in but I like to make these things explicit.

Note the use of StringBuilder instead of String as strings are immutable in VB. Finally, you will need to be careful to allocate enough space in your string builder for the description:

Dim buffer As StringBuilder = New StringBuilder(512)

You can either do this by using a large number in your VB code, as I have just done. This will however, cause problems if your C++ code ever copies more characters than you allocated.

Other better options would either be to pass in the buffer size to the C++ code so that it knows how much it is allowed to write, or to have a get size function in the C++ code that can be used to determine how much space should be allocated for the buffer.

这篇关于从C ++函数返回字符串到VB .Net的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆