200 likes | 359 Vues
第 4 讲 动态链接库 4.1 动态链接库 (DLL) 的概述 4.1.1 DLL 的定义 4.1.2 DLL 的种类 4.1.3 动态链接库和静态链接库的比较 4.2 DLL 的基本理论 4.2.1 DLL 入出口函数 4.2.2 DLL 的链接方式 4.2.3 DLL 动态链接库库函数的导出 4.2.4 从 DLL 中导出数据变量 4.3 用 VC++ 开发环境生成 DLL 4.3.1 用 VC++ 生成 WIN32 DLL 4.3.2 用 VC++ 的 MFC 生成的 DLL
E N D
第4讲 动态链接库 4.1 动态链接库(DLL)的概述 4.1.1 DLL的定义 4.1.2 DLL的种类 4.1.3 动态链接库和静态链接库的比较 4.2 DLL的基本理论 4.2.1 DLL入出口函数 4.2.2 DLL的链接方式 4.2.3 DLL动态链接库库函数的导出 4.2.4 从DLL中导出数据变量 4.3 用VC++开发环境生成DLL 4.3.1 用VC++生成WIN32 DLL 4.3.2 用VC++的MFC生成的 DLL 4.4 使用DLL 4.4.1 DLL的使用 4.4.2 DLL的调试 4.5 用VC++工具开发DLL的编程实例
4.1 动态链接库(DLL)的概述 DLL特点:要求一个DEF文件;要求一个DllMain()的入口点,不是WinMain();DLL可以装入,但不能执行。 4.1.1 DLL的定义 动态链接库:是应用程序中的一段程序,将它放在一个不同的容器内,是一个可以从主.exe文件中单独执行的模块.可以认为一个DLL就是其它应用程序在执行时,能够动态链接和调用的一组服务或函数. DLL中存放的一般是一些公共的子程序段或各种资源和数据.一个最大的特点:可以实现应用程序本地化.如在DLL中封装了各种语言,在安装时进行适当的选择就能实现本地化.
4.1.2 DLL的种类 主要有Win32 DLL和MFC APPWizard DLL两大类及相关子类。 4.1.3 动态链接库和静态链接库的比较 一个应用程序和函数的链接方式有两种: 动态链接:在应用程序中不需要包含所要调用函数的代码,而只需要所调DLL函数的一些信息,如DLL位置及相应的函数名。与函数的链接到编译或运行时进行。 静态链接:应用程序必须从静态链接库中取得所需调用函数的代码,并把这些代码放在应用程序的可执行代码中。如一般的库函数调用则属此类。
DLL的特点: 有利于不同的应用程序共享数据和资源; 多个应用程序可以使用内存中的动态链接库的单一映射,从而节约了程序运行和内存空间; 通过使用动态链接库,应用程序可以拆分为相对独立的功能模块,有利于应用程序的升级; 当多个应用程序需要使用相同的函数时,通过使用动态链接库,可以节约大量的硬盘空间。
4.2 DLL的基本理论 应用程序在使用DLL中的内容之前,系统要调用入出口函数完成DLL的初始化和终止工作。 4.2.1 DLL入出口函数 1、DllMain函数:在一个DLL的调用和撤除时被调用,一般发生在应用程序使用LoadLibrary 和FreeLibrary等函数及进程经线程启动和终止时。函数结构为: BOOL APIENTRY DllMain(HINSTANCE hInstance, DWORD fdwReason , LPVOID lpvReserved){ Switch (fdwReason){ Case DLL_PROCESS_ATTACH:break;/DLL映射到进程地址空间 Case DLL_THREAD_ATTACH:break;/一个线程被创建 Case DLL_THREAD_DETACH:break;/线程退出 Case DLL_PROCESS_DETACH:break;}/DLL从进程中解除映射 Return TRUE;}
其中hInstance是DLL的模块句柄, lpvReserved 指定DLL初始化和清除的一些内容指针,fdwReason表明调用DllMain()函数的原因,具体如下:
2 . MFC的 Regular DLL 入出口 在MFC的DLL使用中,已编好了DllMain()函数,用户不必写,在装载DLL时调用其成员函数InitInstance,在DLL退出时调用成员函数ExitInstance, 所需要的初始化和终止工作在这两个函数中完成.
4.2.2 DLL的链接方式 • DLL中包含一个或多个函数,调用这些函数的过程和编译,链接的过程是独立的.有两种链接方式:隐式链接和显式链接. • 隐式链接DLL • 原理:先说明DLL的导入库文件(lib),因在库文件中包含了一系列指向动态链接库的指针.应用程序通过库文件和DLL链接,调用DLL中的函数. • 应用程序在调用DLL时需以下信息: • 包含导出函数以及类声明的头文件,需要知道函数名和函数接口信息. • DLL的导入库文件,应用程序在编译链接需要. • 实际的DLL文件,应用程序在运行时调用它.
显式链接DLL • 原理:应用程序在运行时通过函数调用来显式装载和卸载DLL,并通过函数指针来调用DLL的导出函数,这种方式主要用于灵活控制DLL库动态装入和装出的场合. • 使用:第一步调用函数LoadLibrary或AfxLoadLibrary装载DLL并得到模块句柄.原型如下: • HINSTANCE LoadLibrary(LPCSTR lpLibFileName); • 参数为要装入的DLL的文件名字.当此函数被多次调用时,在进程中只有一份DLL程序和数据,系统通过计数器来标识.
第二步:调用函数GetProcAddress来获得导出函数的指针.函数原型如下:第二步:调用函数GetProcAddress来获得导出函数的指针.函数原型如下: FARPROC GetProcAddress(HMODULE hModul,LPCSTR lpProName); hMoudul是DLL的实例句柄,参数lpProName是相应的函数名。 第三步:在使用完后调用函数FreeLibrary或AfxFreeLibrary 来释放DLL. FreeLibrary原型为 BOOL FreeLibrary(HINSTANCE hInstLib); 参数是装入的DLL模块的句柄,调用一次,DLL计数器值减一,最终回到0,系统释放被DLL占用的空间。
4.2.3 DLL动态链接库库函数的导出 动态链接库中的函数可以分为导出函数和内部函数。 动态链接库中的函数主要有以下几种: (1)在源程序中使用关键字:_declspec(dllexport). 此函数可从一个DLL中输出数据,函数,类,类成员函数而不需要DEF文件. 原理:根据一个指定的存储类属性(extended-attribute)存储某个项数据.其属性主要有:allocate(“segname”), dllimport,dllexport,naked等,语法如下: _declspec(extended_attribute) declarator;具体使用有二种情况:_declspec(dllexport) void_cdecl Function1(void); Class _declspec(dllexport) CExportCLass:public Cobject {……..}
(2) 在DEF文件中通过EXPORTS来声明函数 DEF是由一个或多个描述DLL属性的语句组成的文本文件,主要有: LIBRARY语句:用于指定DLL的内部名; DESCRIPTION语句:用于描述DLL特性; SECTIONS语句:用于设置段的属性,这些属性有: READ,WRITE,EXECUTE,SHARED; EXPORTS语句:用于列出被导出的函数名及相关信息; VERSION语句:该DLL的版本号。
例: LIBRARY “Dll” DESCRIPTION ‘Dll Windows Dynamic Link Library’ EXPORTS Function1 @1 Function2 @2 Function3 @3 EXPORTS ………. ………. 库函数的声明如下: Entryname[=internalname] [@ordinal[NONAME]] 外部名 内部名 序号 不输出函数名
4.2.4 从DLL中导出数据变量 (1)使用DEF文件,设置关键字CONSTANT导出.通过用CONSTANT标志时,表明前面导出的不是函数,而是一个数据变量. EXPORTS Bvariable @4 CONSTANT Extern BOOL bVariable ;//程序中的应用 (2)可以在应用程序中使用关键字 _declspec(dllimport) 引入对DLL导出的变量的作用,在DLL源程序中以_declspec(dllexport)来说明要导出的变量.
4.3 用VC++开发环境生成DLL • 4.3.1 用VC++生成WIN32 DLL • Win 32的DLL自动生成过程: • FILE->NEW->PROJECT->Win32 Dynamic-Link Library->ok,然后选择相应的类型工程. • 2. DLL工程类型: • (1)空DLL工程 • 在需要时编写程序源文件,和DEF文件 • (2)简单的DLL工程 • 只有DllMain(),没有导出和其它变量或函数,不生成DEF文件,编译后也不产生LIB文件. • (3)导出变量,函数和类的DLL • 较为详细地建立了DLL中的一些基本成分,包括导出关键字_declspec(dllexport),生成LIB文件.
4.3.2 用VC++的MFC生成的 DLL • MFC类库的DLL自动生成过程: • FILE->NEW->PROJECT->MFC AppWizard(dll) -> ok,然后选择相应的类型工程. • 2. MFC AppWizard DLL类型: • (1)静态链接MFC的 Regular DLL • 在内部使用MFC的DLL库,可被MFC和非MFC的应用程序使用,若在工程建立时使用的是MFC静态库,导出函数使用标准C语言接口,创建时自动生成DEF文件,如导出函数:MyExportFunction()用: • extern “c” EXPORT MyExportFunction(); • (2)动态链接MFC 的Regular DLL
动态链接MFC 的Regular DLL和静态链接MFC 的Regular DLL基本相似,最后都是由CWinApp派生类的成员函数InitInstance和ExitInstance来完成DLL的初始化和应用程序调用结束时的终止,清理工作. 不同的是:DLL在建立时用的是MFC的动态共享库.其导出函数的开头部分使用AFX_MANAGE_STATE宏. (3)动态链接MFC 的扩展 DLL MFC 的扩展(Extension) DLL是从已有的MFC类派生新类的DLL,它建立时作用MFC动态链接库,它的导出函数只能由使用MFC动态共享库的MFC应用程序调用. 注:如果显示链接到这种DLL的应用程序是多线程的,则应使用AfxLoadLibrary 和AfxfreeLibray来装载和卸载扩展DLL,而不要用AfxLoadLibrary 和AfxfreeLibray.
4.4 使用DLL 4.4.1 DLL的使用 调用DLL的应用程序在没有指定DLL位置时,默认位置如下: (1)含有该应用程序的目录 (2)当前执行所在目录 (3)Windows的系统目录,如system目录 (4)Windows目录 (5)在环境变量PATH中列出的目录
4.4.2 DLL的调试 (1)使用应用程序调试DLL 打开应用程序的工程, 选择Project->settings-> debug-> category->additional DLLs->指定调试的DLL文件. (2)使用DLL的工程调试DLL 打开DLL工程, 选择Project->settings-> debug -> category->additional DLLs->指定调试的DLL文件. 此时可以设置断点进行调试. (3)同时使用应用程序和DLL调试DLL 可以在同一个工作区中打开应用程序工程和DLL工程,如下: 选择Project->Insert Project into Workspace-> Win32 debug 进行DLL程序调试.
4.5 用VC++工具开发DLL的编程实例 (见P93-P102)