动态链接库与静态链接库

动态链接库:

创建一个动态链接库文件

1571725972571

创建完成后,会出现一个DllMain函数(参数:模块句柄,调用原因,保留)

这个函数在一下几种情况发生时会被调用

  1. 程序被创建
  2. 程序中有线程被创建
  3. 程序即将退出
  4. 程序中有线程将要退出

DllMain函数可以执行一些初始化或清理资源的操作

dll的导出方式有两种

声明导出

DLL.h

1
2
3
4
5
6
#pragma once
//用C的方式导出
extern "C" _declspec(dllexport) int Add(int a, int b);

//C++的方式导出
//_declspec(dllexport) int Add(int a, int b);

DLL.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
// DLL.cpp : 定义 DLL 应用程序的导出函数。
//

#include "stdafx.h"
#include "DLL.h"

int Add(int a, int b) {
return a + b;
}

int Sub(int a, int b) {
return a - b;
}

重新生成后在Debug文件夹下见到dll了

使用PEID可以查看到导出表

1571728214636

def文件导出

新建文件DLL.def

DLL.def(;是备注)

1
2
3
4
;导出脚本

EXPORTS
Add @ 1 ;1代表着导出的序号

DLL.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
// DLL.cpp : 定义 DLL 应用程序的导出函数。
//

#include "stdafx.h"
#include "DLL.h"

int Add(int a, int b) {
return a + b;
}

int Sub(int a, int b) {
return a - b;
}

然后右键项目属性,链接器->输入->模块定义文件修改为刚创建的def文件

1571728605807

重新生成后再拖到PEID中查看

1571728758512

也可以查看到导出的函数


现在已经制作好了dll文件,那么如何才能够使用它呢?有两种方式可以使用dll文件

隐式链接

  1. 包含头文件
  2. 载入lib文件
  3. 调用函数

新建一个控制台项目

1
2
3
4
5
6
#include "..\\DLL\\DLL.h"//相对路径绝对路径都可以
#pragma comment(lib,"..\\Debug\\Dll.lib")
int main() {
int n = Add(1, 2);
return 0;
}

注意:生成的DLL.h和DLL.lib不在同一个文件夹下

显式链接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <Windows.h>
#include <tchar.h>

typedef int(*ADD)(int, int);

int main() {
ADD pFun = nullptr;

//载入dll
HMODULE hModule = LoadLibrary(_T("DLL.dll"));
//根据函数名得到函数地址
pFun = (ADD)GetProcAddress(hModule, "Add");
//调用函数
int n = pFun(1, 2);
//释放
FreeLibrary(hModule);

return 0;
}

使用PEID查看隐式链接和显式链接的输入表

1571729663078

隐式链接会暴露dll的调用信息

1571729732380

显式链接则不会暴露dll的信息


静态链接库

动态链接库在发布时需要跟着exe文件一起发布出去,但是如果想要只发布exe文件程序就可以运行,可以使用静态链接库

1571729887259

项目右键属性->常规->配置类型 修改为静态库

编译后只会生成一个lib文件和一个pdb文件

编译运行Main项目,程序就可以在任意位置运行了

编译动态链接库的时候生成了一个dll文件和一个lib文件

编译静态链接库的时候生成了一个lib文件

静态链接库的lib文件,称为对象库。其中包含了数据和代码

动态链接库的lib文件,称为导入库,其中不包含数据和代码,仅包含一些链接信息

对象库:161KB

1571730182435

导入库:2KB

1571730227500