`

延迟加载DLL

    博客分类:
  • VC
阅读更多

延迟加载DLL 


Microsoft Visual C++ 6.0提供了一个出色的新特性,它能够使DLL的操作变得更加容易。这个特性称为延迟加载DLL。延迟加载的DLL是个隐含链接的DLL,它实际上要等到你的代码试图引用DLL中包含的一个符号时才进行加载。延迟加载的DLL在下列情况下是非常有用的: 


1)如果你的应用程序使用若干个DLL,那么它的初始化时间就比较长,因为加载程序要将所有需要的DLL映射到进程的地址空间中。解决这个问题的方法之一是在进程运行的时候分开加载各个DLL。延迟加载的DLL能够更容易地完成这样的加载。 

2)如果调用代码中的一个新函数,然后试图在老版本的系统上运行你的应用程序,而该系统中没有该函数,那么加载程序就会报告一个错误,并且不允许该应用程序运行。你需要一种方法让你的应用程序运行,然后,如果(在运行时)发现该应用程序在老的系统上运行,那么你将不调用遗漏的函数。例如,一个应用程序在Windows 2000上运行时想 

要使用PSAPI函数,而在Windows 98上运行想要使用ToolHelp函数(比如Process32Next)当该应用程序初始化时,它调用GetVersionEx函数来确定主操作系统,并正确地调用相应的其他函数。如果试图在Windows 98上运行该应用程序,就会导致加载程序显示一条错误消息,因为Windows 98上并不存在PSAPI.dll模块。同样,延迟加载的DLL能够使你 

非常容易地解决这个问题。 


下面让我们从比较容易的操作开始介绍,也就是使延迟加载DLL能够运行。首先,你象平常那样创建一个DLL。也要象平常那样创建一个可执行模块,但是必须修改两个链接程序开关,并且重新链接可执行模块。下面是需要添加的两个链接程序开关: 

/Lib:DelayImp.lib 

/DelayLoad:Mydll.dll 

Lib开关告诉链接程序将一个特殊的函数--delayLoadHelper嵌入你的可执行模块。第二个开关将下列事情告诉链接程序: 

1)从可执行模块的输入节中删除MyDll.dll,这样,当进程被初始化时,操作系统的加载程序就不会显式加载DLL。 

2)将新的Delay Import(延迟输入)节(称为.didata)嵌入可执行模块,以指明哪些函数正在从MyDll.dll的输入。 

3)通过转移到对--delayLoadHelper函数的调用,转换到对延迟加载函数的调用。当应用程序运行时,对延迟加载函数的调用实际上是对--delay LoadHelper函数的调用。该函数引用特殊的Delay Import节,并且知道调用LoadLibrary之后再调用GetProcAddress。一旦获得延迟加载函数的地址, --delayLoadHelper就要安排好对该函数的调用,这样,将来的调用就会直接转向对延迟加载函数的调用。注意,当第一次调用同一个DLL中的其他函数时,必须对它们做好安排。另外,可以多次设定/delayLoad链接程序的开关,为想要延迟加载的每个DLL设定一次开关。 

好了,整个操作过程就这么简单。但是还应该考虑另外两个问题。通常情况下,当操作系统的加载程序加载可执行模块时,它将设法加载必要的DLL。如果一个DLL无法加载,那么加载程序就会显示一条错误消息。如果是延迟加载的DLL,那么在进行初始化时将不检查是否存 

在DLL。如果调用延迟加载函数时无法找到该DLL,--delayLoadHelper函数就会引发一个软件异常条件。可以使用结构化异常处理(SEH)方法来跟踪该异常条件。如果不跟踪该异常条件,那么你的进程就会终止运行.当--delayLoadHelper确实找到你的DLL,但是要调用的函数不在该DLL中时,将会出现另一个问题。比如,如果加载程序找到一个老的DLL版本,就会发生这种情况。在这种情况下,--delayLoadHelper也会引发一个软件异常条件,对这个软件异常条件的处理方法与上面相 

同。下一节介绍的示例应用程序显示了如何正确地编写SEH代码以便处理这些错误。你会发现代码中有许多其他元素,这些元素与SEH和错误处理毫无关系。但是这些元素与你使用延迟加载的DLL时可以使用的辅助特性有关。下面将要介绍这些特性。如果你不使用更多的高级特性,可以删除这些额外的代码。 

如你所见, Visual C++ 开发小组定义了两个软件异常条件代码,即VcppException(ERROR_SEVERITY_ERROR,ERROR_MOD_NOT_FOUND)和VcppException(ERROR_SEVERITY_ERROR、ERROR_PROC_NOT_FOUND)。这些代码分别用于指明DLL模块没有找到和函数没有找到。 


到现在为止,已经讲述了如何使用延迟加载的DLL和正确解决错误条件的基本方法。但是Microsoft的延迟加载DLL的实现代码超出了迄今为止我已讲述的内容范围。比如,你的应用程序能够卸载延迟加载的DLL。假如你的应用程序需要一个特殊的DLL来打印一个文档,那么这个DLL就非常适合作为一个延迟加载的DLL,因为大部分时间它是不用的。不过,如果用户选择了Print命令,你就可以调用该DLL中的一个函数,然后它就能够自动进行DLL的加载。这确实很好,但是,当文档打印后,用户可能不会立即打印另一个文档,因此可以卸载这个DLL,释放系统的资源。如果用户决定打印另一个文档,那么DLL就可以根据用户的要求再次加载,若要卸载延迟加载的DLL,必须执行两项操作。首先,当创建可执行文件时,必须设定另一个链接程序开关( /delay:unload)。其次,必须修改源代码,并且在你想要卸载DLL时调用--

FunloadDelayLoaded DLL函数: 

/delay:unload链接程序开关告诉链接程序将另一个节放入文件中。该节包含了你清除已经调用的函数时需要的信息,这样它们就可以再次调用--delayLoadHelper函数。当调用--

FunloadDelayLoaded DLL时,你将想要卸载的延迟加载的DLL的名字传递给它。该函数进入文件中的未卸载节,并清除DLL的所有函数地址,然后--FunloadDelayLoaded DLL调用FreeLibrary,以便卸载该DLL。 



下面要指出一些重要的问题。 

首先,千万不要自己调用FreeLibrary,来卸载DLL,否则函数的地址将不会被清除,这样,当下次试图调用DLL中的函数时,就会导致访问违规。 

第二,当调用--FunloadDelayLoaded DLL时,传递的DLL名字不应该包含路径,名字中的字母必须与你将DLL名字传递给/DelayLoad链接程序开关时使用的字母大小写相同,否则, --FUnloadDelayLoaded DLL的调用将会失败。 

第三,如果永远不打算卸载延迟加载的DLL,那么请不要设 

定/delay:unload链接程序开关,并且你的可执行文件的长度应该比较小。 

最后,如果你不从用/delay:unload开关创建的模块中调用--FunloadDelayLoaded DLL,那么什么也不会发生, --

FunloadDelayLoaded DLL什么操作也不执行,它将返回FALSE。 

延迟加载的DLL具备的另一个特性是,按照默认设置,调用的函数可以与一些内存地址相链接,在这些内存地址上,系统认为函数将位于一个进程的地址中。由于创建可链接的延迟加载的DLL节会使你的可执行文件变得比较大,因此链接程序也支持一个/Delay:nobind开关。因为人们通常都喜欢进行链接,因此大多数应用程序不应该使用这个链接开关。

延迟加载的DLL的最后一个特性是供高级用户使用的,它真正显示了Microsoft的注意力之 

所在。当--delayLoadHelper函数执行时,它可以调用你提供的挂钩函数。这些函数将接收--

delayLoadHelper函数的进度通知和错误通知。此外,这些函数可以重载DLL如何加载的方法以及如何获取函数的虚拟内存地址的方法。 

分享到:
评论

相关推荐

    DelayLoadDll_Test_延时加载_延时加载的实现_

    用于实现在windows平台下的DLL延时加载技术

    动态加载DLL实例 C++实现

    有时候我们不希望出现一运行就加载DLL,而希望在使用到时候...或者我们希望针对相同接口的DLL有选择地加载,那么我们就需要动态加载DLL(延迟载入). 该实例代码演示了动态加载DLL的方法,代码用C++实现,供有需要的朋友参考.

    Lua加载Dll库来扩展功能

    lualib.dll 自测试用的,仅有三个函数:lua_sleep-延时,showm-返回文本,lua_moveto-返回2个数值 太多的东西,没弄明白。 LuaTest.exe 非常简单的LUA执行程序,代替黑窗口_a testlua.lua 不解释了 说明.txt 本文件...

    精选_DLL延迟加载_源码打包

    DLL延迟加载

    把一个动态链接库作为一个资源嵌入到可执行文件,在可执行文件运行时,自动从资源中释放出来,通过静态加载延迟实现DLL函数的动态加载

    介绍了如何把一个动态链接库作为一个资源嵌入到可执行文件,在可执行文件运行时,自动从资源中释放出来,通过静态加载延迟实现DLL函数的动态加载,程序退出后实现临时文件的自动删除,从而为解决“DLL Hell”提供...

    C#程序实现动态调用DLL的研究

    介绍了如何把一个动态链接库作为一个资源嵌入到可执行文件,在可执行文件运行时,自动从资源中释放出来,通过静态加载延迟实现DLL函数的动态加载,程序退出后实现临时文件的自动删除,从而为解决“DLL Hell”提供...

    C#动态调用Dll的研究

    介绍了如何把一个动态链接库作为一个资源嵌入到可执行文件,在可...动从资源中释放出来,通过静态加载延迟实现DLL函数的动态加载,程序退出后实现临 时文件的自动删除,从而为解决“DLL Hell”提供了一种解决方案。

    blazor-lazy-loading:支持Blazor的自动延迟加载(服务器和WebAssembly)

    Blazor WebAssembly和Blazor Server的自动延迟加载支持!

    Windows软件部署助手

    尽量多的进行些操作,将可能延迟加载的dll加载好。 3.回到这个部署助手里,单击提示对话框确定按钮。 4.助手将收集所有的dll。选择发布的时候要带的DLL 5.然后单击“收集DLL”,将选择的文件拷贝到指定文件夹。 6....

    ExtAspNet_v2.3.2_dll

    -修正了使用IFrameUrl的Tab在切换过程中会重复加载的问题,这是一个在v2.1.6引入的问题(feedback:eroach)。 -修正了启用AutoPostBack的Grid,其RowClick会覆盖LinkButtonField, HyperLinkField, CheckBoxField的...

    windows程序编程

    如何为32位和64位Windows系统构建和实现应用程序 如何新建和处理进程与作业; 如何调度....如何为延迟加载、API拦截和进程注入构建DLL;如何使用结构化异常处理、Windows错误恢复和应用程序重启等机制。

    Windows Process Analysis Tools (Windows程序分析工具源码)

    主要功能:查看进程,线程,模块,堆内存,窗口,挂起线程,结束线程,卸载模块,CPU使用率,内存使用率,附加pe文件解析,支持查看导入表,导出表,重定位表,资源表,TLS表,延迟加载等.. 附加功能:dll注入(win32/x64),无模块Pe...

    补丁制作工具

    一款不错的补丁制作工具 [+] 支持补丁模式:  - 文件偏移。  - 虚拟地址(VA)。  - 相对虚拟地址(RVA)。  [+] 支持32位 和 64位的 PE 文件(EXE,DLL)。... [+] 定时加载器延迟(毫秒)和超时(秒)选项。

    深入理解_Java_虚拟机 JVM_高级特性与最佳实践

    / 126 5.3.5 选择收集器降低延迟 / 130 5.4 本章小结 / 133 第三部分 虚拟机执行子系统 第6章 类文件结构 / 136 6.1 概述 / 136 6.2 无关性的基石 / 136 6.3 Class类文件的结构 / 138 6.3.1 魔数与Class文件...

    120项优化键值

    不加载多余的DLL文件 不显示Administrator超级用户 不显示共享文档和用户文档 不在桌面上显示系统版本 彻底隐藏文件 打开IE安全设定的隐藏项目 打开XP资源管理器的状态栏 打开启动优化功能 登记你的 Windows XP 登陆...

    蒋勇API支持库2.5.2带静态库(终极版)

    user32.dll。 参数的名称为“函数名”,类型为“文本型(text)”。FindWindow。 参数的名称为“用户自定义子程序指针”,类型为“子程序指针(SubPtr)”。用户注意这个自己定义的子程序必须和原来api保持一样的...

    windows API编程(冉林仓)第二章源代码

    第2章 动态链接库  2.1 动态链接库简介  2.2 用程序加载动态链接库  2.3 动态链接库的入口点  2.4 动态链接库的数据共享 ... 2.7 动态链接库的延迟加载  2.8 小结  2.9 思考题  2.10 练习题

    vc++ 应用源码包_6

    代码里用了备份dll的方法,因此在自定义的函数中可以直接调用在内存中备份的dll代码,而不需要再把函数头部改来改去。 IOCP反弹远控客户端模型,外加上线服务端,全部代码注释! 如题。这个是IOCP远程控制软件的...

    可同时浏览XPS和PDF文档类型的程序源代码

    本软件经过测试,可以在不装DevExpress的电脑上运行和编译,当然更不需要安装Acrobat阅读软件了,但编程加载PDFViewer的设计界面时可能会提示不能显示,未找到原因,有可能是某些Dll未完全从DevExpress拷贝过来,...

    DGIS.DesktopShare

    用C#编写的一款windows下进行流畅屏幕共享的库,采用UDP广播进行数据的传输,同屏延迟测试局域网内0.17秒左右。(备注:DGIS.UDP.Service.dll提交加载失败,请删除这个程序集即可)

Global site tag (gtag.js) - Google Analytics