Windows系统编程 教学课件 ppt 作者 李晓黎 第10章

上传人:E**** 文档编号:89400741 上传时间:2019-05-24 格式:PPT 页数:45 大小:492KB
返回 下载 相关 举报
Windows系统编程 教学课件 ppt 作者  李晓黎 第10章_第1页
第1页 / 共45页
Windows系统编程 教学课件 ppt 作者  李晓黎 第10章_第2页
第2页 / 共45页
Windows系统编程 教学课件 ppt 作者  李晓黎 第10章_第3页
第3页 / 共45页
Windows系统编程 教学课件 ppt 作者  李晓黎 第10章_第4页
第4页 / 共45页
Windows系统编程 教学课件 ppt 作者  李晓黎 第10章_第5页
第5页 / 共45页
点击查看更多>>
资源描述

《Windows系统编程 教学课件 ppt 作者 李晓黎 第10章》由会员分享,可在线阅读,更多相关《Windows系统编程 教学课件 ppt 作者 李晓黎 第10章(45页珍藏版)》请在金锄头文库上搜索。

1、,Windows系统编程实用教程,授课教师: 职务:,第10章 动态链接库编程,课程描述 在开发比较大的程序时,往往需要多个程序员协作完成。有人负责数据库操作,有人负责文件操作,有人负责业务逻辑设计,有人负责用户界面设计。但是他们不能在同一台计算机上使用同一个项目来进行编码,因为这样不但在实际上很难操作,而且会把代码搞得很乱。通常的做法是:负责底层功能设计的程序员使用动态链接库实现具体功能,负责用户界面设计的程序员在项目中引用动态链接库,并调用其中的具体功能,这样就把多个程序员的工作集成到一个项目中。这种方法不仅解决了多人合作开发的问题,而且是程序具有很好的模块化,便于定位和调试问题。,本章知

2、识点,10.1 动态链接库的概念 10.2 开发动态链接库 10.3 加载和使用DLL,10.1 动态链接库的概念,动态链接库(DLL,Dynamic-link library)是微软实现的共享库概念,其文件扩展名通常为.dll,也可以是.ocx(包含Active控件的动态链接库)和.drv(系统驱动程序)。,1内存管理,DLL文件中可以分段管理,每个段(section)都有自己的属性,比如可写或只读、可执行(代码段)或不可执行(数据段)等。DLL中的代码通常可以在引用DLL的进程中共享,也就是说,它们在物理内存中占有独立的空间,但不占用页文件的空间。如果物理内存中被DLL代码段占用的空间需要

3、重新分配,则其中的内容会被忽略,下次使用时再从DLL文件中重新加载。 与代码段不同,DLL中得为数据段通常是私有的。使用DLL的每个进程都有自己的DLL数据复件。也可以把DLL的数据段配置成共享的,通过这种方式可以实现进程间的通信。但是,这也造成了一个安全漏洞。比如,一个进程可以破坏共享数据,从而导致其他使用共享数据的进程出现异常。因此,应尽量避免在DLL中使用共享数据。,2导入库,导入库的扩展名是*.lib,它与DLL文件同时生成,它们的名字相同,只有扩展名不同。导入库中包含一个导入地址表(IAT,import address table)。DLL中的每个函数都在导入地址表有一个记录。 如果

4、在项目中引用了DLL文件,则在生成和链接可执行文件时,链接到动态链接库通常被处理为链接到导入库。这样,可执行文件就可以通过导入库中的导入地址表知道如何调用DLL中的函数。导入库就像一本书的目录和索引,而DLL则是书的正文。在生成可执行文件时,可执行文件中已经包含了导入库中的导入地址表。在运行时,还必须找到DLL文件。可执行文件会根据导入地址表在DLL文件中调用函数。,3符号解析和生成,DLL中的每个导出函数都可以使用一个数字序号和一个可选的名字来标识。可以使用数字序号和名字从DLL中导入函数。序号代表DLL导出地址表中的函数地址指针的位置,通常用于只按序号导出内部函数的情形。而对大多数Wind

5、ows API函数而言,在不同的Windows产品和版本中,只有名字被保留,而序号是变化的。因此使用序号导入DLL函数的方法兼容性并不好。 使用序号导入DLL函数比使用名字导入DLL函数要稍微高效一点。DLL的导出表是按名字排序的,使用名字导入DLL函数要首先在导出表中找到名字的位置;而使用序号导入DLL函数则可以直接在导出表中定位函数的位置。 也可以将可执行文件绑定到特定版本的DLL,这样就可以在编译时解析导入函数的地址了。这也称为绑定导入。此时,链接器保存绑定导入的DLL文件的时间戳和校验和(checksum)。运行时,Windows首先检查使用的库是否与绑定的库版本相同,如果相同,则省略

6、处理导入的过程(因为在编译时已经解析并记录导入函数的地址了);否则,Windows会按照正常的方式来处理导入。 如果绑定DLL的可执行文件在与其编译环境相同的环境中运行,它就会运行得快一点。每个标准的Windows应用程序都绑定到一个版本的Windows的系统DLL。将应用程序的导入和其目标环境绑定的最佳时机实在安装应用程序的过程中。这样,除非升级操作系统,都会保持绑定库。,10.2 开发动态链接库,10.2.1 创建动态链接库项目 10.2.2 在DLL中添加导出函数 10.2.3 在DLL中添加导出类,10.2.1 创建动态链接库项目,在Visual Studio 2008中打开“新建项目

