0

作为 C++ 练习的一部分,我创建了一个简单的 DLL,但在调用 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

4 回答 4

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);
}
于 2012-09-14T16:43:05.363 回答
2

如果没有 DLL 的代码,只能推测,并且您选择的命名似乎在中途发生了变化,但看起来您正在执行以下操作:

1)加载dll并在失败时抛出异常......好的。2)在dll中找到一个似乎将两个值相加的函数——但是如果成功了,你会抛出异常吗?由于您没有抛出异常,因此返回了 NULL,因此您无法找到该函数。3)调用函数——它是NULL,所以你会在这里失败。

我怀疑问题在于您没有考虑 C++ 名称修饰。您可以在对 GetProcAddress() 的调用中更改函数名称以正确解释它,或者您可以声明该函数extern "C"以删除重整。

于 2012-09-14T16:33:11.563 回答
1

您确定该方法MathFuncs::MyMathFuncs::Add()实际上是作为简单的“添加”导出的,就像在您的GetProcAddress调用中一样?

我怀疑涉及某种形式的 C++ 名称修改

您可能希望从命令行使用DUMPBIN /EXPORTS来查看实际导出的方法名称。

此外,如果返回值GetProcAddress不是(请参阅您的测试),则该函数成功:您为什么? NULLifthrow

另请注意,如果您调整类头文件以在导出和导入中都使用它,则使用 DLL 会更简单,例如

#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);
  ...
};

这样,客户端可以只#include使用您的头文件(并与相应的 .lib 文件链接),而无需使用LoadLibrary/ GetProcAddress

于 2012-09-14T16:28:48.663 回答
0

我认为使用 DLL 函数时的访问冲突异常是正确的答案,但它有点难以解释 - 我看到的问题是:

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

  2. 成员函数应该可以很好地导出,因为函数是静态的,但我们无法获得函数指针,因为 DLL 没有导出名为“Add”的函数 - 实际名称将被破坏,可以在 .map 文件中找到,如果生成。

  3. 由于我们没有找到函数指针,因此我们将 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);
于 2017-10-03T13:57:10.180 回答