1

Trying to call a C++ DLL from VBA (MS Access) and keep getting a 'bad dll calling convention' error, as well as MS Access crashing.

Here's the C++ API function I'm trying to call:

_IMPORT HRESULT _CONVENTION PCRSNewTrip (Trip *pTripID);

"Trip" is defined as:

typedef long Trip;

From the API header:

#if defined (__BORLANDC__) 
#define  _IMPORT __declspec( dllimport )
#define  _CONVENTION __stdcall
#elif defined (_MSC_VER)
#define  _IMPORT _declspec( dllimport )
#define  _CONVENTION _cdecl
#endif

Here's a bit of info regarding the function: PCRSNewTrip() places a handle to the new trip in the pointer argument passed in (tripID). The return code is the same as all other DLL functions (used for error handling).

Here's my latest attempt at calling the function:

Public Declare Function PCRSNewTrip Lib "C:\xxx\pcrsrv32.dll" Alias "_PCRSNewTrip" (ByRef myTripPtr As Long) As Long

Private Sub NewTrip_Click()

Dim myTrip As Long
Dim myTripPtr As Long

myTripPtr = VarPtr(myTrip)

myTrip = PCRSNewTrip(myTripPtr)

EndSub

I'm getting a "Bad DLL calling convention" error.

creamer298
  • 25
  • 5
  • 1
    Win32 VBA only supports `STDCALL`. What is `_CONVENTION`? – Mathieu Guindon Jul 18 '19 at 16:37
  • 1
    Also `ByRef` already makes you pass a pointer, so you're passing a pointer to a pointer. But that shouldn't cause this error. – Erik A Jul 18 '19 at 16:47
  • From the API header file: #if defined (__BORLANDC__) #define _IMPORT __declspec( dllimport ) #define _CONVENTION __stdcall #elif defined (_MSC_VER) #define _IMPORT _declspec( dllimport ) #define _CONVENTION _cdecl #endif – creamer298 Jul 18 '19 at 16:59
  • 1
    I do not think C++'s `long` means the same thing as VBA's `Long`. I think you are after something like VBA's `LongPtr`. [Reference](https://stackoverflow.com/a/589685/643342) – this Jul 18 '19 at 17:07
  • 1
    Also, the `_CONVENTION` apparently varies based on the compiler. I'm no C++ expert but if you're compiling with Microsoft compiler, you're getting `_cdecl`, which isn't supported. It has to be `__stdcall` through and through. – this Jul 18 '19 at 17:13
  • saw this on reddit, they gave the same answer cept, the OP there didnt put in the header part. – KySoto Jul 18 '19 at 17:29

1 Answers1

1

Guessing this is the "live" branch of the conditionally-compiled header code:

#elif defined (_MSC_VER)
#define  _IMPORT _declspec( dllimport )
#define  _CONVENTION _cdecl
#endif

_cdecl is not supported in VBA on Windows. You need to use a build of that DLL that uses __stdcall.

Mathieu Guindon
  • 69,817
  • 8
  • 107
  • 235
  • I should note that I've been able to successfully call other functions from this DLL through MS Access VBA. Those functions are just initialization/shutdown and don't pass any arguments if that makes a difference. – creamer298 Jul 18 '19 at 17:32
  • @creamer298 parameterless functions probably have something to do with that, since the default `__cdecl` convention [requires each function call to include stack cleanup code](https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=vs-2019) (i.e. the *caller*), whereas in `__stdcall` the *callee* cleans the stack. No args, nothing is on the stack, either works. – Mathieu Guindon Jul 18 '19 at 17:43
  • The documentation for the dll states that it: "allows easy integration into popular software, such as Microsoft Access, Microsoft Excel and custom applications built with software development environments such as Visual Basic and Borland C++." and that it "is a 32-bit DLL product which can run in a 32-bit Windows environment." – creamer298 Jul 18 '19 at 18:03
  • Sure, given stdcall. – Mathieu Guindon Jul 18 '19 at 18:04