WIN32汇编语言教程:第11章 动态链接库和钩子 · 11.1 动态链接库(1)

11.1.1 动态链接库的概念

在DOS环境下编过程序的读者一定知道静态库的含义——程序员将实现各种功能的代码写成一个个子程序(函数),编译成obj文件后,将多个obj文件组合成一个lib文件,当程序中要用到这些函数的时候,只需要指定函数名称,编译器就可以从库中抽出对应的子程序代码插入到可执行文件中去,这样就可以不必一遍遍地重写相同的功能代码。这种链接方法就是静态链接,

静态链接的缺点显而易见,如果有多个程序用到库中的同样函数,那么所有这些可执行文件中都会包含一份同样的代码,对于每个程序几乎必须使用的一些函数来说,如果硬盘上有一万个程序用到这个函数,那么就存在一万份相同的代码,这显然是很浪费空间的。静态链接的另外一个缺点是:如果某个函数因为发现有错或更新算法等种种原因需要升级版本时,必须把所有用到此函数的可执行文件都找回来重新编译一遍,遗漏的程序中存在的还是旧版本的代码。

DOS操作系统是单任务的操作系统,每时每刻只能有一个程序在运行,所以使用静态链接浪费的空间仅表现在磁盘空间的浪费上;而Windows操作系统是多任务的,内存中会同时装入多个程序的代码,如果使用静态链接的话,意味着有多份相同的代码被装入内存,这种浪费代价将是更昂贵的。

Windows的解决办法就是使用动态链接库,动态链接库从表面上看也是提供了一大堆通用的函数,也可以被多个程序使用,但它和静态库的使用上有很多的不同点。

静态库仅在编译的时候使用,编译完成后,可执行文件就可以脱离库文件单独使用了,而动态链接库中的代码在程序编译的时候并不会被插入到可执行文件中,在程序运行的时候才将整个库的代码调入内存,所以称为“动态链接”。如果有多个程序用到同一个动态链接库,Windows在物理内存中只保留一份库的代码,仅通过分页机制将这份代码映射到不同进程的地址空间中,这样不管有多少程序在使用一个库,库代码实际占用的物理内存永远只有一份。当然,这时候库使用的数据段还是会被映射到不同的物理内存中,多少个程序在使用动态链接库就会有多少份数据段。DLL的工作方式在图1.6中就已经有所演示了。

当应用程序装载动态链接库的时候,程序中仅包括库的名称和函数的名称,这些信息是动态寻找对应函数所必须的,程序在编译和链接的时候必须插入这些定位信息,定位信息取自导入库文件,这一点在前面的编程中已经多次涉及。

动态链接库的缩写为DLL,大部分动态链接库是以扩展名为dll的文件形式存在的,但并不是只有dll扩展名的文件才是动态链接库,系统中的某些exe文件、字体文件(*.fon)、一些驱动程序(*.drv)、各种控件(*.ocx)和输入法模块(*.ime)等都是动态链接库。实际上,系统中大部分包含公用代码的模块——不管扩展名是什么——都有可能是动态链接库。

一个文件是否是动态链接库取决于它的文件结构,动态链接库文件和可执行文件同样使用标准的PE文件格式,仅文件头中的属性位不同而已,所以exe文件的一些特征也存在于动态链接库中,比如在动态链接库中也可以定义并使用各种资源,可以导入并使用其他动态链接库中的函数等。

有一个最重要的概念一定要牢记:动态链接库是被映射到其他应用程序的地址空间中执行的,它和应用程序可以看成是“一体”的,动态链接库可以使用应用程序的资源,它所拥有的资源也可以被应用程序使用,它的任何操作都是代表应用程序进行的,当动态链接库进行打开文件、分配内存和创建窗口等操作后,这些文件、内存和窗口都是为应用程序所拥有的。

11.1.2  编写动态链接库

与前面一些例子程序相比,写动态链接库程序应该算是很简单的,程序中并不需要用到新的函数,只是在程序的结构上和链接时的选项有些区别而已。让我们通过一个简单的例子来说明,例子代码在所附光盘的Chapter11\Dll\Dll目录中,包括汇编源文件Counter.asm和定义文件Counter.def。上一层子目录Chapter11\Dll中存放的是调用DLL的例子,其中的内容将在下一节中分析。

Counter.asm的内容如下:

               .386
               .model flat, stdcall
               option casemap :none
;####################################################################
; Include 文件定义
;####################################################################
include        windows.inc
include        user32.inc
includelib     user32.lib
include       kernel32.inc
includelib     kernel32.lib
;####################################################################
               .data?
dwCount        dd ?
;####################################################################
               .code
DllEntry       proc       _hInstance,_dwReason,_dwReserved
 
               mov    eax,TRUE
               ret
 
DllEntry       Endp
;####################################################################
_SetText       proc       _hWnd,_dwID,_dwCount
 
               invoke SetDlgItemInt,_hWnd,_dwID,_dwCount,TRUE
               ret
 
_SetText       endp       
;####################################################################
_IncCount  proc       _hWnd,_dwID
 
               inc    dwCount
               invoke _SetText,_hWnd,_dwID,dwCount
               mov    eax,dwCount
               ret
 
_IncCount      endp
;####################################################################
_DecCount  proc       _hWnd,_dwID
 
               dec    dwCount
               invoke _SetText,_hWnd,_dwID,dwCount
               mov    eax,dwCount
               ret
 
_DecCount      endp
;####################################################################
               End    DllEntry

程序很简单,既没有创建窗口的代码也没有创建对话框的代码,总之,程序没有任何和创建界面有关的代码,仅定义了4个子程序:DllEntry,_SetText,_IncCount和_DecCount。其中程序的入口点由最后一句End语句定义到了DllEntry处。而_SetText子程序被最后两个子程序调用,功能是将指定的数值显示到指定对话框的一个子窗口控件中。最后两个子程序的功能分别是对dwCount变量进行递增或递减的操作,并把操作结果显示在参数指定的对话框中的子窗口控件中。

一眼看上去,程序比较莫名其妙——入口的代码什么都没有做,仅返回一个TRUE;也没有地方用到_IncCount和_DecCount函数,这是为什么呢?请记住,dll文件的设计不是供自己使用的,而是被映射到其他应用程序的地址空间中代表“宿主”程序执行的,这两个函数就是供其他程序使用的函数,实际上对于“宿主”程序来说,虽然这两个函数仅包含3行代码,但它们的级别和User32.dll中的CreateWindowEx与DefWindowProc等极其复杂的函数没有任何区别。

1. 入口点和初始化代码

与可执行文件一样,动态链接库需要一个入口点,动态链接库的入口点是一个函数,函数的名称并不重要,例子代码中的入口函数命名为“DllEntry”,读者也可以把它取名为其他任何合法的名字,但入口函数的格式是有规定的。

库的入口函数对调用动态链接库的应用程序来说是不可见的,它仅供操作系统使用。Windows在库装载、卸载、进程中线程的创建和结束等时候调用入口函数,以便动态链接库可以采取相应的动作。在入口函数中可以通过参数来判别Windows的本次调用究竟是在哪种情况下发生的。入口函数的结构一般如下面所示:

上页:第10章 内存管理和文件操作 · 10.4 内存映射文件(4) 下页:第11章 动态链接库和钩子 · 11.1 动态链接库(2)

第11章 动态链接库和钩子

版权所有 © 云南伯恩科技 证书:粤ICP备09170368号