在Excel VBA中使用C ++ DLL

时间:2016-02-27 10:23:59

标签: c++ vba excel-vba excel

我从https://msdn.microsoft.com/de-de/library/ms235636.aspx创建MathFuncsDll.dll没有问题。 我也可以在不同的C ++项目中使用数学函数而没有问题。

现在我想在Excel VBA中使用这些功能。我试过了:

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

但我收到Run-time error '453'无法找到DLL入口点。

我该如何解决这个问题?

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;
    }
}

1 个答案:

答案 0 :(得分:5)

我假设您知道自己在做什么从VB程序调用C ++库时,我指的是calling convention

问题是C ++名称是mangled

如果您查看导出的函数名称(例如使用dumpbin /EXPORTS MathFuncsDll.dll,它们是这样的:

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

我的输出与您的输出不同,但只需显示没有像Add这样的简单名称。

通常使用修饰符extern "C"来避免这种混乱 使用Microsoft编译器,类memebers名称似乎总是被破坏,所以在这里没用。

您可以通过以下四种方式解决此问题:

<强> 1。定义重命名功能的DEF文件

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

<强> 2。在VBA声明中使用正确的别名

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。按序数导入,使用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。定义调用其等效项的全局存根函数

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

并导出它们。

这些都不是完美的,请记住,受损的名称是编译器特定的,如果您使用它们并更改/更新编译器,事情可能会破裂。

除非您使用 DEF 文件(再次需要受损的名称),否则也不会修复序数。

最后一个选项对于更改调用约定很有用,不会改变原始函数的导出方式,因此允许访问C ++和非C ++程序。