I've been able to design a front-end for a C DLL, calling the DLL functions from the VB program but I'm having trouble calling the VB functions from the C DLL. Maybe I should have put this in the C forum, but I don't know.

If I have this in a VB module:

Public Declare Function callback Lib "C:\c\dll\mydll" (ByVal cbAddress As Long)

Public Sub cb()
    MsgBox "Called back."
End Sub

and callback AddressOf cb is used for the even of a button click or something. In a C DLL I would use this:

EXPORT void __stdcall callback(long cbAddress){
    typedef void (__stdcall *funcp)();
    funcp VBCallback;
    VBCallback = (funcp)cbAddress;
    VBCallback();
}

Well, the DLL compiles, and the VB program runs, but when I try to call the callback function, it says bad DLL calling convention. I tried taking the address by pointer as well (since I was able to pass values by pointer in the past, I figured it would work this time also) to no avail. And I commented out all the code in the function to see if that was the problem, but it wasn't--it's the VB program calling the callback function, which is using a "bad convention." The only difference I can see between the working code and the broken code, is that I'm using a Long data type, and that I'm not returning a value (which shouldn't matter...right?)
I used DUMPBIN /EXPORTS to check the exports of the DLL and I get:

1    0 00001190 callback
2    1 00001190 callback@4

I checked the data types for VB6 and it says a long is 4 bytes, and if I compile the DLL using int, long, or short the DLL export always asks for 4 bytes in parameters, so I don't know what I'm doing wrong... Any ideas? Maybe I'll link to this in the C forum as well

Dani AI

Generated

Good catch, — the runtime error you saw is exactly the sort of problem that comes from a declaration/signature mismatch. Declaring an external procedure as a Function when the DLL actually exposes a void (no-return) routine will confuse VB’s call semantics and can produce the “bad DLL calling convention” behavior you observed. In short: if the native routine does not return a value, declare it as a Sub in VB.

A few concise reminders and troubleshooting steps for anyone hitting the same trap later:

  • Make the return and parameter sizes match exactly. VB6 is 32-bit: use Long for 32-bit pointers/handles and declare Sub vs Function to match whether the native code returns a value.
  • Match calling convention. VB6 expects stdcall-style exports. On the C side use the stdcall/WINAPI convention and export with a stable name (extern "C" for C++ or a DEF file / __declspec(dllexport>). The decorated export (for example name@N) indicates stdcall and the N is bytes of parameters.
  • Inspect the DLL exports (Dumpbin /EXPORTS or Dependency Walker) to confirm the exported name and decoration. If necessary use VB’s Alias clause to bind to the decorated name.
  • When passing AddressOf: the callback itself must have the exact parameter list and calling convention VB expects (stdcall). AddressOf yields a raw pointer; cast it carefully on the native side and call it with the correct prototype.
  • Watch platform bitness: VB6 only loads 32-bit DLLs. Migrating to VB.NET/VBA x64 requires different declarations (IntPtr/LongPtr and .NET delegates with proper marshaling).

If the problem resurfaces, create a tiny repro: a minimal exported function that simply invokes the passed pointer, and a minimal VB Sub declared to match it. That isolates calling-convention/return-type issues quickly.

fix'd.
Know what the problem was?

Public Declare Function callback Lib "C:\c\dll\mydll" (ByVal cbAddress As Long)

The function in the DLL doesn't return a value, so it should have been

Public Declare Sub callback Lib "C:\c\dll\mydll" (ByVal cbAddress As Long)

you would think VB could have just told me that since I didn't add "As ___" to the end of it, but, oh well.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.