locked
VC++ 2010 DLL Functions not compatible with VB 2010 Express

    Question

  • I'm using Visual C++ 2010 Express to create a DLL and Visual Basic 2010 Express to call its functions.  In my VC++ DLL (qTest.dll) I have the following function:

    DWORD Go_Test(DWORD oddly);

    ...

    DWORD Go_Test(DWORD oddly)
    {
        if (oddly > 10)
            oddly = 3;
        else
            oddly = 5;

        return oddly;
    }

    and the code builds without problems.  In my VB code I have

    Public Declare Function Go_Test Lib "qTest.dll" (ByVal oddly As UInt32) As UInt32

    and later

    Dim odd As UInt32 = 99
    Dim pork As UInt32 = 7

    odd = Go_Test(pork)

    MsgBox("Go_Test is odd at " + Str(odd)) 'if (odd > 10) return 3; else return 5;

    But in the VB project when I press <F5> to start debugging / running the program, I get

    PInvokeStackImbalance was detected

    A call to PInvoke function 'TestPanel!TestPanel.TestPanelModule::Go_Test' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

    As you can see, my definition and invocation should match up, everything being a 32-bit unsigned integer, AFAIK.  Thoughts?  Why am I getting this error?

    • Edited by NojiRatz Tuesday, July 20, 2010 10:00 PM Better formatting
    Tuesday, July 20, 2010 9:49 PM

Answers

All replies

  • Use the DllImport attribute instead (it provides more options) and set CallingConvention:=CallingConvention.Cdecl.  This matches what the C compiler uses by default.  The default (on Windows other than Windows CE) resolves to StdCall.  (There is a long story as to why the default is StdCall even though most of Windows is written in C and C++.)

    This page which documents declare (http://msdn.microsoft.com/en-us/library/4zey12w5.aspx) shows how to convert to DllImport at the bottom. 

    The documentation for DllImport is here: http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.dllimportattribute.aspx

    • Proposed as answer by Bin-ze Zhao Monday, July 26, 2010 10:26 AM
    • Marked as answer by Alex Liang Monday, July 26, 2010 10:27 AM
    Wednesday, July 21, 2010 2:04 AM
  • Whoa...that worked!  You're a lifesaver.  I've beating my head against the wall for three days now trying to figure this one out.

     

    Thanks,

    NojiFusion

    Wednesday, July 21, 2010 4:32 PM
  • I had the similar issues with calling VC++ Win32 DLL from VB.net, it was solved with DLLimport Attribute.

     

    -Bin-ze/Alex/other experts,

    is DLLimport the only solution for this kinds of issues?

    Is anyway to link/import VC win32 DLL into VB.net project, and make DLL function call directly (some similar way like Adding reference/import namespace)?

    -NojiFusion, can you please post your final working code, so that we could learn more from your experience.

     

    Thanks for sharing. It helps people who you might not know..................

     

    Wednesday, March 23, 2011 12:48 AM
  • Here's my final code, after all the necessary embellishments:

    Module NameModule
      <DllImport("myGood.dll", EntryPoint:="Good_GetNumberOfNames", SetLastError:=True, CharSet:=CharSet.Unicode, ExactSpelling:=True, CallingConvention:=CallingConvention.Cdecl)>
      Public Function Good_GetNumberOfNames() As Integer
        'Intentionally left blank
      End Function
      <DllImport("myGood.dll", EntryPoint:="Good_GetNameString", SetLastError:=True, CharSet:=CharSet.Unicode, ExactSpelling:=True, CallingConvention:=CallingConvention.Cdecl)>
      Public Function Good_GetNameString(ByVal unitNumber As Integer, ByRef nameString As Byte, ByVal flags As Integer) As Integer
        'Intentionally left blank
      End Function
      <DllImport("myGood.dll", EntryPoint:="Good_Open", SetLastError:=True, CharSet:=CharSet.Unicode, ExactSpelling:=True, CallingConvention:=CallingConvention.Cdecl)>
      Public Function Good_Open(ByVal unitNumber As UInt32, ByRef unitHandle As UInt32) As Integer
        'Intentionally left blank
      End Function
      <DllImport("myGood.dll", EntryPoint:="Good_Close", SetLastError:=True, CharSet:=CharSet.Unicode, ExactSpelling:=True, CallingConvention:=CallingConvention.Cdecl)>
      Public Function Good_Close(ByVal unitHandle As UInt32) As Integer
        'Intentionally left blank
      End Function
      <DllImport("myGood.dll", EntryPoint:="Good_Read", SetLastError:=True, CharSet:=CharSet.Unicode, ExactSpelling:=True, CallingConvention:=CallingConvention.Cdecl)>
      Public Function Good_Read(ByVal unitHandle As UInt32, ByRef buffer As Byte, ByVal bytesToRead As Integer, ByRef bytesReturned As Integer) As Integer
        'Intentionally left blank
      End Function
    End Module
    NojiRatz / NojiFusion / NojiMSDN
    Thursday, March 24, 2011 12:44 AM