DLL书写
import和export
头文件由于不参与编译,所以一定要注意区分是在什么时候引用的。如果是在定义函数/类的源文件中使用(内部编译),则要使用__declspec(dllexport),指明要输出在生成的dll文件中的函数/类。但若在引用该DLL的文件中使用(外部引用),包含的头文件中应为__declspec(dllimport),指明要从对应的DLL文件中引入哪些函数/类。
头文件中最开始的宏定义往往如下,注意DLL_EXPORT最好更换为更特别的名字,以防引用该库的文件中也定义了该宏:
#ifdef DLL_EXPORT
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
为了成功编译,还要在预编译的头文件中预先定义DLL_EXPORT,同时在对应的DLL源文件中添加#define DLL_EXPORT __declspec(dllexport)
。
DLL的使用
隐式链接
DLL程序书写完毕后编译后会在DEBUG文件夹下生成对应的.dll和.lib文件。新的项目若想引用该dll,则需要进行如下操作:
- 将.h头文件引入包含目录,并在需要使用dll库中函数/类的源文件中include该头文件;
- 引入Lib文件:
- .lib文件引入库目录,并且在“链接器->输入->依赖项”中添加对应的.lib文件;
- 或
#pragma comment (lib,"*.lib")
加入预编译指令,添加对应lib文件;
- 编译链接,生成可执行文件,将.dll文件拷贝至.exe同一文件夹下;
显式链接
该方法需要通过编码完成,较复杂,但能指定DLL文件位置,不需要DLL文件一定与exe文件在同一个文件夹下。具体操作如下:
- 定义DLL句柄,使用
LoadLibrary(L"/path/to/*.DLL")
函数加载对应DLL; - 定义对应的函数指针,以接纳DLL库中对应的函数;
- 使用
GetProcAddress(DLL_Handle, Function_Name)
寻找该dll中对应名称的函数指针,此处应注意进行编译时,不同的编译器对函数名称会有一定方式的处理。C++由于支持函数重载,故函数名中会以一定规则添加参数列表中参数的属性。而C不支持重载,故仅仅是函数名。这也就是为何在编写DLL程序时往往在函数前添加extern "C"
的缘故,添加了这个前缀的函数才会按照C编译器规则,直接将函数名称原封不动地编译。另外一种方式就是通过MAKEINTRESOURCEA(int)
代替Function_Name,直接指定寻找第几个函数; - 使用函数指针调用相应的函数,注意使用前判空;
代码示例:
typedef int(*pAdd)(int, int); //宏定义函数指针类型
HINSTANCE hDll; //DLL句柄
pAdd addFun; //函数指针
pAdd subFun; //函数指针
hDll = LoadLibrary(L"/path/to/Dll1.dll"); // 加载DLL
if (hDll != NULL)
{
addFun = (pAdd)GetProcAddress(hDll, "add"); // 通过名称搜索dll库中的add函数赋值给addFun,注意不同编译器的名称处理
subFun = (pAdd)GetProcAddress(hDll, MAKEINTRESOURCEA(2)); // 通过顺序搜索dll库中的第2个函数赋值给subFun
if (addFun != NULL){
cout << "3 + 2 = " << addFun(3, 2) << endl;
} else {
cout << "Couldn't Found Function whose name is 'add'" << endl;
}
if (subFun != NULL){
cout << "3 - 2 = " << subFun(3, 2) << endl;
} else {
cout << "Couldn't Found the 2nd Function" << endl;
}
FreeLibrary(hDll); // 使用完毕后一定注意关闭资源
} else {
cout << "Couldn't Found DLL file - DLL1.dll" << endl;
}
来源:CSDN
作者:水蓝城城主
链接:https://blog.csdn.net/mrliuzhao/article/details/103858586