2024年4月12日发(作者:)

关于DLL动态库调用小结

引言

比较大的应用程序都由很多模块组成,这些模块分别完成相对独立的功能,它们彼此

协作来完成整个软件系统的工作。可能存在一些模块的功能较为通用,在构造其它软件系

统时仍会被使用。在构造软件系统时,如果将所有模块的源代码都静态编译到整个应用程

序EXE文件中,会产生一些问题:一个缺点是增加了应用程序的大小,它会占用更多的磁

盘空间,程序运行时也会消耗较大的内存空间,造成系统资源的浪费;另一个缺点是,在

编写大的EXE程序时,在每次修改重建时都必须调整编译所有源代码,增加了编译过程的

复杂性,也不利于阶段性的单元测试。

Windows系统平台上提供了一种完全不同的较有效的编程和运行环境,你可以将独

立的程序模块创建为较小的DLL(Dynamic Linkable Library)文件,并可对它们单独编译

和测试。在运行时,只有当EXE程序确实要调用这些DLL模块的情况下,系统才会将它们

装载到内存空间中。这种方式不仅减少了EXE文件的大小和对内存空间的需求,而且使这

些DLL模块可以同时被多个应用程序使用。Windows自己就将一些主要的系统功能以DLL

模块的形式实现。

一般来说,DLL是一种磁盘文件,以.dll、.DRV、.FON、.SYS和许多以.EXE为扩展名

的系统文件都可以是DLL。它由全局数据、服务函数和资源组成,在运行时被系统加载到

进程的虚拟空间中,成为调用进程的一部分。如果与其它DLL之间没有冲突,该文件通常

映射到进程虚拟空间的同一地址上。DLL模块中包含各种导出函数,用于向外界提供服务。

DLL可以有自己的数据段,但没有自己的堆栈,使用与调用它的应用程序相同的堆栈模式;

一个DLL在内存中只有一个实例;DLL实现了代码封装性;DLL的编制与具体的编程语言

及编译器无关。

在Win32环境中,每个进程都复制了自己的读/写全局变量。如果想要与其它进程共

享内存,必须使用内存映射文件或者声明一个共享数据段。DLL模块需要的堆栈内存都是

从运行进程的堆栈中分配出来的。Windows在加载DLL模块时将进程函数调用与DLL文

件的导出函数相匹配。Windows操作系统对DLL的操作仅仅是把DLL映射到需要它的进

程的虚拟地址空间里去。DLL函数中的代码所创建的任何对象(包括变量)都归调用它的

线程或进程所有.

调用方式

1、静态调用方式(隐式调用):由编译系统完成对DLL的加载和应用程序结束时DLL

卸载的编码(如还有其它程序使用该DLL,则Windows对DLL的应用记录减1,直到所

有相关程序都结束对该DLL的使用时才释放它),简单实用,但不够灵活,只能满足一般

要求。

隐式的调用:需要把产生动态连接库时产生的.LIB文件加入到应用程序的工程中,想

使用DLL中的函数时,只须说明一下。隐式调用不需要调用LoadLibrary()和FreeLibrary()。

程序员在建立一个DLL文件时,链接程序会自动生成一个与之对应的LIB导入文件。该文

件包含了每一个DLL导出函数的符号名和可选的标识号,但是并不含有实际的代码。LIB

文件作为DLL的替代文件被编译到应用程序项目中。

当程序员通过静态链接方式编译生成应用程序时,应用程序中的调用函数与LIB文件

中导出符号相匹配,这些符号或标识号进入到生成的EXE文件中。LIB文件中也包含了对

应的DLL文件名(但不是完全的路径名),链接程序将其存储在EXE文件内部。