【问题标题】:Why do I get an Exception Exception thrown at 0x00000000 in ConsoleApplication1.exe: 0xC0000005: Access violation executing location 0x00000000为什么我在 ConsoleApplication1.exe 中的 0x00000000 处出现异常异常:0xC0000005:访问冲突执行位置 0x00000000
【发布时间】:2021-04-25 06:52:12
【问题描述】:

我正在尝试创建一个非常简单的 dll 并将其加载到另一个文件以用于学习目的。我对 DLL 和 C++ 文件使用相同版本的 VC++。这是我的源代码:

加载.cpp:

#include <iostream>
#include <windows.h>

using namespace std;

typedef int(__stdcall* nsum)(int a, int b);

int main(void)
{
    HINSTANCE myDll = LoadLibrary(L".\\DLL1.dll");
    nsum sum = (nsum)GetProcAddress(myDll, "sum");

    if (!myDll) {
        cout << "could not load the dynamic library" << endl;
        return EXIT_FAILURE;
    }


    int xfinal = sum(10, 20);
    cout << xfinal << endl;

    return 0;
}

和 dll.cpp

#include <windows.h>
#include "pch.h"

using namespace std;

int __declspec(dllexport) __stdcall sum(int a, int b)
{
    return a + b;
}

pch.h

// pch.cpp: source file corresponding to the pre-compiled header

#include "pch.h"

// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.

但我仍然遇到异常。我搜索了答案,但没有找到,所以我写这个寻求帮助

在 load.cpp 中,在 HINSTANCE myDll 中,我可以窥视并看到设置为 0x000000000 的值。是这个原因吗?如果是这样,我该如何解决?

【问题讨论】:

  • 为什么会在 0x00000000 处抛出异常异常 0x00000000 通常不是要写入的有效地址。 (它是为nullptr“保留”的。)因此,您可能无法读取或写入它(或者操作系统会因访问冲突而中止您的应用程序)。
  • @Scheff 那么我应该怎么做才能解决它?
  • 顺便说一句。您首先使用myDll,然后检查它的有效性。如果myDll 无效,您的应用程序将在检查前终止。您应该在调试器中检查这是根本问题还是还有其他问题。
  • @Scheff 你能指导我如何检查吗?是不是像调试一样?
  • @Mayukh "你能指导我如何检查吗?"myDll的任何其他用法之前移动if (!myDll) {

标签: c++ visual-studio visual-c++


【解决方案1】:

你的问题很简单。您的函数的导出名称不是sum,因为您使用C ABI。相反,它是一个mangled 名称?sum@@YGHHH@Z,当然你使用GetProcAddress(myDLL, "sum"); 是找不到的。没有这样的函数sum。因此,您正在尝试调用地址 0 处的函数,即异常告诉您的内容。

Microsoft 将这些称为 Decorated Names 而不是“mangled”,但它们的含义相同:参数类型、调用约定和返回值的类型信息被编码为构成名称的特殊符号。

这里有几个选项可以解决这个问题:

  • 使用导入库而不是显式链接,这将使用重命名的名称,因此您可以坚持使用 C++ ABI。

  • 通过extern "C" 使用C ABI,保持现有的__stdcall 调用约定,在这种情况下,为x86(32 位)构建时名称将为_sum@8

extern "C" int __declspec(dllexport) __stdcall sum(int a, int b)
  • 使用带有extern "C" 的C ABI,但使用__cdecl,这实际上会导致x86(32 位)的sum
extern "C" int __declspec(dllexport) __cdecl sum(int a, int b)

对于 x64,有一个标准调用约定 __fastcall__cdecl__stdcall 只是 __fastcall 的别名)。在这种情况下,仅使用 extern "C" 将导致名称 sum 用于任何这些调用约定。使用用于 x64 的 C ABI 导致“损坏”导出的唯一情况是 extern "C" __vectorcall

如果您更改它,请务必更新您的 typedef 以匹配您使用的调用约定。

其次,你应该添加更多的错误检查:

HMODULE myDll = LoadLibrary(L".\\DLL1.dll");
if (!myDll) {
    cout << "could not load the dynamic library" << endl;
    return EXIT_FAILURE;
}

nsum sum = (nsum)GetProcAddress(myDll, "sum");
if (!sum) {
    cout << "could not find the export" << endl;
    return EXIT_FAILURE;
}

如果您使用的是 C++11 或更高版本(Visual Studio 2012 或更高版本),那么auto sum = reinterpret_cast&lt;nsum&gt;(reinterpret_cast&lt;void*&gt;(GetProcAddress(myDll, "sum"))); 更好。

【讨论】:

  • 我正在使用 VC++
  • @Mayukh 好吧,VC++ 与 c++11 标准一起使用是可行的。您应该尝试弄清楚您的开发环境中到底是什么。 VC++ 是 IDE,而不是编译器。
猜你喜欢
  • 2017-05-15
  • 1970-01-01
  • 2021-02-14
  • 1970-01-01
  • 2013-10-11
  • 1970-01-01
  • 1970-01-01
  • 2013-04-05
  • 1970-01-01
相关资源
最近更新 更多