自从微软推出16位的Windows操作系统起,此后每种版本的Windows操作系统都非常依赖于动态链接库(DLL)中的函数和数据,实际上 Windows操作系统中几乎所有的内容都由DLL以一种或另外一种形式代表着,例如显示的字体和图标存储在GDI DLL中、显示Windows桌面和处理用户的输入所需要的代码被存储在一个User DLL中、Windows编程所需要的大量的API函数也被包含在Kernel DLL中。
DLL是建立在客户/服务器通信的概念上,包含若干函数、类或资源的库文件,函数和数据被存储在一个DLL(服务器)上并由一个或多个客户导出而使用,这些客户可以是应用程序或者是其它的DLL。DLL库不同于静态库,在静态库情况下,函数和数据被编译进一个二进制文件(通常扩展名为*.LIB), Visual C++的编译器在处理程序代码时将从静态库中恢复这些函数和数据并把他们和应用程序中的其他模块组合在一起生成可执行文件。这个过程称为"静态链接",此时因为应用程序所需的全部内容都是从库中复制了出来,所以静态库本身并不需要与可执行文件一起发行。
在动态库的情况下,有两个文件,一个是引入库(.LIB)文件,一个是DLL文件,引入库文件包含被DLL导出的函数的名称和位置,DLL包含实际的函数和数据,应用程序使用LIB文件链接到所需要使用的DLL文件,库中的函数和数据并不复制到可执行文件中,因此在应用程序的可执行文件中,存放的不是被调用的函数代码,而是DLL中所要调用的函数的内存地址,这样当一个或多个应用程序运行是再把程序代码和被调用的函数代码链接起来,从而节省了内存资源。从上面的说明可以看出,DLL和.LIB文件必须随应用程序一起发行,否则应用程序将会产生错误。
微软的Visual C++支持三种DLL,它们分别是Non-MFC Dll(非MFC动态库)、Regular Dll(常规DLL)、Extension Dll(扩展DLL)。Non-MFC DLL指的是不用MFC的类库结构,直接用C语言写的DLL,其导出的函数是标准的C接口,能被非MFC或MFC编写的应用程序所调用。Regular DLL:和下述的Extension Dlls一样,是用MFC类库编写的,它的一个明显的特点是在源文件里有一个继承CWinApp的类(注意:此类DLL虽然从CWinApp派生,但没有消息循环),被导出的函数是C函数、C++类或者C++成员函数(注意不要把术语C++类与MFC的微软基础C++类相混淆),调用常规DLL的应用程序不必是MFC应用程序,只要是能调用类C函数的应用程序就可以,它们可以是在Visual C++、Dephi、Visual Basic、Borland C等编译环境下利用DLL开发应用程序。
打开VS2013,选择Win32:
选择DLL:
里边会自动为你添加好几个文件:
以及一个dllmain的格式,这里面是,当加载一个DLL(ATTACH)或者释放一个DLL(DETACH)等不同状态发生时,所要执行的代码(只不过下面的代码是当四个状态发生时什么都不执行):
参数中,hMoudle是动态库被调用时所传递来的一个指向自己的句柄(实际上,它是指向_DGROUP段的一个选择符); ul_reason_for_call是一个说明动态库被调原因的标志,当进程或线程装入或卸载动态链接库的时候,操作系统调用入口函数,并说明动态链接库被调用的原因,它所有的可能值为:DLL_PROCESS_ATTACH: 进程被调用、DLL_THREAD_ATTACH: 线程被调用、DLL_PROCESS_DETACH: 进程被停止、DLL_THREAD_DETACH: 线程被停止;lpReserved为保留参数。
我们直接在testDLL.cpp中添加代码,这里保存的是DLL的导出函数:
extern "C" __declspec(dllexport) int add(int a, int b) { return (a + b); } extern "C" __declspec(dllexport) int sub(int a, int b) { return (a - b); }
编译生成一个testDLL.dll.下面进行测试:
隐式连接:
#include <iostream> #include <windows.h> #pragma comment(lib,"testDLL.lib") extern "C"_declspec(dllimport) int add(int a, int b); extern "C"_declspec(dllimport) int sub(int a, int b); int main() { int nParam1 = 9; int nParam2 = 3; int nAdd = add(nParam1, nParam2); int nSub = sub(nParam1, nParam2); std::cout << nAdd << ":" << nSub << std::endl; system("pause"); return 0; }
显示链接:
#include <iostream> #include <windows.h> int main() { typedef int (*_pAdd)(int a, int b); typedef int (*_pSub)(int a, int b); HINSTANCE hDll = LoadLibrary("testDLL.dll"); int nParam1 = 9; int nParam2 = 3; _pAdd pAdd = (_pAdd)GetProcAddress(hDll, "add"); _pSub pSub = (_pSub)GetProcAddress(hDll, "sub"); int nAdd = pAdd(nParam1, nParam2); int nSub = pSub(nParam1, nParam2); std::cout << nAdd << ":" << nSub << std::endl; FreeLibrary(hDll); system("pause"); return 0; }