Win32_Windows库
一 Windows的库
由于项目的复杂程序或为了提高代码的重用率,所以才引入了库程序
库包含两种:
1 静态库:扩展名为 lib 的文件,是不能被加载的程序,可以理解为目标程序的归档。
2 动态库:扩展名是 dll 的文件,是可以被应用程序加载的程序
二 静态库
1 静态库的特点
1.1 目标程序的归档
1.2 静态库的代码会被嵌入到程序当中,程序执行时不需要静态库的存在
2 C语言静态库
2.1 创建静态库
创建Win32静态库项目使用 *.c 文件建立项目
2.2 添加静态库函数
2.3 在程序中将静态库导入
1)项目的 setting 设置
2)使用关键字 pragma
#pragma comment(lib,"../lib/winclib.lib");
2.4 使用静态库提供的函数
在C语言程序中,直接使用函数即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //winclib.lib 2 3 int C_Add(int nAdd1,int nAdd2) 4 { 5 return(nAdd1 + nAdd2); 6 } 7 8 int C_Sub(int nSub1,int nSub2) 9 { 10 return(nSub1 - nSub2); 11 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //useclib.c 2 3 #pragma comment(lib,"../lib/winclib.lib")//导入静态库 4 5 int main() 6 { 7 int nAdd = 0; 8 int nSub = 0; 9 //使用C静态库函数 10 nAdd = C_Add(100,100); 11 nSub = C_Sub(100,100); 12 13 printf("ADD:%d\n",nAdd); 14 printf("SUB:%d\n",nSub); 15 return 0; 16 }
3 c++ 语言的静态库
3.1 创建静态库
创建win32静态库项目,使用 *.CPP文件建立项目
3.2 添加静态库的函数
3.3 导入静态库
1)项目的 Setting 里设置
2)使用关键字 pragma
#pragma comment(lib,"../lib/wincpplib.lib")
3.4 定义库函数的原形
int CPP_Add(int nAdd1,int nAdd2);
3.5 使用库函数
注:如果在CPP文件使用C语言静态库,定义静态库函数原型需要增加 extern"C".
如:extern "C" int C_Add(int nAdd1,int nAdd2);
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 int CPP_Add(int nAdd1,int nAdd2) 2 { 3 return(nAdd1 + nAdd2); 4 } 5 6 int CPP_Sub(int nSub1,int nSub2) 7 { 8 return(nSub1 - nSub2); 9 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 // usecpplib.cpp : Defines the entry point for the console application. 2 //使用.lib 3 4 #include "stdafx.h" 5 6 #pragma comment(lib,"../lib/wincpplib.lib")//导入C++的静态库 7 #pragma comment(lib,"../lib/winclib.lib") 8 //定义函数原形 9 int CPP_Add(int nAdd1,int nAdd2); 10 int CPP_Sub(int nSub1,int nSub2); 11 12 //加载C定义的lib库格式 13 extern "C" int C_Add(int nAdd1,int nAdd2); 14 extern "C" int C_Sub(int nSub1,int nSub2); 15 16 int main(int argc, char* argv[]) 17 { 18 //使用C++库函数 19 int nAdd = CPP_Add(100,100); 20 int nSub = CPP_Sub(100,100); 21 printf("ADD:%d\n",nAdd); 22 printf("SUB:%d\n",nSub); 23 //使用C库函数 24 int nAdd2 = C_Add(100,100); 25 int nSub2 = C_Sub(100,100); 26 printf("C_ADD:%d\n",nAdd); 27 printf("C_SUB:%d\n",nSub); 28 return 0; 29 }
三 动态库
1 动太库的好处
1.1 可以提供模块化的方式,方便协调开发
1.2 对源代码保护
1.3 减小可执行文件的大小
1.4 提供代码的重用率等
2 动态库的基本使用方法
2.1 动态库的创建
2.2 加载动态库
2.3 获取并使用库函数、变量或类
2.4 释放动态库
3 动态库的函数
3.1 创建
1)创建DLL的项目
使用Win32 DLL 项目创建DLL,添加相应的文件
2) 增加动态库函数
3) 导出动态库函数
(1)使用 _declspec(dllexport)方式在函数前增加这个个关键字,如:
_declspec(dllexport) int Dll_Add()
(2)增加 extern "C"方式,即:extern "C"_declspec(dllexport)以
C语言方式导出函数
(3)使用DEF文件导出
增加扩展名为DEF的文件到项目中,在DEF文件中添加导出定义
LIBRARY dllfunc.dll //导出库
EXPORTS //导出表
Dll_Mul @1 //导出函数
Dll_Div @2
3.2 使用
1)隐式链接
(1) 导入LIB
项目的 Setting 或者使用 #pragma 导入,如:
#pragma comment(lib,"../lib/dllfunc.lib")
(2) 定义函数原形
声明了一个和导出函数一致函数定义,如果DLL采用 extern "C"导出函数
需要定义 extern "C" 方式函数原形
(3) 使用函数
直接使用函数即可
(4)应用程序查找DLL的路径
查找当前应用程序的目录
当前的工作目录
查找 Windows System32的目录
查找 Windows System的目录
查找 Windows 目录
查找环境变量PATH 指定路径
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 // 生成dllfunc.dll文件 2 // C++导出方式 3 _declspec(dllexport) int Dll_Add(int nAdd1,int nAdd2) 4 { 5 return(nAdd1 + nAdd2); 6 } 7 // C导出方式 8 extern "C" _declspec(dllexport) int Dll_Sub(int nSub1,int nSub2) 9 { 10 return(nSub1 - nSub2); 11 } 12 // DEF导出方式 13 int Dll_Mul(int nMul1,int nMul2) 14 { 15 return(nMul1 * nMul2); 16 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 LIBRARY DllFunc.dll 2 EXPORTS 3 Dll_Mul @1
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 // callDllfun.cpp : Defines the entry point for the console application. 2 //使用 3 4 #include "stdafx.h" 5 6 #pragma comment(lib,"../lib/DllFunc.lib")//导入DLL的Lib文件 7 // 定义函数原形 8 int Dll_Add(int nAdd1,int nAdd2); 9 extern "C" int Dll_Sub(int nSub1,int nSub2); 10 int Dll_Mul(int nMul1,int nMul2); 11 12 int main(int argc, char* argv[]) 13 { 14 //使用函数 15 int nAdd = Dll_Add(100,100); 16 int nSub = Dll_Sub(100,100); 17 int nMul = Dll_Mul(100,100); 18 printf("Dll_Add:%d\n",nAdd); 19 printf("Dll_Sub:%d\n",nSub); 20 printf("Dll_Mul:%d\n",nMul); 21 return 0; 22 }
2)显示链接
(1)加载动态库
HINSTANCE LoadLibrary( LPCTSTR lpLibFileName);//DLL的路径
返回加载好DLL的句柄
(2)定义函数原形对应 的函数指针
(3)获取函数地址
FARPROC GetProcAddress( HMODULE hModule,//DLL的句柄 LPCSTR lpProcName//函数的名称 );
返回对应函数地址
注意:
1 对于 _declspec(dllexport)导出的函数由于函数名称发现变化,所以无
法使用函数名称获取对应的函数地址,尽量采用隐式链接方式
2 extern "C" 或DEF方式导出的函数可以正常的使用函数名称获取函数地址
(4)使用函数
(5)释放函数
FreeLibrary
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 // InvokeDllFunc.cpp : Defines the entry point for the console application. 2 // 3 4 #include "stdafx.h" 5 #include "windows.h" 6 7 typedef int (* DLL_ADD)(int nAdd1,int nAdd2); 8 typedef int (* DLL_SUB)(int nSub1,int nSub2); 9 typedef int (* DLL_MUL)(int nMul1,int nMul2); 10 11 void UseDll() 12 { 13 //加载动态库 14 HMODULE hDll = (HMODULE)LoadLibrary("dllfunc.dll"); 15 if (hDll == NULL) 16 { 17 printf("Load Failed\n"); 18 return; 19 } 20 21 // 定义函数指针 22 23 DLL_ADD Dll_Add = NULL; 24 DLL_SUB Dll_Sub = NULL; 25 DLL_MUL Dll_Mul = NULL; 26 27 //获取函数地址 28 Dll_Add = (DLL_ADD) GetProcAddress(hDll,"Dll_Add"); 29 if (NULL == Dll_Add) 30 { 31 printf("Get Dll_Add Failed\n"); 32 } 33 printf("Dll_Add:%p\n",Dll_Add); 34 Dll_Sub = (DLL_SUB) GetProcAddress(hDll,"Dll_Sub"); 35 if (NULL == Dll_Sub) 36 { 37 printf("Get Dll_Sub Failed\n"); 38 } 39 printf("Dll_Sub:%p\n",Dll_Sub); 40 Dll_Mul = (DLL_MUL) GetProcAddress(hDll,"Dll_Mul"); 41 if (NULL == Dll_Mul) 42 { 43 printf("Get Dll_Mul Failed\n"); 44 } 45 printf("Dll_Mul:%p\n",Dll_Mul); 46 //使用函数 47 int nSub = Dll_Sub(100,100); 48 int nMul = Dll_Mul(100,100); 49 printf("Dll_Sub:%d\n",nSub); 50 printf("Dll_Mul:%d\n",nMul); 51 52 //释放动态库 53 FreeLibrary(hDll); 54 } 55 56 int main(int argc, char* argv[]) 57 { 58 UseDll(); 59 return 0; 60 }
4 动态库的变量
4.1 定义全局变量
4.2 导出全局变量
4.2.1 _declspec(dllexport)导出
_declspec(dllexport) int g_nValuel = 100;
4.2.2 DEF文件导出
int g_nValue2 = 200;
在DEF文件的导出列表中增加 g_nValue2 @1 DATA
4.3 导入LIB文件
4.4 定义导入变量
需要使用 _declspec(dllimport) 定义变更
4.4 使用变量
1 /******************************************* 2 * 3 * dllvalue.cpp 4 ********************************************/ 5 //导出DLL的全局变量 6 _declspec(dllexport) int g_nValuel = 100; 7 8 // DEF 导出的全局变量 9 int g_nValue2 = 200;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 LIBRARY dllvalue 2 EXPORTS 3 g_nValue2 @1 DATA
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 // usevalue.cpp : Defines the entry point for the console application. 2 // 3 4 #include "stdafx.h" 5 6 #pragma comment(lib,"../lib/dllvalue.lib")//导入LIB 7 8 extern _declspec(dllimport) int g_nValuel;//定义DLL导入变量 9 extern _declspec(dllimport) int g_nValue2; 10 11 int main(int argc, char* argv[]) 12 { 13 printf("g_nValuel = %d\n",g_nValuel); 14 printf("g_nValue2 = %d\n",g_nValue2); 15 return 0; 16 }
5 动态库的类
5.1 创建动态库并定义类
5.2 从DLL中导出类
在类名称前增加 _declspec(dllexport)定义
class _declspec(dllimport) CMath
{...};
5.3 使用时导入LIB文件
5.4 导入
5.5 使用类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //math.h 2 #ifndef _MATH_H_ 3 #define _MATH_H_ 4 5 //定义类导入导出宏 6 #ifdef _DLLCLASS_DLL_ //(在设置 C/C++ Category--Preprocessor 下 增加_DLLCLASS_DLL_) 7 #define DLLCLASS_EXT __declspec(dllexport) 8 #else 9 #define DLLCLASS_EXT __declspec(dllimport) 10 #endif //_DLLCLASS_DLL_ 11 12 //增加类的导入导出宏 13 class DLLCLASS_EXT CMath 14 { 15 public: 16 int Add( int nAdd1, int nAdd2 ); 17 int Sub( int nSub1, int nSub2 ); 18 }; 19 20 #endif //_MATH_H_
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //math.cpp 2 #include "math.h" 3 4 int CMath::Add( int nAdd1, int nAdd2 ) 5 { 6 return ( nAdd1 + nAdd2 ); 7 } 8 9 int CMath::Sub( int nSub1, int nSub2 ) 10 { 11 return ( nSub1 - nSub2 ); 12 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include "stdafx.h" 2 //导入DLL的LIB文件 3 #pragma comment( lib, "../lib/dllclass.lib") 4 //需要类的导入方式的声明 5 #include "../DllClass/math.h" 6 7 int main(int argc, char* argv[]) 8 { //使用DLL中的类 9 CMath math; 10 int nAdd = math.Add( 100, 100 ); 11 int nSub = math.Sub( 100, 100 ); 12 printf("math.Add = %d\n", nAdd ); 13 printf("math.Sub = %d\n", nSub ); 14 return 0; 15 }
5.6 关于类的导入和导出
1)定义一个宏,例如:
#ifdef _DLLCLASS_DLL_
#define DLLCLASS_EXT _declspec(dllexport)
#else
#define DLLCLASS_EXT _declspec(dllimport)
#endif //_DLLCLASS_DLL
2)根据编译项目,修改_DLLCLASS_DLL_宏声明对于导出类,需要定义
_DLLCLASS_DLL_,否则不需要定义 _DLLCLASS_DLL_ 宏
3)类的定义为:
class DLLCLASS_EXT CMath
{...};
6 DllMain 函数
是DLL文件入口函数。当程序加载或者释放动态库的时候会自动调用这个函数
BOOL WINAPI DllMain( HINSTANCE hinstDLL,//DLL的句柄 DWORD fdwReason,//DLL被调用 的原因 LPVOID lpvReserved //保留值 );
fdwReason -
DLL_PROCESS_ATTACH 进程加载
DLL_THREAD_ATTACH 进程加载
DLL_THREAD_DETACH 进程卸载
DLL_THREAD_DETACH 进程卸载
返回值表示是否加载成功
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include "windows.h" 2 #include "stdio.h" 3 4 BOOL WINAPI DllMain( HINSTANCE hinstDLL, 5 DWORD fdwReason, LPVOID lpvReserved ) 6 { 7 printf( "DLL=%p, Reason=", hinstDLL ); 8 switch( fdwReason ) 9 { 10 case DLL_PROCESS_ATTACH: 11 printf( "DLL_PROCESS_ATTACH\n" ); 12 break; 13 case DLL_THREAD_ATTACH: 14 printf( "DLL_THREAD_ATTACH\n" ); 15 break; 16 case DLL_THREAD_DETACH: 17 printf( "DLL_THREAD_DETACH\n" ); 18 break; 19 case DLL_PROCESS_DETACH: 20 printf( "DLL_PROCESS_DETACH\n" ); 21 break; 22 } 23 return TRUE; 24 } 25 26 //C++导出方式 27 __declspec(dllexport) int Dll_Add( int nAdd1, int nAdd2 ) 28 { 29 return ( nAdd1 + nAdd2 ); 30 } 31 //C的导出方式 32 extern "C" __declspec(dllexport) int Dll_Sub( int nSub1, int nSub2 ) 33 { 34 return ( nSub1 - nSub2 ); 35 } 36 //DEF的导出方式 37 int Dll_Mul( int nMul1, int nMul2 ) 38 { 39 return ( nMul1 * nMul2 ); 40 }