C++调用DLL
编译DLL时会生成两个文件,一个是lib, 一个是dll. 注意,此处生成的lib文件和静态库的lib文件不是一个东西。
调用DLL有两种方式:隐式加载、显式加载。
一、隐式加载方式
隐式加载方式下,需要3个文件,分别是dll文件、lib文件以及对应的头文件。例paneldata.dll、paneldata.lib、paneldata.h,将上述文件放入调用程序代码所在目录。
调用代码非常简单,程序中只需要增加两行代码,以下举例说明:
#include<iostream>
#include "paneldata.h" //引入头文件
#pragma comment(lib,"paneldata.lib") //把lib文件包括进来
int main(){
int result = paneldata_func1(3.14); //像调用本地函数一样调用外部函数
cout<< result <<endl;
return 0;
}
二、显式加载方式
显式加载方式下,调用dll文件只需要为调用者提供一个.dll文件,以及要调用的函数(或类)的名称和参数,将dll文件放入调用程序代码所在目录。
调用有以下步骤:
1、typedef一个与被调用函数类型一致的函数指针。
typedef int (*Dllfunc)(double)
//假设被调用函数返回值为int, 参数类型为double
在这段代码中,Dllfunc的类型被定义为:
“一个指向返回值为int 且 参数类型为double的函数的指针”。
划重点:
typedef 绝不是像 typedef int integer 这么简单——把类型名换个别名。为了深入理解以上代码,建议对此知识点另外深入学习。
2、获得dll文件的句柄。因为是动态调用,dll和可执行文件一起发布,要调用dll,必须先获得它的句柄,要用到一个函数:
HMODULE hDLL = LoadLibrary(dllname);
//HMODULE 是windows句柄类型,为了使用它,头文件中需包括windows.h
3、定义一个函数指针,用于指向dll中被调用的函数地址,以实现函数功能。
DLLFunc dllfunc;
dllfunc = (DLLFunc)GetProcAddress(hDLL, "paneldata_func1");
现在就可以像使用paneldata_func1()一样来使用dllfunc()了。
最后,别忘了释放dll句柄:
FreeLibrary(hDLL);
完整代码如下:
#include "windows.h"
typedef int (*Dllfunc)(double);
int main(){
const wchar_t* dllname = L"dll1.dll";
HMODULE hDLL = LoadLibrary(dllname);
//LoadLibrary的参数类型为LPCWSTR(即wchar_t *)
DLLFunc dllfunc;
dllfunc = (DLLFunc)GetProcAddress(hDLL, "paneldata_func1");
//从hDLL文件空间中获得paneldata_func1函数的地址,然后将其强制转换为DLLFunc类型,作为一个函数体传递给dllfunc指针。
dllfunc(3.1415); //调用了paneldata_func1()
FreeLibrary(hDLL);
return 0;
}
关于显式加载的通俗理解
举一个简单的例子,病人到医院看病,首先要挂号,拿着挂号单走进医院,找到对应科室,向医生提供各种检查结果,医生开药。
由于机器人技术的发展,病人现在不用大老远跑到医院了。只需要网上挂了号,通过机器人把检查结果发给医生,医生就能反馈开药结果。
在这个过程中,病人不再需要直接和医院、医生打交道。但为了通过机器人与医院取得联系,病人首先需要一张合法的挂号单,通过挂号单和医院建立联系,医院就相当于dll文件,这个挂号单相当于dll文件的句柄。和医院取得联系后,还要知道科室的位置,需要把科室名称通过机器人告诉医院,由医院返回科室地址。科室名称就相当于我们要调用的函数的名称,而科室地址就是函数在dll文件中的位置。与科室取得联系后,机器人还不能与科室对话,因为不同科室需要的检查结果类型不同,有要CT片子的,有要验血结果的,有要血压血糖的,机器人不知道它应该向病人要什么,所以机器人首先要知道科室需要什么类型的检查结果以及科室开的药物类型,然后自己实现一个和科室完全一样的接口,明确需要的检查结果及类型,并把这个接口展示给病人。这个人机接口就是我们定义的函数指针。通过这个指针,可以把病人的检验结果传递给科室医生,同时能正确接收科室医生开出的药物类型,也就是函数的返回类型。看病完毕后,病人要告诉机器人释放与医院的连接。
完整梳理概念如下:
医院——dll文件
挂号单——dll文件句柄
科室——函数
人机接口——函数指针
检查结果类型——函数参数类型
开药类型——函数返回值类型
获得科室位置——获得函数地址
释放与医院连接——释放dll句柄