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

Explicit Linking of Dynamic Load Library and Runtime misconception

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

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

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

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

Program.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;
    }
}

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

地址 Space 布局随机化 (ASLR) 的出现已经改变了进程之间共享 DLL 代码的目标。 Raymond Chen 已就此广泛发表博客,例如 here