动态链接库通常不能直接运行,也不能接收消息。它们是一些独立的文件,其中包含能被可执行程序或其他DLL调用来完成某项工作的函数。只有在其他模块调用动态链接库中的函数时,它才发挥作用。实际编程时,可把完成某种功能的函数放在一个动态链接库中,提供给其他程序调用。
Windows API中所有函数都包含在DLL中,比较重要的有3个,分别为:
1、Kernel32.dll
包含用于管理内存、进程和线程的函数。
2、User32.dll
包含用于执行用户界面任务(如窗口创建和消息传递的函数等)的函数。
3、GDI32.dll
包含用于画图和显示文本的函数。
静态库和动态库
1、静态库
函数和数据被编译成一个二进制文件,扩展名为.LIB。使用静态库时,编译链接可执行文件时,链接器从库中复制这些函数和数据并把它们和应用程序的其他模块组合起来创建最终的可执行文件。发布产品时,只需要发布这个可执行文件,并不需要发布被使用的静态库。
2、动态库
需要提供2个文件:引入库.lib文件和DLL文件。动态库的引入库.lib文件与静态库虽然后缀相同,但含义完全不同。引入库文件.lib包含DLL导出的函数和变量的符号名,.dll文件包含DLL实际的函数和数据。编译链接时,只需要链接DLL的引入库文件,DLL中的函数代码和数据并不复制到可执行文件中,直到可执行程序运行时,才去加载需要的DLL,将该DLL映射到进程的地址空间,然后访问DLL中的导出函数。发布产品时,除了发布可执行文件,还要同时发布动态链接库。
如果多个应用程序使用同一个DLL,该DLL的页面只需要放入内存一次,所有的应用程序都可以共享它的页面。
有两种加载动态链接库的方式:隐式链接和显式加载。
应用程序如果想访问某个DLL中的函数,该函数必须是已经被导出的函数。为了让DLL导出一些函数,需要在每一个将要被导出的函数前面添加标志符_declspec(dllexport)。
客户调用DLL的导出函数时,必须先申明该函数是外部的extern。除了使用extern关键字表明函数是外部定义的之外,还可以使用_declspec(dllimport)来表明函数是从动态链接库中引入的。使用_declspec(dllimport)声明外部函数,能够明确告诉编译器函数是从动态链接库中引入的,编译器可以生成运行效率更高的代码。
通常在编写动态链接库时,都会提供一个头文件,在此文件中提供DLL导出函数原型的声明,以及函数的有关注释文档。程序编译时,头文件不参与编译,源文件单独编译。
dll_1.h文件
#ifdef DLL1_API #else #define DLL1_API _declspec(dllimport) #endif DLL1_API int add(int a, int b); DLL1_API int subtract(int a, int b);
dll_1.cpp文件
#define DLL1_API _declspec(dllexport) #include "dll_1.h" DLL1_API int add(int a, int b) { return a + b; } DLL1_API int subtract(int a, int b) { return a - b; }
动态链接库还可以导出C++类。
dll_1.h文件
#ifdef DLL1_API #else #define DLL1_API _declspec(dllimport) #endif DLL1_API int add(int a, int b); DLL1_API int subtract(int a, int b); class DLL1_API point { public: void Output(int x, int y); };
dll_1.cpp文件
#define DLL1_API _declspec(dllexport) #include "dll_1.h" DLL1_API int add(int a, int b) { return a + b; } DLL1_API int subtract(int a, int b) { return a - b; } void point::Output(int x, int y) { HWND hwnd = GetForegroundWindow(); HDC hdc = GetDC(hwnd); TCHAR buf[20] = { '