Windows库程序
静态库
静态库特点
- 运行不存在 --> 没有入口
- 静态库源码被链接到调用程序中
- 目标程序的归档
C语言静态库
- C静态库的创建
- 创建一个静态库项目
- 添加库程序,源文件使用C文件
- C静态库的使用
库路径设置: 可以使用pragma关键字设置
#pragma comment(lib,".../xxx.lib")
C++语言静态库
- C++静态库的创建
- 创建一个静态库项目
- 添加库程序,源文件使用CPP文件
- C++静态库的使用
库路径设置: 可以使用pragma关键字设置
#pragma comment(lib,".../xxx.lib")
- C++ 静态库函数使用时必须要有声明
C++ --> 换名,编译器会给函数换名
C编译器没有换名
- C++ 不换名
extern "C" 函数声明; // 使用C方式编译,不换名
动态库
动态库特点
- 运行时独立存在 --> 可以运行 --> 依附其他程序存在 --> 运行后有自己的地址空间
- 源码不会链接到执行程序
- 使用时加载( 使用动态库必须是动态库执行 )
与静态库比较
- 由于静态库是将代码嵌入到使用程序中,多个程序使用时,会有多份代码,代码体积会增大。动态库的代码只需要存在一份,其他程序通过函数地址使用,所以代码体积小
- 静态库发生变化后,新的代码需要重新链接嵌入到执行程序中。动态库发生变化后,如果库中函数的定义(或者地址)未变化,其他使用DLL的程序不需要重新链接
动态库创建
- 创建动态库项目
- 添加库程序
- 库程序导出 - 提供给使用者库中的函数等信息导出的是函数地址
- 声明导出
使用_declspec(dllexport) 导出函数
动态库编译链接后,也会有LIB文件,是作为动态库函数映射使用,与静态库不完全相同
要使用extern “C” --> 不换名
- 模块定义文件 .def
LIBRARY 动态库文件名->不要.dll后缀 EXPORTS // 库导出表 函数名1 @1 // 导出的函数 函数名2 @2 // 导出的函数 函数名n @n // 导出的函数
动态库的使用
- 隐式链接( 操作系统负责使用动态库执行)
- 头文件和函数原型
可以在函数声明前,增加_declspes(dllimport)
_declspes(dllimport) 函数声明;
- 导入动态库的LIB文件
#pragma comment(lib,"xxx.lib")
- 在程序中使用函数
- 隐式链接的情况,dll文件可以存放的路径
- 与执行文件同一个目录下
- 当前工作目录
- Windows目录
- Windows/System32目录
- Windows/System
- 环境变量PATH指定目录
- 显式链接( 自己负责使动态库执行 )
- 定义函数指针类型 typedef
typedef int (*ADD) (int m,int n);
- 加载动态库
HMODULE LoadLibrary( LPCTSRT lpFileName // 动态库文件名或者全路径 );// 返回DLL的实例句柄 ( HINSTANCE )
让动态库进内存
- 获取函数真实地址
地址值为0 是NULL, 为无效地址
FARPROC GetProcAddress( HMODULE hModule , // DLL句柄 LPCTSRT lpProcName, // 函数名称 ); // 成功返回函数地址
- 使用函数
- 卸载动态库
BOOL FreeLibrary( HMODULE hModule // DLL的实例句柄 );
动态库中封装类
- 在类名称前增加_declspec(dellexport)定义
class _declspec(dllexport) CMath{ //... public: int Add(int n1,int n2); int Sub(int n1,int n2); };
- 通常使用预编译开关切换类的导入导出定义
#ifdef DLLCLASS_EXPORTS #define EXT_CLASS _declspec(dllexport) #else #define EXT_CLASS _declspec(dllimport) // 使用者 #endif
导出的不是类,类是没有地址的,实际上导出的是类的成员函数地址