7、”对话框,在“项目类型”列表中,选择“Visual C+”/“Win32”,然后在右侧的模板列表中选中“Win32项目”,如图10.1所示。 在“名称”文本框中输入mylib,然后单击“确定”按钮,打开如图10.2所示的向导对话框。,Win32应用程序向导,单击“下一步”按钮,打开“应用程序配置”对话框,在“应用程序”列表中选择“DLL”如图10.3所示。,“应用程序配置”对话框,DllMain()是DLL的入口函数,#include “stdafx.h“ BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPV

8、OID 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; ,参数说明,hModule,DLL的句柄。 ul_reason_for_call,用于指定调用DLL入口函数的原因,其取值如表10.1所示。 lpReserved,指定DLL初始化和清理的方式。当dwReason等于DLL_PROCESS_ATTACH时,如果lpvRese

9、rved为NULL,则表示动态加载;否则表示静态加载。当dwReason等于DLL_PROCESS_DETACH时,如果lpvReserved为NULL,则DllMain()函数由FreeLibrary()函数调用;否则表示在结束进程时调用DllMain()函数。,10.2.2 在DLL中添加导出函数,extern “C“_declspec(dllexport) int sum(int a, int b) return a +b; ,10.2.3 在DLL中添加导出类,在DLL项目中添加类的方法和在其他项目中添加类的方法是一样的。在菜单中选择“项目”/“添加类”,打开“添加类”窗口。,“一般C

10、+类向导”窗口,声明为导出类,class _declspec(dllexport) CMath public: CMath(void); CMath(void); ; 在类CMath中添加一个sum()函数,代码如下: int CMath:sum(int a, int b) return a +b; ,10.3 加载和使用DLL,10.3.1 加载时动态链接 10.3.2 运行时动态链接 10.3.3 搜索DLL文件的次序,10.3.1 加载时动态链接,使用加载时动态链接的程序需要引用导入库(*.lib文件)。在引用DLL的项目中,打开“项目属性”对话框,左侧的“配置属性”树中,依次选择“链接

11、器”/“输入”,在右侧的“附加依赖项”中添加导入库。,1使用DLL中的导出函数,在使用DLL中的导出函数之前,应声明函数的原型。比如10.2.2小节介绍的sum()函数的声明如下: extern “C“ int sum(int a, int b);,【例10.1】,演示如何使用加载时动态链接的方法引用mylib.dll中的导出函数。 创建一个控制台应用程序MydllTester,将mylib.lib复制到项目目录下。参照图10.6将mylib.lib添加到项目链接器的附加依赖项中。 在程序中调用mylib.dll中的sum()函数,计算3+4的和,代码如下: #include “stdafx.

12、h“ #include / 从DLL导入的函数 extern “C“ int sum(int a, int b); int _tmain(int argc, _TCHAR* argv) printf(“4+3 = %dn“, sum(4, 3); system(“Pause“); return 0; ,提示,在编译和生成程序之前,应将mylib.lib复制到项目目录下。否则会出现下面的错误。 错误 1 fatal error LNK1104: 无法打开文件“mylib.lib” MydllTester MydllTester 在运行程序之前,应将mylib.dll复制到应用程序可执行文件所在的

13、目录下。否则会出现图10.8所示的错误。,【例10.1】的运行结果,2使用DLL中的导出类,在使用DLL中的导出类之前,应重新声明类。比如10.2.3小节介绍的类CMath的声明如下: extern “C“ class _declspec(dllexport) CMath public: CMath(void); CMath(void); int sum(int a, int b); ;,【例10.2】,演示如何使用加载时动态链接的方法引用mylib.dll中的导出类。 创建一个控制台应用程序MydllTester2,将mylib.lib复制到项目目录下。参照图10.1将mylib.lib添加

14、到项目链接器的附加依赖项中。 在程序中调用mylib.dll中的Cmath:sum()函数,计算3+4的和,代码如下: #include extern “C“ class _declspec(dllexport) CMath public: CMath(void); CMath(void); int sum(int a, int b); ; int _tmain(int argc, _TCHAR* argv) CMath math; printf(“4+3 = %dn“, math.sum(4, 3); system(“Pause“); return 0; ,10.3.2 运行时动态链接,在应

15、用程序可以调用LoadLibrary()函数将指定的DLL模块加载到进程的地址空间中。函数原型如下: HMODULE WINAPI LoadLibrary( _in LPCTSTR lpFileName / 要加载的DLL文件名 ); 如果函数执行成功,则返回指定的DLL文件的句柄,DLL句柄可以用来标识一个DLL文件;否则返回NULL。,LoadLibraryEx()函数,也可以调用LoadLibraryEx()函数加载指定的DLL模块。函数原型如下: HMODULE LoadLibraryEx( LPCTSTR lpLibFileName, / 要加载的DLL文件名 HANDLE hFil

16、e, / 保留必须使用NULL DWORD dwFlags / 指定加载模块是采取的动作 );,GetModuleHandle()函数,也可以调用GetModuleHandle()函数返回DLL模块句柄,函数原型如下: HMODULE GetModuleHandle( LPCTSTR lpModuleName / 要加载的DLL文件名 ); 如果函数执行成功,则返回指定的DLL文件的句柄;否则返回NULL。,GetProcAddress()函数,可以调用GetProcAddress()函数获取DLL的导出函数的地址,函数原型如下: FARPROC GetProcAddress( HMODULE hModule, / DLL模块句柄 LPCWSTR lpProcName / 导出函数名 );,定义函数原型,为了使用DLL中的导出函数,需要先定义一个函数原型。例如,10.2.2小节中介绍的导出函数sum()可以定义为PROCSUM,代码如

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 高等教育 > 大学课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号