C++ Qt 调用动态库 插件

1.隐式调用

1>新建一个C++库,工程名为Cal,自动生成三个文件cal.h, cal_global.h, cal.cpp,编译后生成我们需要的Cal.lib, Cal.dll

#ifndef CAL_H
#define CAL_H

#include "cal_global.h"

class CALSHARED_EXPORT Cal
{

public:
    Cal();
    int add(int a, int b);
    int substract(int a, int b);
};

#endif // CAL_H

#include "cal.h"


Cal::Cal()
{
}

int Cal::add(int a, int b)
{
    return a + b;
}

int Cal::substract(int a, int b)
{
    return a - b;
}
2>新建一个Qt应用程序,工程名为CalTest

在CalTest.pro文件所在目录下新建一个lib->cal目录,将cal相关文件拷贝到这个目录下:cal.h, cal_global.h, Cal.lib;

在CalTest.pro文件后面增加两行代码:

INCLUDEPATH += $${PWD}/lib/cal
LIBS += $${PWD}/lib/cal/Cal.lib

我们在构造函数里面测试,代码如下:

#include "dialog.h"
#include "ui_dialog.h"
#include "cal.h"
#include <QDebug>

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    Cal cal;
    int a = 100, b = 200;
    int addResult = cal.add(a, b);
    int substractResult = cal.substract(a, b);
    qDebug() << "add:" << addResult << ",substract:" << substractResult;
}

Dialog::~Dialog()
{
    delete ui;
}


编译完成之后,将Cal.dll文件拷贝到生成的CalTest.exe目录下运行即可。

隐式调用用起来比较方便,但是不太灵活,如果缺少头文件,库文件那么这个程序就编译,执行不了了。


2.显示调用

Cal工程代码如下:

#ifndef CAL_H
#define CAL_H

#include "cal_global.h"

class CALSHARED_EXPORT Cal
{

public:
    Cal();
    int add(int a, int b);
    int substract(int a, int b);
};

extern "C" CALSHARED_EXPORT Cal* createCal();
extern "C" CALSHARED_EXPORT void deleteCal(Cal *cal);

#endif // CAL_H
#include "cal.h"


Cal::Cal()
{
}

int Cal::add(int a, int b)
{
    return a + b;
}

int Cal::substract(int a, int b)
{
    return a - b;
}

Cal* createCal()
{
    return new Cal();
}

void deleteCal(Cal *cal)
{
    delete cal;
    cal = NULL;
}

CalTest调用的时候,CalTest.pro里就不需要

INCLUDEPATH += $${PWD}/lib/cal
LIBS += $${PWD}/lib/cal/Cal.lib

这两行代码了,直接看cpp文件

#include "dialog.h"
#include "ui_dialog.h"
#include <QDebug>
#include <QLibrary>
#include "../Cal/cal.h"


Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);

    typedef Cal* (*CreateCal)();
    typedef void (*DeleteCal)(Cal *cal);

    QLibrary lib("Cal.dll");
    if (lib.load()) {
        CreateCal createCal = (CreateCal)lib.resolve("createCal");
        DeleteCal deleteCal = (DeleteCal)lib.resolve("deleteCal");
        if (createCal && deleteCal) {
            Cal *pcal = createCal();
            int a = 100, b = 200;
            int addResult = pcal->add(a, b);
            int substractResult = pcal->substract(a, b);
            qDebug() << "add:" << addResult << ",substract:" << substractResult;
            deleteCal(pcal);
        } else {
            qDebug() << "resolve failed";
        }
        lib.unload();
    } else {
        qDebug() << "load failed";
    }
}

Dialog::~Dialog()
{
    delete ui;
}

#include "../Cal/cal.h"头文件还是需要的,因为我们不知道Cal类是怎么声明的。

这样当这个dll不存在的时候我们的程序还是可以通过编译运行的。

但是这里还存在问题,Cal类我们还是导出了,因为我们演示的是一个比较简单的类,如果这个类比较复杂那么导出就有麻烦了,因为导出类的父类和子类也要导出,所以我们希望这个类不导出也可以使用。

3.纯虚基类,不导出类,通过虚表来定位具体的函数

Cal工程代码

#ifndef CALINTERFACE_H
#define CALINTERFACE_H

#include "cal_global.h"

class CalInterface
{
public:
    virtual ~CalInterface() {}
    virtual int add(int a, int b) = 0;
    virtual int substract(int a, int b) = 0;
};

extern "C" CALSHARED_EXPORT CalInterface* createCal();
extern "C" CALSHARED_EXPORT void deleteCal(CalInterface *cal);

#endif // CALINTERFACE_H

#include "CalInterface.h"
#include "cal.h"

CalInterface* createCal()
{
    return new Cal();
}

void deleteCal(CalInterface *cal)
{
    delete cal;
    cal = NULL;
}

#ifndef CAL_H
#define CAL_H

#include "cal_global.h"
#include "CalInterface.h"

class Cal : public CalInterface
{

public:
    Cal();
    virtual ~Cal();

    virtual int add(int a, int b);
    virtual int substract(int a, int b);
};

#endif // CAL_H
Cal.cpp内容和上面一样
CalTest工程调用:

