动态负载库和运行时误解的显式链接

Posted

技术标签:

【中文标题】动态负载库和运行时误解的显式链接【英文标题】:Explicit Linking of Dynamic Load Library and Runtime misconception 【发布时间】:2019-03-26 16:07:33 【问题描述】:

我在 Windows 中使用 DLL。我创建了其中一个,并且我可以成功地将我的客户端程序链接到 DLL。但我有一个误解。当我阅读 DLL 时,有一句话强调当 DLL 加载到内存中时,所有程序实例都可以使用它。所以它导致我们有效地使用内存并且代码重复从未发生过。

所以我编写了一个程序,它可以成功加载一个 DLL 并使用它。当程序运行时,我在不同的路径中执行了前一个程序的示例,该路径中不存在 DLL,但是当我运行第二个程序时,它显示错误,DLL 不加载。

我的假设是当第一个程序将 DLL 加载到内存中时,它的一个实例存在于内存中,所以我应该再次使用它,但它没有发生。所以我想知道多个程序如何使用一个 DLL 的实例?我应该如何实现一个例子来测试这种行为?程序本身的路径中必须有DLL的样本吗?

对不起,英语不好,我不得不提一下,我是新手程序员,不是专业人士。对不起,如果你发现这个问题太愚蠢了。这是我的代码:

程序.cpp

#include <Windows.h>
#include <iostream>
#include <string>

typedef void(__cdecl *PtrSetInformation)(std::string, std::string, int);
typedef void(__cdecl *PtrShowInformation)(void);

auto main() -> int 
    HINSTANCE HandlerInstance = LoadLibrary(TEXT("LibEngine.dll"));

    if (!HandlerInstance) 
        std::cout << "DLL doesn't load successfuly." << std::endl;
    
    else 
        std::cout << "Dll is loaded successfuly." << std::endl;
    

    PtrSetInformation OSetInformation = reinterpret_cast<PtrSetInformation>(GetProcAddress(HandlerInstance, "SetInformation"));
    PtrShowInformation OShowInformation = reinterpret_cast<PtrShowInformation>(GetProcAddress(HandlerInstance, "ShowInformation"));

    if (!OSetInformation || !OShowInformation) 
        std::cout << "Function pointers doesn't initiliazed successfuly." << std::endl;
    
    else 
        OSetInformation("Mikhail", "Razborov", 24);
        OShowInformation();
    

    std::cin.get();

    return 0;

我的 DLL 代码:

#include <iostream>
#include <string>

std::string __name;
std::string __family;
int __age;

extern "C" 
    __declspec(dllexport) void __cdecl SetInformation(std::string arg_name, std::string arg_family, int arg_age) 
        __name = arg_name;
        __family = arg_family;
        __age = arg_age;
    

    __declspec(dllexport) void __cdecl ShowInformation() 
        std::cout << "Your name is " << __name << " " << __family << std::endl;
        std::cout << "You are a " << __age << " year old programmer." << std::endl;
    

【问题讨论】:

【参考方案1】:

即使 DLL 的内存映像可能是共享的(并非总是如此),Windows 在加载 .exe 时仍需要访问磁盘上的副本。这是因为您可能在不同的目录中有两个同名的不同 DLL,而 Windows 将每个 DLL 视为一个单独的实体。

地址空间布局随机化 (ASLR) 的出现改变了在进程之间共享 DLL 代码的目标。 Raymond Chen 已经在博客中广泛讨论了这一点,例如 here。

【讨论】:

以上是关于动态负载库和运行时误解的显式链接的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Thymeleaf 的显式链接?

OpenGL着色器的显式与自动属性位置绑定

不运行时接收消息,Xamarin Android上的显式广播和隐式广播

想【C++ 】高手发起挑战,请教一个【动态链接库 dll 和 类成员函数 显式链接】问题

gcc -nostdlib是否会阻止标准库的显式附加?

Linux学习——动态链接库和静态链接库