【问题标题】:Dynamically use a DLL from a console application动态使用控制台应用程序中的 DLL
【发布时间】:2020-08-06 12:27:16
【问题描述】:

我正在尝试创建一个库 Lib.dll 以从控制台应用程序动态调用,但找不到我要调用的函数 funci()

Lib.dll 是在 Visual Studio 2019 中创建的项目(控制台应用程序,但设置为配置类型:.dll)的结果。

Lib.cpp 是该项目中唯一的文件,并且只包含代码:

__declspec(dllexport) int funci() 
{
    return 50;
}

我认为我正确地导出了该函数,因为我使用 DLL Export Viewer v1.66 找到了该函数。

但是,我很难通过控制台应用程序 (.exe) 找到该功能:

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

typedef int(__cdecl* o_funci)(void);

o_funci funci;

int main()
{
    HINSTANCE hGetProcIDDLL = LoadLibraryA("C:\\Lib.dll");

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

    // resolve function address here
    funci = (o_funci) GetProcAddress(hGetProcIDDLL, "funci");
    if (!funci) {
        std::cout << "could not locate the function" << std::endl;
        return EXIT_FAILURE;
    }

    std::cout << "funci() returned " << funci() << std::endl;

    FreeLibrary(hGetProcIDDLL);
}

GetProcAddress 出了点问题,但不知道为什么。我哪里做错了?

输出:

我一直在看这个旧帖子:Dynamically load a function from a DLL


编辑:感谢 tenfour 解决

我使用了 DependencyWalker。

没有extern "C" 我可以看到未修饰的funci 有名称?funci@@YGHXZ

所以funci = (o_funci)GetProcAddress(hGetProcIDDLL, "?funci@@YGHXZ"); 工作了。

使用extern "C",未修饰的funci 的名称为_funci@0 - 更干净一些。

另一个注释;使用序数 0x0001 在这两种情况下都有效。像这样:funci = (o_funci)GetProcAddress(hGetProcIDDLL, (PCSTR)0x0001);

【问题讨论】:

    标签: c++ windows winapi dllexport


    【解决方案1】:

    您使用的工具正在向您显示导出名称的漂亮版本。它的真实名称将包括名称修饰,这是一种将呼叫信息嵌入导出名称的复杂尝试。

    您可以通过多种方式使用GetProcAddress

    1. 使用 REAL 导出名称。您的工具可能可以选择查看未美化的名称(损坏的导出名称)
    2. 使用模块定义文件 (*.def) 导出函数,您甚至可以在其中指定要导出的名称
    3. 按序号而不是名称导入
    4. 将函数包装在 extern "C" { ... } 中,这将使用 C 样式命名,从而避免名称混淆。

    最常见的解决方案可能是#4,紧随其后的是#2。

    【讨论】:

    • WTF?我错过了extern "C",但看了 OP 的快照并想:嗯。 __cdecl 可能会修复它,但我没有这方面的经验。我从没想过 DLL 导出查看器会显示导出名称的漂亮版本(我对 DependencyWalker 有一些经验,但我不记得它是如何在那里完成的。)多么卑鄙...
    • @Scheff "我对 DependencyWalker 有一些经验,但我不记得它是如何在那里完成的。" Dependecy Walker 有一个名为“Undecorate C++ functions”的切换开关。跨度>
    • @AlgirdasPreidžius 正确,确认。 ;-) 我不确定这是否可以配置(或以某种方式被记住),但在我的情况下,默认显示“真实”(装饰)名称。这就是我认为的“不那么卑鄙”。 (Dep.Walker 仍然摇摆不定。):-)
    • extern "C" 不会避免名称修改。它只是选择了一组不同的名称装饰,更易于阅读和输入。还有第 5 个选项:编译 64 位二进制文​​件(使用 extern "C")。在这种情况下,名称装饰将消失。
    • @jub:按序号导入要求您从不更改导出顺序。这是一个很难满足的要求,如果您只需要更方便的重要名称,这几乎是不合理的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-10
    • 1970-01-01
    • 2010-10-30
    • 2012-07-16
    • 2014-09-10
    • 2022-06-10
    • 2010-11-04
    相关资源
    最近更新 更多