Runtime Error 49: “Bad DLL calling convention,” explained and fixed

Error 49, “Bad DLL calling convention”, means a Declare call passed arguments in a way the DLL function does not accept. The count, the types, or the passing mechanism (ByVal versus ByRef) disagrees with the real function, so the stack is left unbalanced and VBA raises error 49, if it is lucky; if it is unlucky, the application crashes instead. It is always a defect in the Declare statement or the call, never in the data.

For people who just run the program

  1. Expect this after a version change. A macro written against one version of a library, an older Office, or a different Windows API set can start failing when the environment moves.
  2. Check whether the macro came from a 32-bit setup. Declares written for 32-bit Office frequently misbehave under 64-bit Office; this error is one of the milder outcomes.
  3. Do not try random documents to “test” it. The mismatch is in the code's declaration, identical for every file.
  4. Send the maintainer the error and your Office bitness. Declare fixes are version-sensitive, and that one fact steers the repair.

For people who write the code

  1. Compare the Declare against the function's real signature. Every parameter must match in count, type, and ByVal/ByRef. C long is VBA Long in 32-bit and still Long (not LongLong) in 64-bit for most API parameters; pointers and handles are LongPtr.
  2. ' Wrong on 64-bit: handle declared As Long truncates the pointer
    ' Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
    '     (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
    Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" _
        (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
  3. Pass strings correctly. API functions expect strings ByVal so VBA hands over a converted pointer to text. Declaring a string parameter ByRef (the default) is a classic error 49, or crash, cause.
  4. Check callbacks and return types. A function declared with the wrong return type unbalances the stack just as surely as a wrong argument. Verify against the library's documentation, not against another macro copied from a forum.
  5. Test the Declare in isolation. A five-line test procedure calling only that function separates a bad declaration from a bad call site in minutes.
Error 49 is the polite version of this bug. The same mismatch often crashes the host application with no error at all. If a Declare sometimes crashes and sometimes raises 49, treat them as the same defect and audit the signature, do not chase the crash separately.

If it still happens

If the signature matches the documentation exactly and error 49 persists, the documentation may describe a different version of the library than the one installed. Confirm the DLL version on the machine, and check whether the function uses a calling convention (such as cdecl in some third-party libraries) that VBA Declare cannot call at all; those need a wrapper, not a better Declare.

Common questions

Does error 49 mean the DLL is broken? No. The DLL is usually fine; the VBA declaration of how to call it is wrong. The error is raised because the arguments placed on the stack did not match what the function removed from it.

Why do old Declare statements fail on 64-bit Office? Because pointer-sized values changed. Handles and pointers declared As Long are truncated, and without PtrSafe the declaration does not even compile cleanly; at run time the mismatch surfaces as error 49 or a crash.

Related errors

Runtime Error 48 · Runtime Error 453 · Runtime Error 458