目录
动态库特点
1)运行时独立存在
动态库是能运行的,有入口函数,动态库最终能运行,进内存生成进程映像;但是不能独立运行必须依附程序进程才能运行起来之后有自己的独立进程空间。
2)源码不会连接到执行程序
别的程序调用动态库的函数,不会从动态库中抓取一份源码,只会记录调用函数在动态库的地址。
3)使用时需要加载(使用动态库必须使动态库执行)
我们要想调用动态库的函数,我们必须主动让动态库执行,让动态库进内存生成进程映像
与静态库的比较:
1)由于静态库是将代码嵌入到使用程序中,多个程序使用时,会有多份代码,所以代码体积会增大。动态库的代码只需要存在一份,其他程序通过函数地址使用,所以代码体积小。
2)静态库发生变化后,新的代码需要重新链接嵌入到执行程序中。动态库发生变化后,如果库中函数的定义或地址(函数名、参数表、返回值未变化,仅仅是函数内部实现变化了)未变化,其他使用DLL的程序不需要重新链接。
动态库创建
创建动态库项目
添加库程序
//xxx.cpp文件
int CPPdll_add(int a, int b) {
return a + b;
}
int CPPdll_sub(int a, int b) {
return a - b;
}
int CPPdll_mul(int a, int b) {
return a * b;
}
库程序导出 - 提供给使用者库中的函数等信息
声明导出:使用 _declspec(dllexport) 导出函数
//_declspec(dllexport):导出函数(具体的意思是导出函数的地址)
_declspec(dllexport) int CPPdll_add(int a, int b) {
return a + b;
}
_declspec(dllexport) int CPPdll_sub(int a, int b) {
return a - b;
}
_declspec(dllexport) int CPPdll_mul(int a, int b) {
return a * b;
}
注意:动态库编译连接后,也会有lib文件,是作为动态库函数映射使用,与静态库的lib完全不同
动态库使用
隐式链接(操作系统负责使动态库执行)
1)头文件和函数原型
可以在函数原型的声明前 ,增加_declspec(dllimport)
#include "CPPdll.h"
//_declspec(dllexport):导出函数(具体的意思是导出函数的地址)
_declspec(dllexport) int CPPdll_add(int a, int b) {
return a + b;
}
_declspec(dllexport) int Cppdll_div(int a, int b)
{
return a==0?(throw "error"):(a/b);
}
_declspec(dllexport) int CPPdll_sub(int a, int b) {
return a - b;
}
_declspec(dllexport) int CPPdll_mul(int a, int b) {
return a * b;
}
2)导入动态库的LIB文件
3)在程序中使用函数
4)隐式链接的情况下,dll文件可以存放的路径:
与执行文件中同一个目录下
与当前工作目录
Windows目录
Windows/System32目录
Windows/System
环境变量PATH指定目录
显式链接(程序员自己负责使动态库执行)
1)定义函数指针类型 typedef
#include<iostream>
#include<windows.h>
using namespace std;
typedef int(*ADD)(int m, int n);
typedef int(*SUB)(int m, int n);
typedef int(*MUL)(int m, int n);
int main() {
HINSTANCE hDll = LoadLibraryA("CPPdll.dll");
cout << "hDll:" << hDll << endl;
ADD myAdd = (ADD)GetProcAddress(hDll, "CPPdll_add");
cout << "myAdd:" << myAdd << endl;
int sum = myAdd(5, 4);
cout << "sum=" << sum << endl;
system("pause");
return 0;
}
2)加载动态库
HMODULE LoadLibrary(
LPCTSTR lpFileName //动态库文件名或全路径
);//返回DLL的实例句柄(HINSTANCE)
3)获取函数地址
FARPROC GetProcAddress(
HMODULE hModule,//DLL句柄,这个参数获取的是dll在执行时的首地址绝对地址
LPCTSTR lpProcName //函数名称,这个参数获取得是函数相对于首地址的相对地址
);//返回DLL的实例句柄(HINSTANCE)//成功返回函数地址
4)使用函数
5)卸载动态库
BOOL FreeLibrary(
HMODULE hModule //DLL的实例句柄
);
动态库中封装类
在类名称前面增加_declspec(dllexport) 定义 如:
class _declspec(dllexport) 类名{
.....
};
创建
//头文件
#pragma once
#ifdef DLLCLASS_EXPORTS
#define EXT_CLASS _declspce(dllexport)
#else
#define EXT_CLASS _declspec(dllimport)
#endif // DLLCLASS_EXPORTS
class EXT_CLASS ClassDll
{
public:
int Add(int add1, int add2);
int Sub(int sub1, int sub2);
};
//源文件
#include "ClassDll.h"
#define DLLCLASS_EXPORTS
int ClassDll::Add(int add1, int add2)
{
return add1+add2;
}
int ClassDll::Sub(int sub1, int sub2)
{
return sub1-sub2;
}
编译后
使用
//使用
#include<ClassDll.h>
#include<iostream>
using namespace std;
#pragma comment(lib,"../x64/Debug/ClassDll.lib")
int main() {
ClassDll c;
int a=c.Add(40, 30);
cout << a << endl;
system("pause");
}