第九讲 动态链接库
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
隐式链接与显式链接
利用VC可以编写各种DLL程序,其最终目的是在应用程序中调用 DLL。链接DLL到可执行程序有两种方式:
隐式链接(Implicit linking ) 显式链接(Explicit linking)
1.隐式链接 若在代码中没有明确指定应用程序要装入的动态链接库,但却使用 其中的某个函数,这种链接的方式称为隐式链接。
动态链接库是一个文件,其中包含有函数或全局变量,使用他们 就像应用程序使用自己定义的函数一样。用API开发Windows应用 程序,实质就是调用Windows操作系统下的动态链接库。它包含 函数,数据或资源等其他应用程序可用到的东西它可以在需要的时 候随时装入,
Windows操作系统都非常依赖于动态链接库(DLL)中的函数和 数据,实际上Windows操作系统中几乎所有的内容都由DLL以 一种或另外一种形式代表着。 我们在Windows目录下的system32文件夹中会看到 kernel32.dll、user32.dll和gdi32.dll,windows的大多数 API都包含在这些DLL中。kernel32.dll中的函数主要处理内存 管理和进程调度;user32.dll中的函数主要控制用户界面; gdi32.dll中的函数则负责图形方面的操作。 例如一般的程序员都用过类似MessageBox的函数,其实它就包 含在user32.dll这个动态链接库中。由此可见DLL对我们来说其 实并不陌生。
错误 1 fatal error LNK1104: 无法打开文件 “mylib.lib” MydllTester MydllTester 在运行程序之前,应将mylib.dll复制到应用程序可执行文件 所在的目录下。否则会出现图10.8所示的错误。
【例1】的运行结果
方法二.通过DEF文件指定 动态链接库DLL是通过导出函数和变量来实现代码共享的,外部程序 能通过这个导出过程来访问内部的函数和变量。 在VC 下,除了使用编译指令 dllexport 与dllimport 实现导出、导 入函数的指定外,还可以通过DLL工程中的DEF文件来实现,利用应用程 序向导生成的动态链接库中有一个和工程名同名的一个 .def 文件,例 如建立一个在 mydll.dll的动态链接库,则生成的mydll.def的主要内
DLL的优点
共享DLL,节省内存,减少动态交换 不同程序设计语言之间可以共享DLL 减少可执行代码大小 重用代码 大工程可分为易管理的小工程 实现新功能更容易、软件升级 在动态库的情况下,有两个文件 引入库(.LIB)文件 DLL文件 引入库文件包含被DLL导出的函数的名称和位置 DLL包含实际的函数和数据 应用程序使用LIB文件链接到所需要使用的DLL文件
静态链接库
多个应用程序,多个静态链接库的副本 占用较多的内存资源 在静态库情况下,函数和数据被编译进一个二进制文件(通常扩 展名为*.LIB) Visual C++的编译器在处理程序代码时将从静态库中恢复这些 函数和数据并把他们和应用程序中的其他模块组合在一起生成可 执行文件 "静态链接",此时因为应用程序所需的全部内容都是从库中复制 了出来,所以静态库本身并不需要与可执行文件一起发行
Windows在加载DLL的时候,需要一个入口函数,就如同控制台或 DOS程序需要main函数、WIN32程序需要WinMain函数一样。根 据编写规范,Windows必须查找并执行DLL里的DllMain函数作为 加载DLL的依据,它使得DLL得以保留在内存里。这个函数并不属 于导出函数,而是DLL的内部函数。这意味着不能直接在应用工程 中引用DllMain函数,DllMain是自动被调用的。
“一般C++类向导”窗口
声明为导出类
class _declspec(dllexport) CMath { public: CMath(void); ~CMath(void); };
在类CMath中添加一个sum()函数,代码如下:
int CMath::sum(int a, int b) { return a +b; }
方法一.通过扩展关键字dllexport 与dllimport 指定 从一个动态链接库中导出一个函数可以通过如下的语句来完成 __declspec( dllexport ) void MyFunction(int i) { //动态链接库中的函数MyFunction的实现代码 } 其中__declspec是一个扩展关键字,其作用和具有一个参数的 函数类似,实际上,它与它的“参数”一起构成了一个“标志”,即 “ __declspec( dllexport) ”,该语句的含义为“出现在我后面的 函数在当前的动态链接库文件中被合法导出,外部应用程序可以使用 这个函数”。 从一个动态链接库中导入一个函数可以通过如下的语句来完成 __declspec( dllimpot ) void MyFunction(int i); __declspec(dllimpot ) 的 含 义 为 “ 出 现 在 我 后 面 的 函 数 MyFunction是从动态链接库文件中导入的函数”。
动态链接库
与静态链接库不同,动态链接库则允许若干个应用程序共享某个 函 数 的 单 个 副 本 。 事 实 上 , 每 个 Windows API 函 数 , 如 GetMesssage()、CreateWindow() 和 TextOut() 分别留于动态链接库 —— Kernel32.dll、User32.dll、Gdi32.dll 之中。如果两个应用 程序同时运行,且都使用了某个特定的Windows函数,那么它们将共 享该函数代码的单个副本。DLL除了实现代码的共享外,还可以实现 其它资源的共享,如数据和硬件资源的共享。Windows的设备驱动程 序允许应用程序共享硬件资源,这些设备驱动程序就是以动态链接 库的形式来出现。 从某种程度上讲,动态链接库也是一种类型的计算机资源。一个 动态链接库可以为多个应用程序使用,如果一个应用程序使用了某 个动态链接库中函数,若库不存在,则调用将不能完成。
静态链接与动态链接
DLL与运行函数库(如C语言的运行函数库)类似,二者主要 区别在于库代码的链接时机不同。 DLL是在运行期间才被链接进来,该操作由Windows操作系 统自身来完成,而运行函数库则是在程序链接期间由应用程序的链 接器如LINK.EXE来完成,运行函数库的链接被称为“静态链接”, 它把函数代码链接到应用程序中,增加了应用程序最终执行代码的 长度。它的主要优点是建立了一个应用程序可以利用的标准函数集。 静态链接库在多任务环境中建立与运行时效率可能很低。一方面, 如果两个应用程序同时运行,且它们使用了同一个静态库中的函数, 那么就要求系统中出现该函数的两个副本,这显然降低了内存的使用 效率。另一方面,对于比较复杂的问题,应用静态链接库将导致最终 的应用程序长度超过系统内存而无法运行。
单击“下一步”按钮,打开“应用程序配置”对话框,在“应用程 序”列表中选择“DLL”如图10.3所示。
“应用程序配置”对话框
DllMain()是DLL源自文库入口函数
#include "stdafx.h"
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH://进程映射 case DLL_THREAD_ATTACH://线程映射 case DLL_THREAD_DETACH://进程卸载 case DLL_PROCESS_DETACH://线程卸载 break; } return TRUE; }
第九讲
动态链接库
主讲:吕骏
动态链接库定义
动态链接库(Dynamic Link Library,简称DLL)是一个包含了若干 函数的可执行模块,它实质上是一个函数包,Windows应用程序可以 调用这些函数来完成实际的任务。DLL 在Windows 环境中起着重要的 作 用 — — Windows 利 用 DLL 来 建 立 Windows 应 用 程 序 可 以 使 用 的 Windows函数与资源。 动态链接库(DLL)是从C语言函数库的概念发展而来的。几乎所有的 Windows API都包含在DLL中
参数说明
hModule,DLL的句柄。 ul_reason_for_call,用于指定调用DLL入口函数的原因,其取 值如表所示。 lpReserved,指定DLL初始化和清理的方式。当dwReason等 于DLL_PROCESS_ATTACH时,如果lpvReserved为NULL, 则表示动态加载;否则表示静态加载。当dwReason等于 DLL_PROCESS_DETACH时,如果lpvReserved为NULL,则 DllMain()函数由FreeLibrary()函数调用;否则表示在结束进程 时调用DllMain()函数。
#include "stdafx.h" #include <windows.h> // 从DLL导入的函数 extern “C” int sum(int a, int b);//在使用DLL中的导出函数之前,应 声明函数的原型。 int _tmain(int argc, _TCHAR* argv[]) { printf("4+3 = %d\n", sum(4, 3)); system("Pause"); return 0; }
加载时动态链接
使用加载时动态链接的程序需要引用导入库(*.lib文件)。在引 用DLL的项目中,打开“项目属性”对话框,左侧的“配置属性 ”树中,依次选择“链接器”/“输入”,在右侧的“附加依赖 项”中添加导入库。
提示
在编译和生成程序之前,应将mylib.lib复制到项目目录下。 否则会出现下面的错误。
动态链接库中函数的导出与导入
动态链接库是一个.DLL文件 ,它存放在特定的位置上。程序 员所创建的动态链接库中的函数要有导出标志,在使用动态链接库 中的函数的程序中,要具有导入标志。 动态链接库中的函数并不是杂乱无章地堆放在一起,它们都有 一个标志,即动态链接库中的导出标志。同样,如果应用程序要使 用该库中的函数,也要向动态链接库发出“是否有我们想要的函数 ”,这通过导入标志来进行。双方必须达成一致后才能使用。
创建动态链接库项目(非mfc方式)
在Visual Studio 2010中打开“新建项目”对话框,在“项 目类型”列表中,选择“Visual C++”/“Win32”,然 后在右侧的模板列表中选中“Win32项目”。 在“名称”文本框中输入mylib,然后单击“确定”按钮,
Win32应用程序向导
【例1】演示如何使用加载时动态链接的方法引 用mylib.dll中的导出函数。
创建一个控制台应用程序MydllTester,(不要选空项目)将 mylib.lib复制到项目目录下。参照图将mylib.lib添加到项目链 接器的附加依赖项中。 在程序中调用mylib.dll中的sum()函数,计算3+4的和,代码 如下:
2.显式链接
显 示 链 接 , 又 称 显 式 调 用 , 是 由 编 程 者 用 API 函 数 LoadLibrary() 加载 DLL、并通过 GetProcessAddress() 来获取应 用程序要调用的导出函数指针来调用 DLL 的导出函数,最后通过 FreeLibrary()卸载DLL。它是一种动态调用的方式,通过它能够 有效地使用内存,是编制大型应用程序的重要方式。
在DLL中添加导出函数
extern "C"__declspec(dllexport) int sum(int a, int b) { return a +b; }
在DLL中添加导出类
在DLL项目中添加类的方法和在其他项目中添加类的方法是一 样的。在菜单中选择“项目”/“添加类”,打开“添加类” 窗口。