动态链接库
DLL就是整个windows操作系统的基础。动态链接库不能直接运行,也不能接收消息。他们就是一些独立的文件。
Windows API中的所有函数都包含在DLL中。
其中三个最重要的DLL
- Kernel32.dll——它包含用于管理内存、进程和线程的各个函数:CreateThread
- User32.dll——它包含用于指定用户界面任务(如窗口的创建和消息的传送)的各个函数
- GDI32.dll——它包含用于画图和显示文本的各个函数
静态库和动态库
静态库:
函数和数据被编译进一个二进制文件(通常扩展名为.LIB)。在使用静态库的情况下,在编译链接可执行文件时,链接器从库中复制这些函数和数据并把它们和应用程序的其他模块组合起来创建最终的可执行文件(.EXE文件)。
动态库:
在使用动态库的时候,往往提供提供两个文件:一个引入库(静态库)(LIB)和一个DLL。引入库包含被DLL导出的函数和变量的符号名,DLL包含实际的函数和数据。在编译链接可执行文件时,只需要链接引入库,DLL中的函数代码和数据并不复制到可执行文件中,而是在运行时候,再去加载DLL,访问DLL中导出的函数。
使用动态链接库的好处:
- 增强产品的功能(更换界面的DLL)
- 提供二次开发的平台(SDK基础版本)
- 简化项目管理(串行开发,以多个DLL的方式获取)
- 可以节省磁盘空间和内存
- 有助于资源的共享(对话框模块,字符串,图标)
- 有助于实现应用程序的本地化(多语言版本)
- 可以采用多种语言来编写
使用动态链接库
创建DLL
dumpbin命令
通过使用这个命令来知道库中导出的都是什么函数。
//提供给用户用的函数
//应用程序如果要访问某个DLL中的函数,那么函数必须是被导出的函数。
//为了让DLL导出一些函数,需要在每个将要被导出的函数前面加上_declspec(dllexport)
_declspec(dllexport)int add(int a, int b)
{
return a + b;
}
_declspec(dllexport)int substract(int a, int b)
{
return a - b;
}
名字改变===名字粉碎,区分不同的函数。
DLL的导入和导出以及条件编译
lib文件直接复制到当前文件路径下,对应的dll文件也要复制过去。
将静态库文件.lib添加到项目属性的链接器-输入-附加依赖项中。
extern int add(int a, int b);
extern int substract(int a, int b);
void CDLLMFCTestDlg::OnBnClickedButton1()
{
CString str;
str.Format(L"4+3 = %d",add(4,3));
MessageBox(str);
}
void CDLLMFCTestDlg::OnBnClickedButton2()
{
CString str;
str.Format(L"4-3 = %d",substract (4, 3));
MessageBox(str);
}
使用dumpbin -imports XXX.exe查看可执行文件导入了哪些DLL。
在.exe文件运行的时候,系统将为exe分配一个4GB的地址空间,然后加载模块会分析该应用程序的输入信息,从中找到该程序将要访问的动态链接库信息。然后在用户的机器上搜索这些动态链接库。
_ declspec(dllexport)与_declspec(dllimport)
与使用extern关键字这种方式对比,使用_declspec(dllimport)的标识符,它将告诉编译器是从动态链接库引入的。
extern表示函数是外部的全局函数。
_declspec(dllexport)是在类、函数以及数据的声明的时候使用。把DLL里面的相关代码暴露出来给其他应用程序使用。**提供给别的应用程序使用。**表示提供者。供DLL内部使用。
_declspec(dllimport)是在外部程序需要使用DLL内相关内容时使用的标识符。**是把DLL中的相关代码插入到应用程序中去。**表示使用者。不是DLL内部使用。
通常情况下,DLL的实现者和使用者不是同一个人,DLL+头文件方式。
具体:略…
头文件建议使用条件指令编译。是使得程序的可读性增强,灵活性增强。
//如果定义了DLL1_API,则什么也不干,如果没听已,则
#ifdef DLL1_API
#else
#define DLL1_API _declspec(dllimport)
#endif
DLL1_API int add(int a, int b);
DLL1_API int substract(int a, int b);
从DLL中导出C++类
动态链接库导出整个类和仅导出该类的某些成员函数在实现方式的区别:如果在声明该类时,指定了导出标志,那么该类中所有的函数都被导出,否则只有那些声明时指定了导出标志的类成员才会被导出。