《windows核心编程系列》谈谈dll
DLL全称dynamic linking library.即动态链接库。广泛应用与windows及其他系统中。因此对dll的深刻了解,对计算机软件开发专业人员来说非常重要。
windows中所有API都包含在DLL中。三个最重要的DLL是Kernel32.dll,User32.dll,GDI32.dll。
使用dll的好处:
1:扩展了应用程序的特性。
2:简化了项目管理
可以让不同的开发团队管理不同的模块。
3:有助于节省内存。
一个dll可被多个程序共享。多个程序调用同一个dll内的同一个函数时,系统却只需将该dll加载一次。
4:促进资源共享。
5:促进了本地化
可以使应用程序只包含代码但不包含用户界面组件。
6:有助于解决平台间差异。
使用延迟加载机制,程序仅仅加载需要的函数,使程序可以在老版本的系统中运行,可不是在某些函数不被兼容时拒绝运行。
7:可以用于特殊目的。
如钩子等等。
在应用程序可以调用dll中的函数之前,必须将dll载入进程地址空间。可以通过两种方式实现:一种是通过隐式载入时链接。另一种是显式运行时链接。
在载入之前,必须要构造DLL文件。下面我们来谈谈dll的构造。
1:创建一个头文件。该头文件包含我们想要在dll中导出的函数原型、结构以及符号。构建dll时所有的源文件都必须包含该头文件。另外可执行文件也需要该头文件。
2:创建源文件来实现dll模块中想要导出的函数和变量。该源文件在构造可执行文件时并不需要该源文件。
3:编译器对每个源文件处理,并分别产生一个obj文件。
4:链接所有的obj模块。产生独立的dll映像文件。该文件在构建可执行文件时被使用。
5:如果dll文件中输出了至少一个函数或变量,链接器还会生成lib文件。他只是列出了所有被导出的函数和变量的符号名。为了构建可执行模块,在可执行模块代码链接时,该文件也是必需的。
构建可执行模块:
1:所有源文件中包含dll开发人员创建的dll的头文件。
2:创建源文件。包含所有函数和变量。代码中可以引用dll的函数和变量。
3:为每个源文件产生obj文件。
4:将所有obj文件链接,生成独立的可执行映像文件。该文件中包含所有二进制代码预计全局静态变量。还包含一个导入段,列出了他需要的dll模块的名称,以及可执行文件的二进制代码从中引用的函数和变量的符号名。
执行:
加载程序为新建进程申请一个地址空间区域,然后将可执行模块映射到地址空间中。加载程序解释exe文件的导入段,对导入段中每个dll,加载程序会在系统中对dll模块进行定位,并将该dll映射到进程的地址空间中。如果dll需要从其他dll导入变量或函数,其他dll也会被映射到进程地址空间,执行类似的操作。将所有dll映射到进程地址空间后,就可以开始运行了。
构建dll模块。
dll中通常只包含函数或变量,并不包含消息循环或创建窗口的代码,因此创建dll文件相对容易。要注意在实际使用中,为了去掉代码的抽象层,应该避免从dll中导出变量。
首先应该创建一个包含想要导出的变量或函数声明的头文件。所有dll的源文件都应该包含这个文件,所有需要导入这些函数和变量的可执行模块的源文件也要包含该文件。
看例子:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Mydll.h dll头文件。
#ifndef MYLIBAPI
#define MYLIBAPI extern"C" _declspec(dellimport)//用于可执行模块。
#endif
MYLIBAPI export_variable;
MYLIBAPI int export_func();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
dll源文件。
#define MYLIBAPI extern"C" _declspec(dllexport))//如果编译器看到一个变量函数或是C++类是使用此修饰符
//修饰的,他就知道应该在dll模块中导出该变量。
//另外要注意,在dll的头文件中,MYLIBAPI一定要在包含dll的
//头文件之前定义
//否则预处理器就会因为未定义MYLIBAPI而将MYLIBAPI定义为_desclspec(import)
#include "Mydll.h"
int export_varibale;//在源文件中的变量定义时,可以不使用_declspec(dllexport)修饰符,因为编译器在解析头文件时 //会记住应该导出那些函数或变量。<
补充:软件开发 , 其他 ,