明确链接动态负载库和运行时误解

时间:2019-03-26 16:07:34

标签: c++ windows dll runtime

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

因此,我编写了一个程序,它可以成功加载DLL并使用它。当程序运行时,我在不存在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;
    }
}

1 个答案:

答案 0 :(得分:0)

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

地址空间布局随机化(ASLR)的出现改变了有关进程之间共享DLL代码的目标。 Raymond Chen在{@ {3}}等博客中对此进行了广泛的报道。