《VC++深入详解》学习笔记 第十九章 动态链接库
一人可为天下师,一言可为天下法
查看DLL导出函数
通过在D:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin 目录下的dumpbin.exe查询
具体方法为: 在命令行中通过cd指令定位到,,\bin目录下,之后通过dumpbin /exports dll文件完整路径,即可得到DLL的接口。
如要查看user32.dll的接口,输入:dumpbin /exports “C:\Windows\System32\user32.dll” 回车即可。
其中ordinal hint RVA name 行下列出了导出函数
创建Win32DLL库
0、创建win32工程,选择DLL工程。
1、创建.h头文件。头文件中除了标准的#ifndef..#endif外,还需包含两点:1、采用预编译方式定义是输出dll还是读取dll(举例代码如下) 2、声明库函数对外接口(函数声明)对外开放函数需要加上导出标识符MYDLL_API (预编译宏定义)。
#ifndef MYDLL_API #define MYDLL_API extern "C" _declspec(dllimport) //调用时读取dll //extern "C"限定符 #else #define MYDLL_API extern "C" _declspec(dllexport) //输出时导出dll #endif
2、创建.def文件,以输出.lib文件,文件格式如下,该文件为模块定义文件。
LIBRARY “dllName” //.dll文件内部名,工程名一致 EXPORTS //此处可以显式导出,格式为:源文件中函数名为add,这里便添加add,和源文件函数名一致,编译器会自动执行 Add @1 //可以写这个
3、创建.cpp文件,文件内构件库实现函数,注意:需导出函数前均加上导出标识符。
4、调用该库需要文件:.h .dll .lib三个文件。其中.h是函数说明;.lib是引入库文件,保存着函数和变量符号名;.dll是库本体。
隐式调用
静态调用
编译程序时需要头文件、lib文件,运行时需要DLL文件,并且运行过程中DLL文件一直被占用。
显式调用
动态调用
编译时什么都不需要,在需要使用DLL中的函数时,通过LoadLibrary()和FindProcAdress()这两个API调用。
只需要一个DLL文件即可,而且在需要使用的时候DLL才被占用,使用完毕即被解除占用。DLL中有哪些函数可以通过Depends工具查询。
隐式调用win32DLL库
1、将.h .dll .lib三个文件放到工程路径下。
2、在工程中添加.h文件(#include "XXX.h")。
3、添加.lib文件(#pragma comment(lib,"XXX.lib") )。
4、根据.h文件说明直接调用库中函数。
显式调用win32DLL库
1、加载DLL: HMODULE LoadLibrary(LPCTSTR lpFileName); 返回DLL句柄
2、获取目标函数地址: FARPROC GetProcAddress(HMODULE hModule , LPCSTR lpProcName); 返回函数地址
可以通过序号访问DLL函数:通过MAKEINTRESOURCE(序号)获取
... HINSTANCE hInst; //接收加载DLL句柄 hInst = LoadLibrary("MyDll.dll"); //加载DLL typedef int (*ADDPROC)(int a,int b); //定义函数指针类型 ADDPROC Add = (ADDPROC)GetProcAddress(hInst,"add"); //获取DLL导出函数
//ADDPROC Add = (ADDPROC)GetProcAddress(hInst,MAKEINTRESOURCE(1)); ...
释放DLL
BOOL FreeLibrary(HMODULE hModule);
显式访问时,结束使用后需要释放DLL
导出类
声明类的时候在class和类名之间加上导出标识符,就能调用该类,调用方法为构造类对象,然后通过对象调用类成员函数。访问权限仍受限与原版定义权限。
只导出类中部分函数时,应将目标函数前加上导出标识符,调用方法同上
解决名称改编问题
在宏定义导出标识符时加上extern “C"就能实现
注意:1、其中C需要大写
2、只能用于导出全局函数,对于类成员函数无法实现
3、对于类成员函数需要特别添加 _stdcall 关键字在返回值变量和函数名之间(定义和声明都要加)
DllMain函数
可选提供,当提供该函数时加载DLL后就会调用该函数。
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOD lpvReserved);
DLL句柄 调用入口函数原因 可检测该值判断调用方式
该函数不能进行复杂调用,自定义动态库调用优先级高,系统支持库未调用前便以调用复杂函数会出现调用失败导致程序终止。