c++vbaexcel

Using C++ DLL in Excel VBA


I created the MathFuncsDll.dll from https://msdn.microsoft.com/de-de/library/ms235636.aspx without issues. I can use the math functions in a different C++ project also without issues.

Now I want to use these functions in Excel VBA. I tried:

Public Declare Function DLL_Import_Add Lib "C:\Users\User\Desktop\MathFuncsDll.dll" Alias "Add" (ByVal a As Double, ByVal b As Double) As Double

Sub test()
    MsgBox DLL_Import_Add(2.1, 3.3)
End Sub

But I am receiving a Run-time error '453' The DLL entry point cannot be found.

How can I solve that problem?

MathFuncsDll.h:

// MathFuncsDll.h
#ifdef MATHFUNCSDLL_EXPORTS
#define MATHFUNCSDLL_API __declspec(dllexport)
#else
#define MATHFUNCSDLL_API __declspec(dllimport)
#endif

namespace MathFuncs
{
    // This class is exported from the MathFuncsDll.dll
    class MyMathFuncs
    {
    public:
        // Returns a + b
        static MATHFUNCSDLL_API double Add(double a, double b);
        // Returns a - b
        static MATHFUNCSDLL_API double Subtract(double a, double b);
        // Returns a * b
        static MATHFUNCSDLL_API double Multiply(double a, double b);
        // Returns a / b
        // Throws const std::invalid_argument& if b is 0
        static MATHFUNCSDLL_API double Divide(double a, double b);
    };
}

MathFuncsDll.cpp:

// MathFuncsDll.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "MathFuncsDll.h"
#include <stdexcept>
using namespace std;
namespace MathFuncs
{
    double MyMathFuncs::Add(double a, double b)
    {
        return a + b;
    }
    double MyMathFuncs::Subtract(double a, double b)
    {
        return a - b;
    }
    double MyMathFuncs::Multiply(double a, double b)
    {
        return a * b;
    }
    double MyMathFuncs::Divide(double a, double b)
    {
        if (b == 0)
        {
            throw invalid_argument("b cannot be zero!");
        }
        return a / b;
    }
}

Solution

  • I assume you know what you are doing when calling a C++ library from a VB program, I am referring to calling convention.


    The problem is that C++ names are mangled.

    If you take a look at the exported functions names (for example with dumpbin /EXPORTS MathFuncsDll.dll, they are something like these:

    ordinal hint RVA      name
    
          1    0 00001000 ?Add@MyMathFuncs@MathFuncs@@SAHHH@Z
          2    1 00001030 ?Divide@MyMathFuncs@MathFuncs@@SAHHH@Z
          3    2 00001020 ?Multiply@MyMathFuncs@MathFuncs@@SAHHH@Z
          4    3 00001010 ?Subtract@MyMathFuncs@MathFuncs@@SAHHH@Z
    

    My output will differ from yours, but it suffices to show that there are no simple names like Add.

    Usually you avoid this mess with the use of the modifier extern "C".
    With Microsoft compiler, class memebers names seem to be always mangled, so it is useless here.

    You can workaround this in four ways:

    1. Define a DEF file that rename the functions

    LIBRARY MathFuncsDll
    EXPORTS
       Add=?Add@MyMathFuncs@MathFuncs@@SAHHH@Z
       ...
    

    2. Use the correct alias in your VBA declaration

    Public Declare Function DLL_Import_Add Lib "C:\Users\User\Desktop\MathFuncsDll.dll" Alias "?Add@MyMathFuncs@MathFuncs@@SAHHH@Z" (ByVal a As Double, ByVal b As Double) As Double
    

    3. Import by ordinal, using something like Alias "#1"

    Public Declare Function DLL_Import_Add Lib "C:\Users\User\Desktop\MathFuncsDll.dll" Alias "#1" (ByVal a As Double, ByVal b As Double) As Double
    

    4. Define global stub functions that call their equivalents

    extern "C" MATHFUNCSDLL_API double Add(double a, double b)
    {
       return MathFuncs::MyMathFuncs::Add(a, b); 
    } 
    

    and export them.

    None of this is perfect, keep in mind that mangled names are compiler specific, if you use them and change/update the compiler, things may break up.

    Also ordinals are not fixed, unless you use a DEF file (that again need the mangled name).

    The last option is useful to change calling convention and won't change the way the original functions are exported, thus allowing access to both C++ and non C++ programs.