目录
3.1.2 静态库实现文件(CkxCaclulate.cpp)
3.2.1 动态库头文件(CkxCalulate_Dll.h)
3.2.2 动态库实现文件(CkxCalulate_Dll.Cpp)
1、静态库
1.1 条件
- 头文件(.h)
- 静态库文件(lib)
1.2 说明
静态库的实现在lib中,调用者调用静态库时,将实现一起打包到链接到exe中,可实现随处编译随处运行,运行时无需提供其他文件
2、动态库
2.1 条件
- 头文件(.h)
- lib文件
- dll文件
2.2 说明
1、动态库的调用分为静态调用和动态调用,静态调用编译时,需要同时提供上面三个文件,动态调用仅需提供dll文件
2、不管动态调用还是静态调用,都要实现供方(_declspec(dllexport))导出用方(_declspec(dllimport))导入
3、导出的方式有两种,一种是 extern "C" _declspec(dllexport),另一种是.def,两者等价
4、静态调用时,可用加extern "C"也可以不加,但在动态调用时必须加,否则使用原来的函数名无法调用;def方式动态调用和静态调用均可
5、.def和extern "C"的作用,都是防止函数名在导出时"乱码",从而防止动态调用时找不到函数名
3、代码举例
3.1 静态库
3.1.1 静态库头文件(CkxCaclulate.h)
#pragma once
//1、全局函数
int Add_Staic(int a, int b);
int Sub_Staic(int a, int b);
//2、全局变量
extern double g_Count_Static;
//类
class CkxCaclulate
{
public:
CkxCaclulate(void);
~CkxCaclulate(void);
int Mul_Staic(int a, int b);
int Div_Staic(int a, int b);
};
3.1.2 静态库实现文件(CkxCaclulate.cpp)
#include "CkxCaclulate.h"
#include <iostream>
using namespace std;
double g_Count_Static = 10;
int Add_Staic(int a, int b)
{
cout << "Add In Satic!"<<endl;
return a + b;
}
int Sub_Staic(int a, int b)
{
cout << "Sub In Satic!"<<endl;
return a - b;
}
CkxCaclulate::CkxCaclulate(void)
{
}
CkxCaclulate::~CkxCaclulate(void)
{
}
int CkxCaclulate::Mul_Staic(int a, int b)
{
cout << "Mul In Satic!"<<endl;
return a*b;
}
int CkxCaclulate::Div_Staic(int a, int b)
{
cout << "Div In Satic!"<<endl;
return a/b;
}
3.1.3 调用
#pragma comment(lib,"../Lib/Test_Static.lib") //动态链接库
静态链接库///
cout<<"==================静态库调用===================================" << endl;
//1、导入导出函数
cout<<"Add(x,y) = "<< Add_Staic(x,y) << endl;
cout<<"Sub(x,y) = "<< Sub_Staic(x,y) << endl;
//2、导入导出类
CkxCaclulate Caclulate;
cout<<"Div(x,y) = "<< Caclulate.Div_Staic(x,y) << endl;
cout<<"Mul(x,y) = "<< Caclulate.Mul_Staic(x,y) << endl;
//3、导入导出全局变量
cout<<"g_Count_Static = "<< g_Count_Static << endl;
3.2 动态库静态调用
3.2.1 动态库头文件(CkxCalulate_Dll.h)
#pragma once
#ifdef TEST_DLL_EXPORTS
#define API_CLASSEXT _declspec(dllexport)
#define API_STDEXT _declspec(dllexport)
#else
#define API_CLASSEXT _declspec(dllimport)
#define API_STDEXT _declspec(dllimport)
#endif
//1、全局函数
extern "C" API_STDEXT int Add(int a, int b);
extern "C" API_STDEXT int Sub(int a, int b);
/*API_STDEXT*/ int Testdef(int a,int b);//def 等价于 extern "C" _declspec(dllexport)
//2、全局变量
extern /*API_STDEXT*/ int g_Count_def;
extern API_STDEXT double g_Count;
//3、类
class API_CLASSEXT CkxCalulate_Dll
{
public:
CkxCalulate_Dll(void);
~CkxCalulate_Dll(void);
int Mul(int a, int b);
int Div(int a, int b);
};
3.2.2 动态库实现文件(CkxCalulate_Dll.Cpp)
#include "CkxCalulate_Dll.h"
#include <iostream>
using namespace std;
double g_Count = 20;
int g_Count_def = 30;
int Add(int a, int b)
{
cout << "Add In Dll!"<<endl;
return a + b;
}
int Sub(int a, int b)
{
cout << "Sub In Dll!"<<endl;
return a - b;
}
int Testdef(int a,int b)
{
cout << "Testdef In Dll!"<<endl;
return a%b;
}
CkxCalulate_Dll::CkxCalulate_Dll(void)
{
}
CkxCalulate_Dll::~CkxCalulate_Dll(void)
{
}
int CkxCalulate_Dll::Mul(int a, int b)
{
cout << "Mul In Dll!"<<endl;
return a*b;
}
int CkxCalulate_Dll::Div(int a, int b)
{
cout << "Div In Dll!"<<endl;
return a/b;
}
3.2.3 def文件(Test_Dll.def)
LIBRARY "Test_Dll"
EXPORTS
Testdef
g_Count_def
3.2.4 调用
#pragma comment(lib,"../Lib/Test_Dll.lib") //动态链接库
cout<<"==================动态库静态调用=================================== " << endl;
//1、导入导出函数
cout<<"Add(x,y) = "<< Add(x,y) << endl;
cout<<"Sub(x,y) = "<< Sub(x,y) << endl;
cout<<"Testdef(x,y) = "<< Testdef(x,y)<< endl;
//2、导入导出类
CkxCalulate_Dll Object;
cout<<"Div(x,y) = "<< Object.Div(x,y) << endl;
cout<<"Mul(x,y) = "<< Object.Mul(x,y) << endl;
//3、导入导出全局变量
cout<<"g_Count = "<< g_Count << endl;
cout<<"g_Count_def = "<< g_Count_def << endl;
3.3 动态链接库动态调用
3.3.1 动态库头文件
同上
3.3.2 动态库实现文件
同上
3.3.3 调用
typedef int(*FUNA)(int,int); //函数指针
cout<<"==================动态库动态调用=================================== " << endl;
HMODULE hDLL = LoadLibrary(_T("Test_Dll.dll"));
if (hDLL != NULL)
{
FUNA fp1 = (FUNA)(GetProcAddress(hDLL,"Add")); //不加 extern "C"调用不成功
if(fp1 != NULL)
{
fp1(x,y);
}
FUNA fp2 = (FUNA)(GetProcAddress(hDLL,"Testdef"));//不使用 .def 调用不成功
if(fp2 != NULL)
{
fp2(x,y);
}
}
FreeLibrary(hDLL);
3.4 工程全部代码
代码下载地址:https://download.csdn.net/download/vfw2014/88013826
4、总结
1、静态库的调用 需要 头文件、lib文件,lib文件中包含了实现,编译时,一起打包到调用者的exe中,应用程序可以单独运行
2、动态库的调用分为静态调用和动态调用。静态调用时,需要提供.h头文件、lib文件和dll文件;动态调用时仅需要提供dll文件
3、动态库的静态调用,需要将要导出的函数、数据成员、类增加 _declspec(dllexport)导出修饰,一般在头文件中使用宏定义 判断导入还是导出
4、extern "C" 和 .def文件用于防止函数名称被修改,可借助depend工具查看,不加exter "C"或未使用.def时,导出的函数名称“乱码名称”,如下图一
5、经测试仅动态库的动态调用才需要extern "C" 修饰导出或者使用.def,从而保证名称不被修改,静态调用加不加extern "C"也可以
6、.def 等价于 extern "C" _declspec(dllexport)
7、添加.def 时要使用编译器自动添加,也可以手动添加,手动添加时,要注意关联def文件。见图二
图一
图二