楔子
在VB.NET视频的学习中,再次碰见了了DLL这个东东。之前做的两个简单的小系统就和DLL打过交道,那时在知道DLL是动态链接库的英文缩写后就把它给放过了。结果现在的VB.NET视频的学习中DLL又出现了,果然不愧是老师说的“欠下的总会还的”。今天我们从DLL和DLL文件进行下脑补~~~
DLL
DLL是动态链接库的英文缩写,其全称为Dynamic Link Library。是软件界中的巨人微软公司在Windows系统中实现共享函数库概念的一种方式。
DLL主要用于共享和更新这两个方面。在共享方面,DLL主要是通过DLL文件(下文将对DLL文件做初步的阐述分享)实现数据在时间维度和个体层次上的共享。
其中数据在时间维度上的共享指的是多个应用程序可以同时访问内存中单个DLL副本中的内容。而在阐述数据在个体层面上的共享之前,有必要向大家讲解下什么是异函数。异函数就是实现相同功能的由不同语言进行编写的函数。例如同样的错误处理语言,在VB中体现的是On Error Goto,而在.NET中的大多数语言中,则体现的是Try Catch。而所谓的异函数调用就是通过DLL,我们可以赋予进程调用不属于其可执行代码的函数。而这种方法类似于我们在设计模式中接触到的Adapter
Pattern。
更新方面,DLL主要在我们队大型系统的更新时发力。比如一个几十G的3D游戏需要更新一个角色时,我们不必要为了重构那些几个G的软件代码,只需要添加相应的DLL文件或者对相应的DLL文件进行更新即可实现我们的完善性维护既定的目标。
DLL文件
定义
动态链接库文件(Dynamic Link Library Documents)又称“应用程序拓展”,是一种不可执行的二进制文件,属软件文件类型。DLL Documents一般存在放电脑的“C/Windows/System32”目录中。它能允许程序共享执行特殊任务所必需的代码和其他资源。现在我们所使用的许多应用程序并不是一个完整的不可分的整体意义上的可执行文件,而是由许多被分割相对独立的动态链接库文件组成。这点与面向对象思想不谋而合,既提高了代码的呃复用性,而且更有利于代码的维护和扩展。
分类
在Windows操作系统中的一些实现DLL的文件有
.ActiveX(.ocr)文件
根据微软权威的软件开发指南MSDN(Microsoft Developer NetWork)的定义,Active控件也称OLE控件或者OCX控件。它是一些组件或者对象,可以将其插入到Web网页或者其他应用程序中,从而为Web页面或者其他应用程序提供多媒体效果、交互式对象和复杂程序等功能。举例:日历控件,从日历中选择日期。ActiveX——百度百科
.CPL文件
CPL(Control Panel Item)文件也称控制面板项,多保存于系统安装目录中的System32文件下。它们分别对应着控制面板中的项目。普通用户没有相应的访问权限。CPL文件本质是Windows可执行文件,但不属于可以直接独立运行的文件,需要通过shell32.dll文件打开。CPL文件——百度百科
.DRV文件
.DRV(Device Driver)文件,一种使得计算机和其设备进行通信的文件,一如之前我们在《操作系统概论》中接触到的通道机制。Device
Driver——百度百科
特点
一、使用较少的资源
当多个程序同时使用一个函数库时,DLL可以通过构建多个副本来让多个程序进行相应的访问,以减少DLL文件在磁盘和物理内存已经缓存中加载的代码量。(颇有一种美猴王拔毛变小猴子的感觉)
二、推广模块式体系结构
DLL文件本身就是面向对象思想中封装的良好的体现,这就使得我们在开发提供多个语言版本的大型系统时或者具有模块式体系结构的程序时相当的简单。
三、简化部署和安装
当一个系统中的DLL文件需要更新或需要进行相应的改动时,部署和安装新的DLL不需要进行系统和DLL文件的二次链接。此外,若多个模块共享一个DLL文件,那么这些所有的模块都将从本次更新或者修改中收益。
依赖项
当某个程序或者一个DLL文件需要调用其他DLL文件时,就会在相应的程序或者DLL文件中创建一个依赖项以便DLL调用成功。在调用了DLL文件后,该程序或者说该DLL文件将不再是独立的。且如调用的DLL文件出现问题,那么调用该DLL文件的程序或者DLL文件也将出现相应的问题。
使用
链接
应用程序中加载DLL时,可以通过两种链接方法进行调用:动态链接和运行时动态链接。在运行时动态链接,应用程序调用LoadLibraryEx函数以在运行时加载DLL。成功加载DLL后,可以使用GetPro从Address函数获得需要调用的导出的DLL函数的地址,在使用运行时动态链接时,不需要导入库文件。
入口点
在创建DLL时,可以有选择地制定入口点函数。当进程或者线程自身将它们附件到DLL或 者将它们自身从DLL中分离时,将调用入口点函数。我们可以使用入口点函数进行数据结构的初始化或者数据结构的清零工作。若应用程序时多线程的,我们可以在入口点函数中使用线程本地存储(TLS)来分配各个线程专用的内存。DLL入口函数的示例:
<span style="font-family:KaiTi_GB2312;font-size:24px;">BOOL APIENTRY DllMain( HANDLE hModule, // DLL模块的句柄 DWORD ul_reason_for_call, // 调用本函数的原因 LPVOID lpReserved // 保留 ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: //进程正在加载本DLL break; case DLL_THREAD_ATTACH: //一个线程被创建 break; case DLL_THREAD_DETACH: //一个线程正常退出 break; case DLL_PROCESS_DETACH: //进程正在卸载本DLL break; } return TRUE; //返回TRUE,表示成功执行本函数 }</span>
当入口点函数返回值为FALSE时,如果我们使用的加载时动态链接,那么应用程序将不会被启动;若我们使用的运行时动态链接,那么只有个别的DLL文件不会被加载(应用程序可以被启动,但是部分功能不能使用。一些软件开发商用这种方法进行免费版和收费版的运行)。此外,入口点函数应该只执行简单的初始化任务,不应调用任何其他的DLL加载函数或者终止函数。
导出
我们可以通过向需要导出的DLL函数中添加函数关键字或者创建模板定义文件(.DEF文件)来实现DLL文件的导出。
向DLL文件中添加函数关键字:
_decispec(dllexport):通过该关键字声明需要导出的函数,从而得到使用函数关键字的权限。
_decispec(dllimport):使用该关键字声明需要导入的函数,从而得到使用导入函数的权限。
一般通过一个包含define语句和ifdef语句的头文件,区分导出语句和导入语句。
特别调用
在DLL函数中使用了Win32 API或者将一个语言生成的DLL供其他语言使用,需要进行相应的处理
一、在DLL函数中使用了Win32 API
需要关键字_stdcall的帮助
二、将一个语言生成的DLL供其他语言使用,以C++生成的DLL供标准C语言使用为例
1、输出文件需要用extern "C"修饰符
2、导出函数的格式应采用.def文件格式
如使用_stdcall调用方式,可能产生C不识别的修饰名,所以需要设置导出文件为.def文件形式,而不是_decispex(dllexport)形式。因为_decispec(dllexport)会进行修饰名转换,C语言无法识别。
故障排除
微软提供多个工具帮助我们进行DLL问题的解决,我们只介绍其中的(DW)Dependency Walker和DUPS(DLL Universal Problem Solver)。
DW
DW工具可以递归扫描以寻找才程序所使用的所有依赖DLL。当我们在DWr中打开应用程序时,DW将进行以下操作:
Dependency Walker 检查是否丢失 DLL。
Dependency Walker 检查是否存在无效的程序文件或 DLL。
Dependency Walker 检查导入函数和导出函数是否匹配。
Dependency Walker 检查是否存在循环依赖性错误。
Dependency Walker 检查是否存在由于针对另一不同操作系统而无效的模块。
通过使用 Dependency Walker,您可以记录程序使用的所有 DLL。这可能有助于避免和更正将来可能发生的 DLL 问题。当您安装 Microsoft Visual Studio 6.0 时, Dependency Walker 将位于以下目录中:
drive\Program Files\Microsoft Visual Studio\Common\Tools
DUPS
DUPS工具用于审核、比较、记录和显示 DLL 信息。下表说明了组成 DUPS 工具的实用工具:
Dlister.exe:该实用工具枚举计算机中的所有 DLL,并且将此信息记录到一个文本文件或数据库文件中。
Dcomp.exe:该实用工具比较在两个文本文件中列出的 DLL,并产生包含差异的第三个文本文件。
Dtxt2DB.exe:该实用工具将通过使用 Dlister.exe 实用工具和 Dcomp.exe 实用工具创建的文本文件加载到 dllHell数据库中。
DlgDtxt2DB.exe:该实用工具提供 Dtxt2DB.exe 实用工具的图形用户界面(GUI) 版本。
好了,关于DLL和DLL文件就和大家分享到这里。这些东西我也是第一次接触,有些地方还是很模糊的,喜欢大神们多多指教~~~
总结
通过DLL我们可以很方便地实现好多复杂功能,并且能从中体会到面向对象编程的种种好处,有道是“世界种种皆对象”,做个程序员真是太幸福了~~~
感谢您的宝贵时间,愿您幸福快乐。
-joker