动态链接库英文为DLL,是Dynamic Link Library的缩写。dll是一个被其他应用程序调用的程序模块,其中封装了可以被调用的资源或函数。它是依附于EXE文件创建的的进程来执行的,不能够单独运行。每个程序都可以通过包含dll使用dll中包含的功能,这有助于避免代码重用和促进内存的有效使用。 通过使用 DLL,程序可以实现模块化,由相对独立的组件组成。因为模块是彼此独立的,所以程序的加载速度更快,而且模块只在相应的功能被请求时才加载。
比喻就是静态库就是你留在这别走了,而动态库就是你要帮忙时叫我一下,我再来。
#pragma once
//定义导出函数的接口声明
_declspec(dllexport) int _stdcall add(int a, int b);
//填写mfc dll函数的实现
int _stdcall add(int a, int b)
{
//用于模式切换时的状态保护 最好加上这一句
AFX_MANAGE_STATE(AfxGetStaticModuleState());
//定义函数体
//输出一个mfc消息框
AfxMessageBox(L"hello i am mfc dll");
return a + b;
}
; MFCLibrary1.def : 声明 DLL 的模块参数。
LIBRARY
EXPORTS
; 此处可以是显式导出
add @1;
LIBRARY后跟的是项目名,EXPORTS后是这个dll中需要导出的函数名
模块定义文件(.def)是包含一个或多个描述DLL各种属性的模块语句的文本文件,DEF文件必须至少包含下列模块定义语句:(1)文件中的第一个语句必须是LIBRARY语句。(2)EXPORTS语句列出名称,可能的话还会列出DLL导出函数的序号值。通过在函数名的后面加上@符和一个数字,给函数分配序号值。当指定序号值时,序号值的范围必须是从1到N,其中N是DLL导出函数的个数。
将所需的.dll .lib .h放到工程目录下
//隐式加载dll
#pragma comment(lib, "dllDemo.lib")
extern "C" __declspec(dllimport) int __stdcall add(int a, int b);
void main()
{
int sum = add(10, 20);
printf("静态调用,sum = %d\n", sum);
}
或者在项目->属性->链接器->输入中添加附加依赖项 dllDemo.lib。
编译运行,该DLL会直接执行其中的可执行代码
DLL显式加载时指在程序运行过程中,需要用到dll里的函数时,再动态加载dll到内存中,这种加载方式因为是在程序运行后再加载的,所以可以让程序启动更快,而且dll的维护更容易,使得程序如果需要更新,很多时候直接更新dll,而不用重新安装程序.只是这种加载方式,函数调用稍微复杂一点。
需要注意的时这种方式下调用相比较为复杂。比如之前文章中的调用带界面的DLL时,
//1.加载动态库
HINSTANCE hInst= LoadLibrary(L"MyDll.dll");
if (hInst == NULL)
{
printf("加载动态库失败\n");
FreeLibrary(hInst );
return;
}
//2.根据函数名获取函数地址
typedef void(*Add)();//函数指针
Add PrintHello = (Add)GetProcAddress(hInst, "PrintHello");//从dll中加载函数出来
if (PrintHello == NULL)
{
FreeLibrary(hInst);
AfxMessageBox("函数地址获取失败");
}
PrintHello();//运行函数
FreeLibrary(hInst); //LoadLibrary后要记得FreeLibrary
system("pause");
return 0;
// 运行时加载DLL库
HMODULE module = LoadLibraryA("DLLTest1.dll"); // 根据DLL文件名,加载DLL,返回一个模块句柄
if (module == NULL)
{
printf("加载动态库失败\n");
FreeLibrary(module);
return;
}
typedef int(*AddFunc)(int, int); // 定义函数指针类型
// 导出函数地址
AddFunc add = (AddFunc)GetProcAddress(module, "add");// GetProcAddress返回指向的函数名的函数地址
if (add == NULL)
{
FreeLibrary(module);
AfxMessageBox("函数地址获取失败");
}
int sum = add(100, 200);
printf("动态调用,sum = %d\n",sum);
Steps:
1、声明头文件
,说明我想用windows32方法来加载和卸载DLL
2、然后用typedef定义一个指针函数类型.typedef void(*Add)
//这个指针类型,要和你调用的函数类型和参数保持一致
3、定一个句柄实例,用来取DLL的实例地址。HINSTANCE hInst
;
格式为hInst=LoadLibrary(“DLL地址”)
;这里字符串类型是LPSTR,当是unicode字符集的时候会不行,
因此要在配置-属性-常规里面把默认字符集“unicode”改成支持多字符扩展即可。
4、取的地址要判断,返回的句柄是否为空,如果为无效句柄,那么要释放加载DLL所占用的内存。
5、定义一个函数指针,用来获取你要用的函数地址。
然后通过GetProcAdress
来获取函数的地址,参数是DLL的句柄和你要调用的函数名:比如:add=(Add)GetProcAdress(hdll,"add");
这里也要判断要函数指针是否为空,如果没取到要求的函数,那么要释放句柄。
6、然后通过函数指针来调用函数。
7、调用结束后,就释放句柄FreeLibrary(hInst);
预编译 --> 编译 --> 汇编 --> 链接