从vb.net将参数传递给非托管C api

时间:2010-03-03 18:15:35

标签: c vb.net dll parameters unmanaged

我需要在来自vb.net的C lang编写的非托管.dll中调用函数。函数声明如下所示

LONG _stdcall ReadInfo(char * reply);

现在这个函数的行为是它在参数“reply”中复制一些数据,并返回一个数字值,表示其通过/失败状态。我如何传递一个字符串对象,以便它可以复制数据。以下是我如何访问此功能。

Dim str as String obj.ReadDeviceInfo(STR)

以这种方式访问​​库...

Public Declare Auto Function LoadLibrary Lib "kernel32" (ByVal libFilePath As String) As Integer

Public Declare Function GetProcAddress Lib "kernel32" (ByVal ModuleHandle As Integer, ByVal ProcName As String) As Integer

Public Declare Function FreeLibrary Lib "kernel32" (ByVal ModuleHandle As Integer) As Integer


Public Function ReadDeviceInfo(ByRef reply As String) As Integer

    Dim MethodPointer As Integer
    MethodPointer = GetProcAddress(ModuleHandle, "ReadInfo")
    Dim deviceInfo As ReadInfo = Marshal.GetDelegateForFunctionPointer(MethodPointer, GetType(ReadInfo))
    Return deviceInfo.DynamicInvoke(reply)

End Function

当调用完成时,返回状态绝对正常,但字符串“str”中没有任何内容。我错过了什么我不确定我作为参数传递的字符串对象。有任何想法......

3 个答案:

答案 0 :(得分:3)

.NET中的字符串是不可变的。尝试传递StringBuilder:

Public Function ReadDeviceInfo(ByRef reply As String) As Integer    
    ...

    Dim sb As New StringBuilder(1000)
    result = deviceInfo.DynamicInvoke(sb)

    reply = sb.ToString()
    Return result
End Function

来自MSDN Magazine

  

如果可以输入字符串参数   和/或输出,然后使用   System.StringBuilder类型。该   StringBuilder类型是一个有用的类   帮助您构建的库类型   字符串有效,它恰好   非常适合将缓冲区传递给本机   函数填充的函数   代表您的字符串数据。一旦   函数调用已经返回,你需要   只调用ToString   StringBuilder对象获取String   对象

或者,固定一个字符数组并传递其IntPtr。

答案 1 :(得分:0)

使用PInvoke Interop Assistant自动将C函数转换为PInvoke声明。

如果您在返回的“数据”的C中有更详细的定义,请将其放入PInvoke助手中。例如,它可以转换结构定义。

答案 2 :(得分:0)

这些常用函数演示了如何将字符串转换为字节数组,并将其作为固定IntPtr传递给托管c ++函数:

Public Function b_fromString(ByRef str As String) As Byte()
    If Not str Is Nothing Then
        Return System.Text.Encoding.Default.GetBytes(str, 0, str.Length)
    Else
        Return New Byte() {}
    End If
End Function

Public Function cString(ByRef theString As String) As IntPtr
    Dim GC As System.Runtime.InteropServices.GCHandle = System.Runtime.InteropServices.GCHandle.Alloc(b_fromString(theString & Chr(0)), System.Runtime.InteropServices.GCHandleType.Pinned)
    Dim ret As IntPtr = GC.AddrOfPinnedObject
    GC.Free()
    Return ret
End Function

此样式的函数可以在托管c ++包装器中使用:

long libinterface::loadData(System::IntPtr bytes, long length)
{   return lib->functionName((char*)bytes.ToPointer(), length);
}

使用以null结尾的字符串时,字符串长度通常是可选的。有用,如果不是完美的话。

提交以供参考。

额外 - 上传其他数组和位图:

    Public Sub New(ByRef _obj As Array, ByRef read As Boolean, ByRef write As Boolean)
        Me.size = Marshal.SizeOf(_obj(0))
        Me.count = _obj.LongLength
        Me.ptr = GCHandle.Alloc(_obj, GCHandleType.Pinned)
        Me.id = lib.addBuffer(count * size, read, write, ptr.AddrOfPinnedObject)
    End Sub

    Public Function getimgPtr(ByRef img As Bitmap) As IntPtr
        Dim f As System.Drawing.Imaging.BitmapData = img.LockBits(New Rectangle(0, 0, img.Width, img.Height), Imaging.ImageLockMode.ReadOnly, img.PixelFormat)
        getimgPtr = f.Scan0
        img.UnlockBits(f)
    End Function