【问题标题】:Access violation exception when using a DLL function使用 DLL 函数时的访问冲突异常
【发布时间】:2012-09-14 16:24:45
【问题描述】:

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

有什么建议吗?谢谢!

【问题讨论】:

  • DLL 是否在运行主程序的同一文件夹中?

标签: c++ dll


【解决方案1】:

你的问题在这里:

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

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

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

      我怀疑其中涉及某种形式的 C++ 名称​​mangling

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

      另外,如果GetProcAddress的返回值不是NULL(看你的if测试),函数成功:你为什么throw

      另请注意,如果您调整类头文件以便在导出和导入中都使用它,那么使用 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

      【讨论】:

      • @RiskX:不客气。如果您觉得我们的答案有用,您可能需要点击向上箭头。
      【解决方案4】:

      我认为Access violation exception when using a DLL function 是正确答案,但有点难以解释 - 我看到的问题是:

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

      【讨论】:

        猜你喜欢
        • 2010-11-01
        • 2014-03-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-24
        • 1970-01-01
        相关资源
        最近更新 更多