静态链接库的缺陷
- 链接时将函数加入到exe导致exe变大
- 在运行时对于不同进程他们所使用的同一个函数都会独占空间,造成资源浪费
怎么解决
利用之前学习过的内存知识,例如映射类型的内存块
将这些公共代码放在文件中没在进程运行的时候在加载该文件
并且在内存中只需要加载一边,不同进程使用同一份公共代码时,只需要将之前加载过的这个文件映射到自己内存中即可
什么是动态链接库
动态链接库(dynamic link library 缩写位 dll),是微软公司在windows操作系统中
实现共享函数库概念的一种方式
这些库函数的扩展是 .dll .ocx(包含activeX控制的库)
创建动态链接库
extern "C" _declspec(dllexport) 返回类型 调用约定 函数名 (参数列表)
- 使用
.def
文件
制定导出函数,并告知编译器不要以修饰后的函数名作为导出函数名,而以指定的函数名导出函数
EXPORTS
函数名 @编号
函数名 @编号 NONAME
使用序号导出的好处:
名字是一段程序最精华的注释,通过名字可以直接猜到函数的功能
通过使用序号,可以达到隐藏的目的
如何调用动态链接库(显式调用)
- 定义函数指针
- 声明函数变量
- 通过
LoadLibrary()
动态加载DLL到内存中 - 通过
GetProcAddress()
获取函数地址 - 调用函数
-
FreeLibrary()
释放动态链接库
exp:
// 定义
// MyFunction.h
//根据名字查找进程id
//extern "C" _declspec(dllexport) 返回类型 调用约定 函数名 (参数列表)
extern "C" _declspec(dllexport) DWORD _stdcall find_processid_by_name(PWCHAR process_name);
// MyFunction.cpp
#include "stdafx.h"
#include <Windows.h>
#include <TlHelp32.h>
DWORD find_processid_by_name(PWCHAR process_name)
{
HANDLE hand = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if ((int)hand == -1)
{
return GetLastError();
}
PROCESSENTRY32 process_info = { 0 };
process_info.dwSize = sizeof PROCESSENTRY32;
if (!Process32First(hand, &process_info))
{
return GetLastError();
}
do
{
if (!wcscmp(process_info.szExeFile, process_name))
{
return process_info.th32ProcessID;
}
} while (Process32Next(hand,&process_info));
return 0;
}
//调用
//Main.cpp
#include "stdafx.h"
#include "windows.h"
//显示的导入
//1 定义函数指针
typedef DWORD(_cdecl * PFindProcessW)(PWCHAR);
//2 定义变量
PFindProcessW pMyFindProcessW = NULL;
int main()
{
//3 装载DLL
HMODULE hModule = LoadLibrary(L"动态链接库.dll");
//4 获得函数
pMyFindProcessW = (PFindProcessW)GetProcAddress(hModule, "find_processid_by_name");
DWORD err = GetLastError();
WCHAR name[] = L"notepad.exe";
printf_s("PID=%d \r\n", pMyFindProcessW(name));
getchar();
return 0;
}
DLL和EXE的区别
- 动态链接库DLL与可执行文件exe本质上没有区别,我们统称为模块
- 他们内部的数据组织结构都遵循一个叫做PE文件格式的格式
- 两者都可以对外提供函数,只不过DLL提供的更多