#include "dialog.h"
#include "ui_dialog.h"
#include <QDebug>
#include <QLibrary>
#include "../Cal/CalInterface.h"


Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);

    typedef CalInterface* (*CreateCal)();
    typedef void (*DeleteCal)(CalInterface *cal);

    QLibrary lib("Cal.dll");
    if (lib.load()) {
        CreateCal createCal = (CreateCal)lib.resolve("createCal");
        DeleteCal deleteCal = (DeleteCal)lib.resolve("deleteCal");
        if (createCal && deleteCal) {
            CalInterface *pcal = createCal();
            int a = 100, b = 200;
            int addResult = pcal->add(a, b);
            int substractResult = pcal->substract(a, b);
            qDebug() << "add:" << addResult << ",substract:" << substractResult;
            deleteCal(pcal);
        } else {
            qDebug() << "resolve failed";
        }
        lib.unload();
    } else {
        qDebug() << "load failed";
    }
}

Dialog::~Dialog()
{
    delete ui;
}


这样Cal类就不必要导出了,而且CalInterface.h头文件是比较独立的,不依赖于其他的一些东西。

C++调用方法跟这类似,只是将QLibrary换成了LoadLibrary,GetProcAddress。

4.插件编写(lower-level api)

1>创建C++库,类型选择Qt Plugin,名称CalPlugin,删掉自动生成的genericplugin.h和genericplugin.cpp两个文件

2>创建接口类头文件calinterface.h

#ifndef CALINTERFACE_H
#define CALINTERFACE_H

#include <QtPlugin>

class CalInterface
{
public:
    virtual ~CalInterface() {}
    virtual int add(int a, int b) = 0;
    virtual int substract(int a, int b) = 0;
};

Q_DECLARE_INTERFACE(CalInterface, "org.qt-project.Qt.Examples.CalPlugin.CalInterface")

#endif // CALINTERFACE_H
3>创建实现类Cal

#ifndef CAL_H
#define CAL_H

#include <QObject>
#include "calinterface.h"

class Cal : public QObject, public CalInterface
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.CalPlugin.Cal" FILE "CalPlugin.json")
    Q_INTERFACES(CalInterface)

public:
    explicit Cal(QObject *parent = 0);
    int add(int a, int b);
    int substract(int a, int b);
};

#endif // CAL_H

#include "cal.h"

Cal::Cal(QObject *parent)
    : QObject(parent)
{
}

int Cal::add(int a, int b)
{
    return a + b;
}

int Cal::substract(int a, int b)
{
    return a - b;
}
编译默认生成的dll文件在安装目录的plugins子目录下面,等会我们需要将它拷贝出来。

5.调用插件

1>创建CalPluginTest对话框类型的应用程序,编译运行;

2>在CalPluginTest.exe所在目录下新建一个plugins子目录,将上面生成的CalPlugin.dll插件拷贝到plugins目录下;

3>直接在构造函数写测试代码如下:

#include "dialog.h"
#include "ui_dialog.h"
#include <QtWidgets>
#include "../CalPlugin/calinterface.h"

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);

    QDir dir(QCoreApplication::applicationDirPath() + "/plugins");
    foreach (QString filename, dir.entryList(QDir::Files)) {
        qDebug() << "path:" << dir.absoluteFilePath(filename);
        QPluginLoader loader(dir.absoluteFilePath(filename));
        CalInterface *pcal = qobject_cast<CalInterface*>(loader.instance());
        if (pcal) {
            int a = 12, b = 34;
            int addResult = pcal->add(a, b);
            int substractResult = pcal->substract(a, b);
            qDebug() << "add:" << addResult << ", substract:" << substractResult;
        } else {
            qDebug() << "error";
        }
    }
}

Dialog::~Dialog()
{
    delete ui;
}


  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
QT动态库的交互可以通过以下几种方法: 1. 使用QLibrary类:QLibrary是QT提供的一个跨平台的动态库加载类。可以使用QLibrary类中的load()函数来加载动态库文件,然后使用resolve()函数来获取动态库中导出的函数指针,从而调用动态库中的函数。 示例代码: ```c++ QLibrary mylib("mylib.dll"); // 加载动态库 if (mylib.load()) { typedef int (*MyFunc)(int, int); MyFunc myfunc = (MyFunc)mylib.resolve("myfunc"); // 获取动态库中的函数指针 if (myfunc) { int result = myfunc(1, 2); // 调用动态库中的函数 qDebug() << result; } } ``` 2. 使用QPluginLoader类:QPluginLoader是QT提供的一个跨平台的插件加载类。可以使用QPluginLoader类中的load()函数来加载插件,然后使用instance()函数来获取插件中导出的类的实例,从而调用插件中的函数。 示例代码: ```c++ QPluginLoader loader("myplugin.dll"); // 加载插件 if (loader.load()) { MyPluginInterface* plugin = qobject_cast<MyPluginInterface*>(loader.instance()); // 获取插件中导出的类的实例 if (plugin) { int result = plugin->myfunc(1, 2); // 调用插件中的函数 qDebug() << result; } } ``` 其中,MyPluginInterface是插件中导出的类的接口,需要在插件中定义。 3. 使用QProcess类:QProcess是QT提供的一个跨平台的进程类。可以使用QProcess类中的start()函数来启动一个动态库,然后使用readAllStandardOutput()函数来获取动态库中输出的信息,从而调用动态库中的函数。 示例代码: ```c++ QProcess process; process.start("mylib.exe"); // 启动动态库 process.waitForStarted(); process.write("1 2\n"); process.waitForBytesWritten(); process.waitForReadyRead(); QString output = process.readAllStandardOutput(); // 获取动态库中输出的信息 int result = output.toInt(); qDebug() << result; ``` 其中,mylib.exe是一个控制台程序,需要在控制台中输出计算结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值