What is the difference between hot-loading plugins and dynamically loading DLLs in QT? The hot loading plug-in is to dynamically load the plug-in when the program is running, and the dynamic loading of the DLL is to link the DLL file into the program when the program is compiled. Hot loading plug-ins can update plug-ins without stopping the program, while dynamically loading DLLs requires recompiling the program to update the DLL file.
How to hot load plugin in QT to update the plugin without stopping the program? Use the QPluginLoader class to implement hot-loading plugins. When the program is running, use QPluginLoader to load the plug-in, and use the QObject::connect() function to connect the signal and slot of the plug-in. When the plug-in needs to be updated, you can use the QPluginLoader::unload() function to unload the old plug-in, and then use QPluginLoader again to load the new plug-in. This makes it possible to update plugins without stopping the program.
Personally understand that when using a DLL dynamic library in an actual project, if you need to update or replace it, you need to close the program and replace the DLL before restarting the program. Generally, it may be fine, but some special scenarios require 24-hour work or communication, and there are always tasks running It is not suitable to close the main program. In this case, the hot-swappable plug-in function of QT Plugin is very much needed. Without restarting the program, adding a setting button and connecting a signal slot on the setting interface can realize dynamic update of the plug-in without stopping the program.
The author of this article is original, please attach the source of the article and the link of this article for reprinting.
QT Plugin hot plug-in directory
1 QPluginA
Plugin A source code
1.1 QPluginA.pro
QT += core
QT += gui
QT += widgets
TEMPLATE = lib
CONFIG += plugin
TARGET = HelloCTK
CONFIG += c++11
EXAMPLE_FILES = qtplugin.json
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
qplugina.cpp
HEADERS += \
DeclareInterface.h \
QPluginA_global.h \
qplugina.h
# Default rules for deployment.
unix {
target.path = /usr/lib
}
!isEmpty(target.path): INSTALLS += target
1.2 DeclareInterface.h
//declareinterface.h
#ifndef DECLAREINTERFACE_H
#define DECLAREINTERFACE_H
#include <QWidget>
//定义接口
class DeclareInterface
{
public:
virtual ~DeclareInterface() {}
virtual int add(int a,int b) = 0;
};
//一定是唯一的标识符
#define DeclareInterface_iid "Examples.Plugin.DeclareInterface"
QT_BEGIN_NAMESPACE
Q_DECLARE_INTERFACE(DeclareInterface, DeclareInterface_iid)
QT_END_NAMESPACE
#endif // DECLAREINTERFACE_H
1.3 qplugina.h
#ifndef QPLUGINA_H
#define QPLUGINA_H
#include "QPluginA_global.h"
#include <QObject>
#include <QtPlugin>
#include "DeclareInterface.h"
class QPluginA : public QObject, public DeclareInterface
{
Q_OBJECT
Q_INTERFACES(DeclareInterface)
Q_PLUGIN_METADATA(IID "qtplugin.json")
public:
QPluginA(QObject *parent = 0);
int add(int a, int b);
};
#endif // QPLUGINA_H
1.4 qplugina.cpp
#include "qplugina.h"
QPluginA::QPluginA(QObject *parent) : QObject(parent)
{
}
int QPluginA::add(int a, int b)
{
return a+b;
}
2 QPluginB
Plugin B source code
2.1 QPluginB.pro
QT += core
QT += gui
QT += widgets
TEMPLATE = lib
CONFIG += plugin
TARGET = HelloCTKS
CONFIG += c++11
EXAMPLE_FILES = qtplugin.json
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
qpluginb.cpp
HEADERS += \
DeclareInterface.h \
QPluginB_global.h \
qpluginb.h
# Default rules for deployment.
unix {
target.path = /usr/lib
}
!isEmpty(target.path): INSTALLS += target
2.2 DeclareInterface.h
//declareinterface.h
#ifndef DECLAREINTERFACE_H
#define DECLAREINTERFACE_H
#include <QWidget>
//定义接口
class DeclareInterface
{
public:
virtual ~DeclareInterface() {}
virtual int add(int a,int b) = 0;
};
//一定是唯一的标识符
#define DeclareInterface_iid "Examples.Plugin.DeclareInterface"
QT_BEGIN_NAMESPACE
Q_DECLARE_INTERFACE(DeclareInterface, DeclareInterface_iid)
QT_END_NAMESPACE
#endif // DECLAREINTERFACE_H
2.3 qpluginb.h
#ifndef QPLUGINB_H
#define QPLUGINB_H
#include "QPluginB_global.h"
#include <QObject>
#include <QtPlugin>
#include "DeclareInterface.h"
class QPluginB : public QObject, public DeclareInterface
{
public:
Q_OBJECT
Q_INTERFACES(DeclareInterface)
Q_PLUGIN_METADATA(IID "qtplugin.json")
public:
QPluginB(QObject *parent = 0);
int add(int a, int b);
};
#endif // QPLUGINB_H
2.4 qpluginb.cpp
#include "qpluginb.h"
QPluginB::QPluginB(QObject *parent) : QObject(parent)
{
}
int QPluginB::add(int a, int b)
{
return a-b;
}
3 QMainPlugin
project source code
3.1 QMainPlugin.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
mainwindow.cpp
HEADERS += \
DeclareInterface.h \
mainwindow.h
FORMS += \
mainwindow.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
3.2 DeclareInterface.h
//declareinterface.h
#ifndef DECLAREINTERFACE_H
#define DECLAREINTERFACE_H
#include <QWidget>
//定义接口
class DeclareInterface
{
public:
virtual ~DeclareInterface() {}
virtual int add(int a,int b) = 0;
};
//一定是唯一的标识符
#define DeclareInterface_iid "Examples.Plugin.DeclareInterface"
QT_BEGIN_NAMESPACE
Q_DECLARE_INTERFACE(DeclareInterface, DeclareInterface_iid)
QT_END_NAMESPACE
#endif // DECLAREINTERFACE_H
3.3 mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDir>
#include <QDebug>
#include <QMessageBox>
#include <QPluginLoader>
#include "DeclareInterface.h"
#pragma execution_character_set("utf-8")
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void on_pushButton_3_clicked();
private:
Ui::MainWindow *ui;
QPluginLoader pluginLoader;
bool loadPlugin(QString strPlugin); //加载插件
DeclareInterface* m_pInterface = nullptr; //获取插件类型
};
#endif // MAINWINDOW_H
3.4 mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
bool MainWindow::loadPlugin(QString strPlugin){
pluginLoader.setFileName(strPlugin);
QObject *plugin = pluginLoader.instance();
qDebug() << __FUNCTION__ << pluginLoader.errorString();
if (plugin) {
m_pInterface = qobject_cast<DeclareInterface *>(plugin);
if (m_pInterface)
return true;
}
return false;
}
void MainWindow::on_pushButton_clicked()
{
int a = 5;
int b = 5;
int r = -1;
if(m_pInterface){
r = m_pInterface->add(a, b);
}
QMessageBox::warning(this, "插件调用成功", QString::number(r));
}
void MainWindow::on_pushButton_2_clicked()
{
pluginLoader.unload();
if(!loadPlugin("HelloCTK.dll")){
QMessageBox::warning(this, "Error", "Could not load the plugin");
}
}
void MainWindow::on_pushButton_3_clicked()
{
pluginLoader.unload();
if(!loadPlugin("HelloCTKS.dll")){
QMessageBox::warning(this, "Error", "Could not load the plugin");
}
}
PS: Program effect diagram PluginA implements subtraction PluginB implements addition