DLL系列5.延迟载入DLL

基本概念

  为了让DLL更易于使用, Microsoft Visual C++提供了一个很棒的特性,即延迟载入DLL。一个延迟载入的DLL是隐式链接的,系统一开始不会将该DLL载入,只有当我们的代码试图去引用DLL中包含的一个符号时,系统才会实际载入该DLL。延迟载入DLL在下列情况下非常有用。

  • 如果应用程序使用了多个DLL,那么它的初始化可能会比较慢,因为加载程序要将所有必需的DLL映射到进程的地址空间中。缓解这个问题的一种方法就是讲DLL的载入过程延伸到进程的执行过程中。延迟载入DLL可以让我们很容易地实现这一点。
  • 如果我们在代码中调用一个新的函数,然后又试图在一个不提供该函数的老版本的操作系统中运行该应用程序,那么加载程序会报告一个错误并且不允许应用程序运行。我们需要一种方法让应用程序执行,如果(在运行的时候)发现应用程序正在老的操作系统下运行,那么就不调用这个不存在的函数。延迟载入DLL同样可以让我们很容易地解决这个问题。

但是它仍然存在一些局限性,具体如下;

  • 一个导出了字段(全局变量)的DLL无法延迟载入的。
  • Kernel32.dll模块是无法延迟载入的,这是因为必须载入该模块才能调用LoadLibrary和GetProcAddres。
  • 不应该在DllMain入口函数中调用一个延迟载入的函数,因为这样可能导致程序崩溃。

示例演示

  首先,创建一个DLL,再创建一个可执行文件,这些和以往没有任何不同。但在链接可执行文件的时候,我们必须修改一些链接器开关。下面是需要增加的两个链接器开关:

/Lib:DelayImp.lib
/DelayLoad:MyDll.dll

  这两个链接器开关是不能在源代码中通过#pragma comment(linker, " ")来设置的。我们需要在项目属性中设置这两个链接器开关。“Delay Loaded DLLs“选项是通过Configuration Properties/Linker/Input属性页来设置的,如下图所示。
在这里插入图片描述
  “Delay Loaded DLL“选项是通过Configuration Properties/Linker/Advanced属性页来设置的,如下图所示。
在这里插入图片描述

/Lib开关告诉链接器要将指定的函数__delayLoadHelper2嵌入到我们的可执行文件中。第二个开关告诉链接器下列事项。

  • 将DLL模块从可执行模块的导入段中去除,这样当进程初始化的时候,操作系统的加载程序就不会隐式地载入该DLL。
  • 在可执行模块中嵌入一个新的延迟载入段(即Delay Import section,成为.didata)来表示要从该DLL中导入哪些函数。
  • 通过让对延迟载入函数的调用跳转到__delayLoadHelper2函数,来完成对延迟载入函数的解析。

应用程序运行的时候,对延迟载入函数的调用实际上会调用__delayLoadHelper2函数。这个函数会引用那个特殊的延迟载入段,并会先后调用LoadLibrary和GetProcAddress。一旦得到了对应的延迟载入函数的地址,__delayLoadHelper2会修复对该函数的调用,这样今后的调用将直接调用延迟载入函数。注意,同一个DLL中的其他函数仍然必须在第一次被调用的时候修复。另外请注意,我们可以多次指定/DelayLoad链接器开关——每一个开关对应一个我们想要延迟载入的DLL。

猜你喜欢

转载自blog.csdn.net/webzhuce/article/details/105870995
dll