0

我有一个 DLL,我想在其中调用一个函数。我使用 Dependency Walker 检查 DLL,得到的结果是:

 void U2U_Test(void)

这是我编写的代码,但GetProcAddress()返回 NULL:

typedef void(*U2U_Test_pointer)();

void  check() {

    HINSTANCE hGetProcIDDLL1 = LoadLibrary(_T("my_dll.dll"));

    if (hGetProcIDDLL1 == NULL)
        return;

    U2U_Test_pointer addr = (U2U_Test_pointer)GetProcAddress(hGetProcIDDLL1, "U2U_Test");

    if (addr == NULL)
        return;

    return addr();
}
4

1 回答 1

0

根据使用的约定和编译器,DLL 中导出的实际名称可能与您在源代码中编写的名称不完全相同。这种现象通常称为名称修饰或名称修饰。

实际上,只有在以下情况下才能保证您具有完全相同的名称

  • 您的编译器符合 C 约定(可能确实如此)
  • 该函数以 C 而不是 C++ 导出。用于extern "C"指定它。
  • 调用约定是 _cdecl(__cdecl在函数声明中指定)

例如,当调用约定是 __stdcall 而不是 __cdecl,这在许多 Windows DLL 中很常见(他们经常写 WINAPI 或 CALLBACK 而不是 __sstdcall),导出函数的名称通常以 @n 为后缀,其中 n 是字节数期望在堆栈上获取参数。在你的情况下,它可能是U2U_Test@0. 当在编译时导入/链接 DLL 时,类似__declspec(dllimport)__declspec(dllexport)告诉编译器自动处理这类事情的指示。

在 C++ 中,为了支持方法、函数重载、模板和其他特性,使用了复杂的名称修饰,并且每个编译器都发明了疯狂的命名方案以确保不会发生任何冲突。因为在 DLL 级别,没有模板,没有类,只有一个按名称或 ID 索引的导出符号列表。这就是为什么大多数 DLL 都以 C 语言导出以及为什么大多数头文件都声明来自extern "C" { ... }块内 DLL 的函数的原因。

于 2021-08-29T06:15:58.407 回答