一 Windows的库
程序编译一般需经预处理、编译、汇编和链接几个步骤。在我们的应用中,有一些公共代码是需要反复使用,就把这些代码编译为“库”文件;。
库包含两种:静态库和动态库
1 静态库:
在链接步骤中,连接器将从库文件取得所需的代码,复制到生成的可执行文件中。这种库称为静态库,其特点是可执行文件中包含了库代码的一份完整拷贝;缺点就是被多次使用就会有多份冗余拷贝。静态库扩展名为LIB,不能被程序动态加载。
2 动态库:
动态库又称动态链接库英文为DLL,是Dynamic Link Library的缩写形式,DLL是一个包含可由多个程序同时使用的代码和数据的库,DLL不是可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 中,该 DLL包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。DLL还有助于共享数据和资源。多个应用程序可同时访问内存中单个DLL副本的内容。DLL是一个包含可由多个程序同时使用的代码和数据的库。Windows下动态库为.dll后缀,在linux在为.so后缀。
3 动态库和静态库区别:
静态库和动态库是两种共享程序代码的方式,它们的区别是:静态库在程序的链接阶段被复制到了程序中,和程序运行的时候没有关系;动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用。使用动态库的优点是系统只需载入一次动态库,不同的程序可以得到内存中相同的动态库的副本,因此节省了很多内存。
二 静态库
1 静态库的特点
1.1 目标程序的归档
1.2 静态库的代码会被嵌入到程序当中。
1.3 程序执行时不需要静态库存在
2 C语言静态库
2.1 创建静态库
创建Win32静态库项目,使用*.C文件建立
项目。
2.2 添加静态库函数
2.3 在程序中将静态库导入
2.3.1 项目的Setting里设置静态库目录
2.3.2 使用关键字 pragma
#pragmacomment(lib, "../lib/winclib.lib")
2.4 使用静态库提供的函数
在C语言程序中,直接使用函数即可。
3 C++语言的静态库
3.1 创建静态库
创建Win32静态库项目,使用*.CPP文件建立
项目。
3.2 添加静态库的函数
3.3 导入静态库
3.3.1 项目的Setting里设置
3.3.2 使用关键字 pragma
#pragmacomment(lib, "../lib/wincpplib.lib")
3.4 定义库函数的原形
int CPP_Add( intnAdd1, int nAdd2 );
3.5 使用库函数
3.6 注意:
如果在CPP文件使用C语言创建的静态库(即*.c文件生成的静态库),定义的静态库函数原形,需要增加 extern "C".
例如:
extern"C" int C_Add( int nAdd1, int nAdd2 );
因为c语言方式生成静态库,不会改变函数的名字,在c程序中使用静态库的时候,程序寻找库函数时会根据实际的函数名字去寻找;而c++语言方式生成静态库,会改变函数名字,在c++程序中使用静态库的时候,程序寻找库函数时,会先将函数声明时的函数名改变,用改变后的函数名去寻找库函数。所以在c++程序中使用c语言生成的静态库的时候,用extern"C"对编译器提示使用C的方式来处理函数。
三 动态库
1 动态库的好处
1.1 可以提供模块化的方式,方便协调开发。
1.2 对源代码保护
1.3 减小可执行文件的大小
1.4 提高代码的重用率
2 动态库的创建和基本使用方法
2.1 动态库的创建
2.2 加载动态库
2.3 获取并使用库函数、变量或类
2.4 释放动态库
3 动态库的函数
3.1 创建
3.1.1 创建DLL的项目
使用Win32 DLL项目,创建DLL,添加
相应的文件。
3.1.2 增加动态库函数
3.1.3 导出动态库函数
动态库导出主要有两种方式:1__declspec(dllexport)),2DEF文件导出
3.1.3.1 使用__declspec(dllexport)方式
在函数前增加这个关键字,例如
__declspec(dllexport) int Dll_Add()
3.1.3.2 增加 extern "C"方式,即
extern"C" __declspec(dllexport)
以C语言方式导出函数(该动态库供c程序使用时,需要以此方式导出)
3.1.3.3 使用DEF文件导出
增加扩展名为DEF的文件到项目中.
在DEF文件中添加导出定义.
LIBRARY dllfunc.dll //导出库
EXPORTS //导出表
Dll_Mul @1 //导出函数
Dll_Div @2
3.2 使用
使用动态库函数有两种方式:隐式链接和显式链接
3.2.1 隐式链接
3.2.1.1 导入LIB
项目的Setting或者使用#pragma导入,例如:
#pragmacomment( lib, "../lib/dllfunc.lib")
3.2.1.2 定义函数原形
声明一个和导出函数一致的函数定义.
如果DLL采用extern"C"导出函数,
需要定义extern "C"方式函数原形(前提:导入导出都是在C++程序中)
3.2.1.3 使用函数
直接函数即可
3.2.1.4 补充:应用程序查找DLL的路径的顺序
1) 查找当前应用程序的目录.
2) 当前的工作目录
3) 查找Windows System32的目录
4) 查找Windows System的目录
5) 查找Windows目录
6) 查找环境变量PATH指定路径
3.2.2 显示链接
3.2.2.1加载动态库
HINSTANCE LoadLibrary(
LPCTSTR lpLibFileName);//DLL的路径
返回加载好DLL的句柄
3.2.2.2定义函数原形对应的函数指针
3.2.2.3获取函数地址
FARPROC GetProcAddress(
HMODULE hModule,//DLL的句柄
LPCSTR lpProcName );//函数的名称
返回对应函数地址
注意:
1对于__declspec(dllexport)导出的函数,
由于函数名称发生变化,所以无法使用
函数名称获取对应的函数地址,所以
尽量采用隐式链接的方式.
2extern "C"或DEF方式导出的函数,
可以正常的使用函数名称获取函数地址.
3.2.2.4 使用函数
3.2.2.5释放动态库
FreeLibrary
4 动态库的变量
4.1 定义并导出全局变量
4.1.1 __declspec(dllexport)导出
__declspec(dllexport)int g_nValue1 = 100;
4.1.2 DEF文件导出
int g_nValue1 = 100;
在DEF文件的导出列表中增加
g_nValue1 @1 DATA
4.2 导入LIB文件
项目的Setting或者使用#pragma导入,例如:
#pragmacomment( lib, "../lib/dllfunc.lib")
4.3 声明导入变量
需要使用__declspec(dllimport)声明变量.
extern __declspec(dllimport) intg_nValue1;
4.4 使用变量
5 动态库的类
5.1 创建动态库并定义类
5.2 从DLL中导出类
在类名称前增加__declspec(dllexport)定义.
class __declspec(dllexport) CMath
{ ... };
5.3 使用时导入LIB文件
5.4 导入类
在类名称前增加__declspec(dllimport)定义.
class __declspec(dllimport) CMath
{ ... };
5.5 使用类
5.6 关于类的导入和导出
1) 定义一个宏,例如:
#ifdef _DLLCLASS_DLL_
#define DLLCLASS_EXT__declspec(dllexport)
#else
#defineDLLCLASS_EXT __declspec(dllimport)
#endif//_DLLCLASS_DLL_
2) 根据编译项目,修改_DLLCLASS_DLL_宏声明
对于导出类,需要定义_DLLCLASS_DLL_,
否则不需要定义 _DLLCLASS_DLL_宏
3) 类的定义为
classDLLCLASS_EXT CMath
{ ... };
使用_DLLCLASS_DLL_宏作为开关,减少导入导出的重复代码
6 DllMain 函数
是DLL文件入口函数.当程序加载或者释放
动态库的时候,会自动调用这个函数.
BOOL WINAPIDllMain(
HINSTANCEhinstDLL,//DLL的句柄
DWORDfdwReason,//DLL被调用的原因
LPVOIDlpvReserved ); //保留值
fdwReason -
DLL_PROCESS_ATTACH 进程加载
DLL_THREAD_ATTACH 线程加载
DLL_THREAD_DETACH 线程卸载
DLL_THREAD_DETACH 进程卸载
返回值表示是否加载成功.