我创建了一个简单的DLL作为我的C ++练习的一部分,但是在调用DLL函数时我遇到了访问冲突异常。这是DLL的头文件(我怀疑CPP在这里有用):
#pragma once
namespace MathFuncs
{
class MyMathFuncs
{
public:
// Returns a + b
static __declspec(dllexport) double Add(double a, double b);
// Returns a - b
static __declspec(dllexport) double Subtract(double a, double b);
// Returns a * b
static __declspec(dllexport) double Multiply(double a, double b);
// Returns a / b
// Throws DivideByZeroException if b is 0
static __declspec(dllexport) double Divide(double a, double b);
};
}
这是我的主要内容:
#include <iostream>
#include "windows.h"
using namespace std;
int main(void)
{
double (__cdecl *MYPROC)(double,double);
/* get handle to dll */
HINSTANCE hGetProcIDDLL = LoadLibrary("DLLExample.dll");
if(hGetProcIDDLL == NULL)
throw;
/* get pointer to the function in the dll*/
FARPROC lpfnGetProcessID = GetProcAddress(hGetProcIDDLL,"Add");
if(lpfnGetProcessID)
throw;
MYPROC = (double (__cdecl *)(double,double))lpfnGetProcessID;
if(MYPROC)
throw;
double x = MYPROC(5.5,5);
return 0;
}
有什么建议吗?谢谢!
答案 0 :(得分:3)
你的问题在于:
FARPROC lpfnGetProcessID = GetProcAddress(hGetProcIDDLL,"Add");
if(lpfnGetProcessID) // <-- error!
throw;
MYPROC = (double (__cdecl *)(double,double))lpfnGetProcessID;
if(MYPROC) // <-- error!
throw;
double x = MYPROC(5.5,5);
如果lpfnGetProcessId
有一个地址,那么您将抛出异常。如果没有,你以后会试着打电话(繁荣!)。
您将要使用extern "C"
修饰您的函数,以确保它们以用户友好的名称导出。这意味着他们不能进入一个班级:
namespace MathFuncs
{
extern "C" __declspec(dllexport) double Add(double, double);
}
答案 1 :(得分:2)
如果您的DLL没有代码,那么您只能推测,并且您选择的命名似乎在中途更改,但看起来您正在执行以下操作:
1)如果失败,加载dll并抛出异常......好吧。 2)在dll中找到一个似乎一起添加两个值的函数 - 但是如果成功则抛出异常?由于您没有抛出异常,因此返回NULL,因此您无法找到该函数。 3)调用函数 - 该函数为NULL,因此你将在这里失败。
我怀疑问题是你没有考虑到C ++名称错误。您可以在调用GetProcAddress()时更改函数名称以正确计算它,或者您可以使用extern "C"
声明函数以删除重整。
答案 2 :(得分:1)
您确定方法MathFuncs::MyMathFuncs::Add()
实际导出为简单的“添加”,就像在GetProcAddress
电话中一样吗?
我怀疑存在某种形式的C ++名称 mangling 。
您可能希望从命令行使用 DUMPBIN / EXPORTS 来查看实际导出的方法名称。
此外,如果GetProcAddress
的返回值不是 NULL
(请参阅if
测试),则函数成功:为什么你{{1 }}?
另请注意,如果您调整类头文件以便在导出和导入中使用它,那么使用DLL会更简单,例如。
throw
通过这种方式,客户端只需#if defined(MATHFUNCS_EXPORT) // Inside DLL implementation
#define MATHFUNCS_API __declspec(dllexport)
#else // Outside DLL
#define MATHFUNCS_API __declspec(dllimport)
#endif // MATHFUNCS_EXPORT
class MyMathFuncs
{
public:
static MATHFUNCS_API double Add(double a, double b);
...
};
您的头文件(并链接相应的.lib文件),而无需使用#include
/ LoadLibrary
。
答案 3 :(得分:0)
我认为Access violation exception when using a DLL function是正确答案,但有点难以解释 - 我看到的问题是:
检查是向后的 - 如果我们无法获得函数指针,我们继续,只有在成功获取函数指针时才抛出。
由于函数是静态的,因此应该导出成员函数,但是我们无法获得函数指针,因为DLL不会导出名为“Add”的函数 - 实际名称将被修改并且可能是在.map文件中找到,如果已生成。
由于我们没有找到函数指针,因此我们将NULL转换为函数指针类型并尝试调用它,这样我们就可以获得访问冲突。
代码应为:
FARPROC lpfnGetProcessID = GetProcAddress(hGetProcIDDLL,"**MangledAddFunctionName - see .map file**");
if(lpfnGetProcessID == NULL)
throw;
MYPROC = (double (__cdecl *)(double,double))lpfnGetProcessID;
if(MYPROC == NULL)
throw;
double x = MYPROC(5.5,5);