Search code examples
c#c++vb.netdlldllimport

how to declare function in vb.net to call c++ dll


I need to call a function located in a C++ dll from a VB.NET project.

The definition in C++ dll documentation is:

HRESULT GetStatus(LPBYTE lpSize, LPBYTE lpStatus, HWND hWnd = 0)

lpSize Data: size of lpStatus
lpStatus: Specify a pointer of an area to store the Device Status.
The Status and following data are stored.
255 bytes of space is required to store data

I declare the function like this

<DllImport("cplusplusdll.dll", CharSet:=CharSet.Ansi, CallingConvention:=CallingConvention.StdCall, EntryPoint:="GetStatus")>
Public Function GetStatus(ByVal lpSize As String, ByRef lpStatus As String, ByVal hwnd As Long) As Integer
End Function

And I call it like this:

Dim status As String
result = GetStatus("255", status, 0)

but when I call, I get an error about pinvoikeStackImbalance, pinvoke signature not match... seems the definition is not ok...

I've tried lot of combinations but without success. Any help will be appreciated.
Thanks in advance.


Solution

  • LPBYTE would normally be declared ByVal lpSize As Byte() so:

    Public Function GetStatus(ByVal lpSize As Byte(), ByRef lpStatus As Byte(), ByVal hwnd As Long) As Integer
    

    Check the C++ function is actually StdCall, it may be CDecl.


    EDIT Looking at the small amount of info you provided, I very much doubt that lpSize is declared LPBYTE, as it represents the length of the array given in lpStatus. Also, hWnd should be an IntPtr

    Here, it appears you are trying to receive a string in the space provided for in lpStatus. We can do this with Marshal.AllocHGlobal, but an easier method using StringBuilder is available. Do NOT use String for this:

    <DllImport("cplusplusdll.dll", CharSet:=CharSet.Ansi, _
    CallingConvention:=CallingConvention.StdCall, EntryPoint:="GetStatus")>
        Public Function GetStatus(ByVal lpSize As Integer, <Out> ByVal lpStatus As StringBuilder, ByVal hwnd As IntPtr) As Integer
        End Function
    
    Dim status As New StringBuilder(255)
    result = GetStatus(status.Length, status, 0)
    ```
    
    We can also get the `HRESULT` marshaled directly to an exception, if you would like:
    ````vb
    <DllImport("cplusplusdll.dll", CharSet:=CharSet.Ansi, _
    CallingConvention:=CallingConvention.StdCall, EntryPoint:="GetStatus", _
    PreserveSig = False)>
        Public Sub GetStatus(ByVal lpSize As Integer, <Out> ByVal lpStatus As StringBuilder, ByVal hwnd As IntPtr)
        End Sub