c/c++开发时直接调用dll动态库中的函数,无需使用头文件编译
一、开发环境
我写dome用的是Qt5.14.2

二、创建dll
1、搭建生成dll的工程
使用Qt Creator新建一个C++动态库工程




设置类名和所需的Qt库,然后直接下一步

点击完成,完成工程的创建

生成的项目里有以下文件

需要其他的库可以直接在pro文件中进行配置

2、在项目文件中添加代码,实现一个可对外继承QWidget的类
.h文件,ReadDllTest 类继承自QWidget,可以使用Qt的信号与槽函数等等机制。
#include <QWidget>
#include <QString>
class __declspec(dllexport) ReadDllTest : public QWidget
{
public:
ReadDllTest(QWidget *parent = nullptr);
QString getObjStr();
};
.cpp文件,
ReadDllTest::ReadDllTest(QWidget *parent)
:QWidget(parent)
{
// 设置初始位置和大小
resize(100, 100);
move(500, 200);
// 随意打印一个字符串
qDebug() << getObjStr();
}
// 非QWidget的标准函数 用于测试
QString ReadDllTest::getObjStr()
{
return QString("这里是对象中的str");
}
3、使用 __declspec(dllexport) 关键字来修饰dll对外的接口,用来获取dll中的对象指针或其他资源。
// 在调用此接口时返回一个基类是QWidget的对象的指针
__declspec(dllexport) QWidget* __stdcall getObj();
函数实现
// 保存对象指针的全局变量
ReadDllTest *obj = nullptr;
// 判断全局变量是否为空 返回基类为QWidget的对象的指针
QWidget *getObj()
{
if(!obj){
obj = new ReadDllTest();
}
return obj;
}
4、点击构建后生成dll


三、新建一个测试的工程用于加载dll
1、随便绘制一个窗口,给按钮创建槽函数


2、使用windows接口加载dll库
引入接口头文件
#include <windows.h>
使用QFileDialog的接口选择dll文件,获取它的文件路径
QString filepsth = QFileDialog::getOpenFileName(this, "选择dll", "./", "dll(*.dll);");
定义一个用于
将文件路径字符串转换为接口使用的类型
// 定义一个数组,长度根据文件路径自行判断,要够长
wchar_t filepathwc[256];
// 一定要对数组进行初始化,不然后面的步骤会出错
memset(filepathwc, 0, 128 * sizeof(wchar_t));
qDebug() << "file = " << filepsth;
// 使用QString的接口将文件名写入数组中
qDebug() << "to wc = " << filepsth.toWCharArray(filepathwc);
加载动态库
// 传入文件路径 加载dll
HMODULE module = LoadLibrary(filepathwc);
// 判断是否加载成功
if (module == NULL){
qDebug() << "加载动态库失败" << GetLastError();
}else{
qDebug() << "加载成功";
}
定义一个接收函数指针的函数指针类型,接口和dll的接口一致
typedef QWidget*(*GetObj)();
从dll库中获取函数地址
// 获取dll中的函数的地址
GetObj add = NULL;
// 传入动态库句柄 函数在dll中的函数名
add = (GetObj)GetProcAddress(module, "_Z6getObjv");
qDebug() << add;
获取函数地址成功后,调用函数,获取dll库中的对象,并将其显示
// 判断函数地址是否获取成功
if(add){
qDebug() << "fun get success!";
// 使用QWidget指针接收函数传来的对象
QWidget *wids = add();
if(wids){
// 显示dll库中实现的窗口
wids->show();
}
}else{
qDebug() << "error = " << GetLastError();
}
运行效果

dll中的窗口显示出来了

四、 如何查看dll中的函数名
1、打开vs的窗口应用

cd到dll生成的位置

使用命令
dumpbin /exports readDllTest.dll > readDllTest.txt

然后打开生成的txt文档,可以看到一个和我们定义的函数很像的字符串,主要是首位多了些字符


这个就是我们之前定义函数,使用txt文档中的这一串字符来获取函数名,直接使用函数名可能会获取不到

五、总结
这种方法可以用于开发可扩展的应用程序,在程序主体已经发布的情况下,可以通过继承统一的基类来实现exe直接加载dll,无需二次编译,之后可以直接发布dll作为插件,然后在exe中编写加载管理插件模块来实现应用程序平台的动态扩展。