Я создал MathFuncsDll.dll
с https://msdn.microsoft.com/de-de/library/ms235636.aspx без проблем. Я могу использовать математические функции в другом проекте 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;
}
}
Я предполагаю, что вы знаете, что вы делаете при вызове библиотеки C++ из VB-программы, я имею в виду соглашение о вызове.
Проблема заключается в том, что C++ имена искажаются.
Если вы посмотрите на имена экспортируемых функций (например, с 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++.
Add@MyMathFuncs@MathFuncs@@SANNN@Z
но я забыл?
в начале. Я также сделал это в C и определил имя функций в DLL с помощью файла DEF, и там было написано наоборот:name_in_dll = name_in_c
. Это должно быть отражено в вашем ответе?