C++ 调用进程退出后是否可以将DLL保留在内存中?

C++ 调用进程退出后是否可以将DLL保留在内存中?,c++,qt,dll,C++,Qt,Dll,我有一个DLL,加载需要5到10秒,这意味着每次编译和运行使用它的可执行文件时,我都必须等待那么长的时间。是否有一种方法可以将DLL加载到内存中,以便每次编译相应的可执行文件时都可以立即访问它?我正在QT-MinGW上编译程序,如果相关的话 编辑:到目前为止运气不好。在另一个程序上加载DLL似乎没有效果(原始程序仍然加载DLL,并且加载所需的时间与加载相同)。如果DLL和它的函数被加载到另一个程序中,我想我需要以不同的方式加载它们,但我不知道怎么做。现在我正在使用LoadLibrary和GetP

我有一个DLL,加载需要5到10秒,这意味着每次编译和运行使用它的可执行文件时,我都必须等待那么长的时间。是否有一种方法可以将DLL加载到内存中,以便每次编译相应的可执行文件时都可以立即访问它?我正在QT-MinGW上编译程序,如果相关的话


编辑:到目前为止运气不好。在另一个程序上加载DLL似乎没有效果(原始程序仍然加载DLL,并且加载所需的时间与加载相同)。如果DLL和它的函数被加载到另一个程序中,我想我需要以不同的方式加载它们,但我不知道怎么做。现在我正在使用LoadLibrary和GetProcAddress。

创建一个显式安装的系统服务,使DLL保持加载状态。这样,初始化将在启动时发生,而不会再次发生。我建议不要采用其他大多数答案中概述的方法。虽然它们看起来很有效,但在我看来,它们就像是您的软件中的不良行为。从用户和维护人员的角度来看,我更喜欢显式安装的系统服务,而不是将某些东西挂接到winlogin.exe。您越诚实地使用Windows API和环境,跨版本和在版本升级时进行的破坏性更改就越少

如果我没有记错的话,Windows会在内存中保留一个DLL实例,因此保持该实例的活动状态应该是可行的:

#include <conio.h>
#include <windows.h>

int main()
    {
    HMODULE handle=LoadLibrary("yourdll.dll");
//  Make shure Windows resolves the DLL
    FARPROC dummy=GetProcAddress(handle,"functionInDll");
//  The process will now just wait for keyboard input.
    getch();
    CloseHandle(handle);
    return 0;
    }
#包括
#包括
int main()
{
hmodulehandle=LoadLibrary(“yourdll.dll”);
//使舒尔Windows解析DLL
FARPROC dummy=GetProcAddress(句柄,“functionInDll”);
//该过程现在将只等待键盘输入。
getch();
关闭手柄(手柄);
返回0;
}

最简单的解决方案是(假设MSVC++)加载DLL延迟。当然,折衷的办法是仍然必须进行初始化,但这将不再延迟程序的其他部分。例如,您可以在后台线程上执行此操作。

我不是MinGW开发人员,但您的问题非常常见,并不真正取决于您如何创建DLL。这些问题通常通过使用三种技术来解决:

  • 选择DLL的唯一基址
  • 绑定DLL和exe(在应用程序安装期间)
  • DLL延迟加载技术的使用
  • 稍微缩短加载时间,调用
    DLL\u进程\u附加
    DllMain部分
链接器或其他工具的确切开关取决于您的开发环境

要理解这个问题,您应该知道如何加载可执行文件或DLL。首先,EXE或DLL将映射到内存中。将创建指向EXE/DLL的(节)。因此,在访问过程中将有一些地址与EXE/DLL文件相对应。如果链接DLL,则可以选择基址。如果该地址在进程地址空间中未使用,则不会执行任何操作。如果将使用第一行代码(从DLL调用某个函数),则使用地址附近的内存8K页将从文件加载到内存中。如果两个进程使用相同的DLL,那么代码的物理内存将在进程之间共享。即使您持有已初始化的变量,也将共享包含这些变量的页面,直到变量发生第一次更改。修改时,将为进行修改的进程制作内存页的副本

在进程中加载DLL后,必须修改调用程序的一些小部分(例如EXE),以包含DLL中使用的函数的实际地址。使用另一个DLL函数的DLL也将执行相同的操作

一切听起来都很完美,但如果在DLL编译期间未设置任何链接器选项(如果未使用
--image base
--启用自动镜像base
链接器选项),则所有DLL都将具有相同的基地址(链接器的默认值)。因此,第一个DLL可以在该地址加载。加载与相同(或某些重叠地址)链接的第二个DLL时,将重新定位DLL。在重新定位过程中,DLL的代码将被修改,因此1)DLL的加载将缓慢进行2)代码的修改副本将在过程中进行(包括DLL使用的内存)3)修改副本不会在DLL的多个实例之间共享(即使所有实例都将以相同的方式修改)

我建议您首先使用示例来验证哪些DLL将在应用程序中重新定位。您应该在“视图”/“下疼痛视图”菜单中选择选项“DLL”,并在“选项”菜单的“配置突出显示”中选择“重新定位DLL”复选框。您还可以自定义显示每个DLL的哪些信息。下面的信息越多,加载程序的速度就越慢,应用程序实例之间或使用同一DLL的不同应用程序之间不共享的地址空间就越多:

在上面的示例中,您可以看到树Lenovo dll
TPOSDSVC.dll
HKVOLKEY.dll
TPLHMM.dll
与相同的基址
0x10000000
链接,并且只有一个dll(
TPOSDSVC.dll
此处)将加载到该地址。另外两个DLL必须重新定位

我不能在这里写一本关于这个主题的书。我建议你检查一下关于搬迁问题的申请。您可以使用链接器选项(
--image base
--enable auto image base
似乎就是您所需要的)。您可以使用该工具(也可以在免费版中从VisualStudio获得)检查PE图像

在所有DLL都具有唯一的基址之后,您可以使用另一个工具