使用DLL函数时访问冲突异常

时间:2012-09-14 16:24:45

标签: c++ dll

我创建了一个简单的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;
}

有什么建议吗?谢谢!

4 个答案:

答案 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是正确答案,但有点难以解释 - 我看到的问题是:

  1. 检查是向后的 - 如果我们无法获得函数指针,我们继续,只有在成功获取函数指针时才抛出。

  2. 由于函数是静态的,因此应该导出成员函数,但是我们无法获得函数指针,因为DLL不会导出名为“Add”的函数 - 实际名称将被修改并且可能是在.map文件中找到,如果已生成。

  3. 由于我们没有找到函数指针,因此我们将NULL转换为函数指针类型并尝试调用它,这样我们就可以获得访问冲突。

  4. 代码应为:

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