5.03 动态库
动态库特点
● 动态库特点
运行时独立存在(独立内存空间)
源码不会链接到执行程序(不会抓源码 只存地址)
使用时加载(使用动态库必须使动态库执行)
● 与静态库的比较
由于静态库是将代码嵌入到使用程序中,多个程序使用时,会有多份代码.所以代码体积会增大。动态库的代码只需要存在一份,其他程序通过函数地址使用,所以代码体积小
静态库发生变化后,新的代码需要重新链接嵌入到执行程序中。动态库发生变化后,如果库中函数的定义(或地址)未变化,其他使用 DLL 的程序不需重新链接
● 内容
dll 文件包含 函数文件头(函数名,函数标号与地址)和函数源码
配套的 lib 包含 函数名,函数标号以及 dll 文件名
动态库创建
● 创建动态库项目
● 添加库程序
● 库程序导出-提供给使用者库中的函数等信息.
1)声明导出:使用_declspec(dlexport)
导出函数(此时是换名函数)
_declspec(dlexport) int add(){
...
};
注意:动态库编译链接后,也会有 LIB 文件,是作为动态库函数映射使用
- 模块定义文件.def(函数不会换名)
例如: LIBRARY DLLFunc //库名称 EXPORTS //库导出表 DLL_Mul @1 //导出的函数
// CppDll.def
LIBRARY CPPdll
EXPORTS
CPP_add @1
CPP_sub @2
动态库的使用
● 隐式链接(操作系统负责使动态库执行) 1)头文件和函数原型
可以在函数原型的声明前,
- 增加_declspec(dllimport)
- 导入动态库的 LIB 文件
- 在程序中使用函数
- 隐式链接的情况,dll 文件可以存放的路径
- (1)与执行文件中同一个目录下
- (2)当前工作目录
- (3)Windows 目录
- (4)Windows/System32 目录
- (5)Windows/System
- (6)环境变量 PATH 指定目录
_declspec(dllimport) int add(int a,int b);
#pragma comment(lib,"CPPdll.lib"); // 抓取附属静态库
add()...// 正常使用
● 显式链接(程序员自己负责使动态库执行
1)定义函数指针类型 typedef
2)加载动态库
HMODULE LoadLibrary(
LPCTSTR IpFileName //动态库文件名或全路径
); 返回 DLL 的实例句柄( HINSTANCE)
3)获取函数地址
FARPROC GetProcAddress(
HMODULE hModule,//DLL 句柄
LPCSTR IpProcName //函数名称
);成功返回函数地址
4)使用函数
5)卸载动态库
BOOL FreeLibrary(
HMODULE hModule //DLL 的实例句柄
);
typedef int(*ADD)(int m,int n);
HINSTANCE/HMODULE hDll = LoadLibrary(CppDll.dll);
ADD myADD = (ADD)GetProcAddress(hDll,"CPPADD");
myADD()...
FreeLibrary(hDll);
动态库中封装类
导出的不是类地址, 而是类的成员函数地址
在类名称前增加_declspec(dllexport) 定义,例如
class _declspec(dllexport) CMath {
...
}
通常使用预编译开关切换类的导入导出定义,例如
// 为了制作者,使用者共有一个头文件, 需要判断,整个宏
#ifndef _DLLCLASS_H
#define _DLLCLASS_H
#ifdef DLLCLASS_EXPORTS
#define EXT_CLASS _declspec(dllexport)//DLL
#else
#define EXT_CLASS _declspec(dllimport)//使用者
#endif
class EXT_CLASS CMath(
...
}
// 源码.cpp
#define DLLCLASS_EXPORTS // 这样制作动态库 就按导出算
...