包括刚才提到过的通用文件对话框在内,DLL文件提供了应用程序间共享资源的可能。资源可以是程序对话框、字符串、图标,或者声音文件等。
⑤ 解决应用程序本地化问题
在下载了某个程序的汉化包后,打开汉化说明,经常可以看到用下载包中的DLL文件覆盖掉程序原来的DLL,汉化就完成了。这些程序都是将执行代码和应用程序界面分开编写了,所以汉化者只需简单地将其中和程序界面相关的DLL汉化并发布即可。
3 隐式链接和显式链接
应用程序导入函数与DLL文件中的导出函数进行链接有两种方式:隐式链接和显式链接。
隐式链接(load-time dynamic linking)是指在应用程序中不需指明DLL文件的实际存储路径,程序员不需关心DLL文件的实际装载(由编译器自动完成地址分配)。采用隐式链接方式,程序员在建立一个DLL文件时,链接程序会自动生成一个与之对应的LIB导入文件。该文件包含了每一个DLL导出函数的符号名和可选的标识号,但是并不含有实际的代码。LIB文件作为DLL的替代文件被编译到应用程序项目中。当程序员通过静态链接方式编译生成应用程序时,应用程序中的调用函数与LIB文件中导出符号相匹配,这些符号或标识号进入到生成的EXE文件中。LIB文件中也包含了对应的DLL文件名(但不是完全的路径名),链接程序将其存储在EXE文件内部。当应用程序运行过程中需要加载DLL文件时,Windows根据这些信息发现并加载DLL,然后通过符号名或标识号实现对DLL函数的动态链接。我们使用的大部分系统Dll就是通过这样的方式链接的。若找不到需要的Dll则会给出一个Dll缺少的错误消息。
显式链接(run-time dynamic linking)与此相反。用户程序在编译的时候并没有指明需要哪些Dll,而是在运行起来之后调用Win32 的LoadLibary()函数,去装载Dll。若没有找到Dll则这个函数就会返回一个错误。在用LoadLibary()函数装载Dll之后,应用程序还需要用GetProcAdress()函数去获得Dll输出函数的地址。显式链接方式对于集成化的开发语言比较适合。有了显式链接,程序员就不必再使用导入文件,而是直接调用Win32 的LoadLibary()函数,并指定DLL的路径作为参数。还要说明一点的就是Known Dlls就是保证在通过LoadLibary()去装载系统Dll的时候,只从特定的系统目录去装载,防止装载错。装载的时候会去看注册表下是否有一样的注册表键名。
应用程序怎样找到DLL文件
如果应用程序使用LoadLibrary显式链接,那么在这个函数的参数中可以指定DLL文件的完整路径。如果不指定路径,或是进行隐式链接,Windows将遵循下面的搜索顺序来定位DLL:
I 包含EXE文件的目录,
II 进程的当前工作目录,
III Windows系统目录,
IV Windows目录,
V 列在Path环境变量中的一系列目录。
在Windows上有个注册表键值决定了Dll的搜索顺序:HKLMSystemCurrentControlSetSessionManagerSafeDllSearchMode。在windows 7,server2003,xp sp2中这个值为1,在xp,2000 sp4中为0。
1值时的搜素顺序为:1.可执行文件所在目录,2.系统目录windowssystem32,3. 16位系统目录,4.windows目录,5.当前进程目录。6.环境变量PATH中的目录。
0值时的搜素顺序为:1.可执行文件所在目录,2. 当前进程目录。3.系统目录windowssystem32,4. 16位系统目录,5.windows目录,6.环境变量PATH中的目录。
4 DLL的加载与连接
Windows DLL装入(除ntdll.dll外)和连接是通过ntdll.dll中一个函数LdrInitializeThunk实现的。先对LdrInitializeThunk()这个函数名作些解释“Ldr显然是“Loader”的缩写。而“Thunk”意为“翻译”、“转换”、或者某种起着“桥梁”作用的东西。这个词在一般的字典中是查不到的,但却是个常见于微软的资料、文档中术语。这个术语起源于编译技术,表示一小片旨在获取某个地址的代码,最初用于函数调用时“形参”和“实参”结合。后来这个术语有了不少新的特殊含义和使用,但是DLL的动态连接与函数调用时“形实结合”确实有着本质的相似。
DLL文件中包含一个导出函数表。这些导出函数由它们的符号名和称为标识号的整数与外界联系起来。函数表中还包含了DLL中函数的地址。当应用程序加载DLL模块时时,它并不知道调用函数的实际地址,但它知道函数的符号名和标识号。动态链接过程在加载的DLL模块时动态建立一个函数调用与函数地址的对应表。如果重新编译和重建DLL文件,并不需要修改应用程序,除非你改变了导出函数的符号名和参数序列。
5 DLL注册及为什么需要注册?
在系统故障中,有很多都是由于DLL文件丢失、损坏或没有注册造成的,比如Windows XP的压缩文件夹功能出现故障就很有可能是系统目录中的zipfldr.dll没有注册造成的,这类故障的解决方法也大多是下载一个对应的DLL并运行如下命令:
for%1 in (%windir%system32*.dll)do regsvr32.exe /s %1
很多人不理解为什么要这么做,是不是所有的DLL都能这样做呢?
其实系统中有两种DLL,一种是不需注册即可使用的,另一种则是必须经过注册才能使用的。就好像一个临时工,和一个记录在员工名单上的长期合同工的区别一样。如何才能区分这两种DLL呢?方法很简单,可以用一个工具(如Dependency Walker)打开这个DLL,看函数输出表,如果其中包含以下两个函数(前者是注册DLL,后者是反注册DLL),那么就一定是需要注册才能使用的DLL了。
DllRegisterServer
DllUnregisterServer
而regsvr32这个命令,实际上就是调用DLL中的这两个函数(“regsvr32 /u DLL文件名”调用的即为DllUnregisterServer反注册函数)。
注册与不注册,.dll文件都在system32下面。不同的是,注册了会在注册表中有相应信息,同时载入到了dll缓存,没有注册信息和进缓存就不能使用(开机时操作系统的一些核心功能再加载到了内存,并开始在后台运行,程序、数据、模块都需要进入内存才能被访问。)。
文件注册前和注册后都没有变化,只是通过命令把相应的信息添加到了注册表中。
注册文件的命令行是 regsrv32
regsrv32 xxx.dll
regsrv32 xxx.dll /u
regsvr32 [/u] [/s] [/n] [/i[:cmdline]] dllname
参数说明:
/u - 解除服务器注册
/s - 无声;不显示消息框
/i - 调用 DllInstall,给其传递一个可选 [cmdline];跟 /u 一起使用时,卸载 dll
/n - 不要调用 DllRegisterServer;这个选项必须跟 /i 一起使用
-End-返回搜狐,查看更多