当前位置:网站首页>(QT) plug in of QT project
(QT) plug in of QT project
2022-07-18 14:06:00 【Suzhou frog】
One . Preface < original >
The author's previous project used the method of dynamic library to make the program load when running DLL, Recently, several projects have used the plug-in method to load the modules required by the program . At first I also wondered , With my shallow understanding Qt The plug-in nature of is loaded dll, It's just that it can be done during operation dll Loading , No load required lib, Then it should be no different from loading with dynamic library , Some inherent benefits of dynamic libraries, such as decoupling , Benefits of flexibility , Plug in also has , So what's the difference between these two , Can plug-in also bring some benefits that pure dynamic libraries don't have , Here are the benefits of my own perspective .
benefits :
The plug-in supports hot plug, which makes the application more flexible , The software only needs to load plug-ins when it is used , Do not load when not in use , Then when the program is packaged, you can only package the plug-ins you need DLL, Take my current project as an example , Various formats are analyzed in the project , So many libraries are needed to support parsing , The volume of software packages is getting larger ( almost 300M), After supporting plug-ins , For example, the software clicks on the video , I found that there is no video parsing dll, Background online download , Then software assembly , Before that 300M Get rid of many unnecessary DLL At present, there are only the most primitive 100M, A slimming of the software package . Look slightly The essence One o'clock , A link that must be loaded before running the software , It becomes a behavior that can freely control loading after running , Then the flexibility and controllability will be very strong , There will be more choices for projects . It has all the advantages of traditional dynamic library , So sometimes projects prefer to be in the form of plug-ins .
Two . Plugins in Qt The use of
1. Encapsulation of plug-in library
<1> Add the interface header file of the plug-in library ( Exposed to external modules )
Define a virtual function class for external access plug-ins , After definition, use Q_DECLARE_INTERFACE Bind these two external classes to two unique strings , notice Qt Meta object system this interface .
#ifndef IMAINWIDGET_H
#define IMAINWIDGET_H
#include <QtGlobal>
#define MAINWIDGET_UUID "{89586123-e83d-451c-a1d5-84ff78b76d79}"
class IMainWidget
{
public:
virtual QWidget *instance() = 0;
// Add the interface that the external module needs to access
};
class IMainWidgetPlugin
{
public:
virtual QObject *instance() = 0;
virtual IMainWidget *mainWidget() const = 0;
virtual void showMainWidget() = 0;
protected:
virtual void mainWidgetCreated() = 0;
virtual void aboutToSignOut() = 0;
};
Q_DECLARE_INTERFACE(IMainWidget,"QtFrameworkTemplate.Plugin.IMainWidget/1.0")
Q_DECLARE_INTERFACE(IMainWidgetPlugin,"QtFrameworkTemplate.Plugin.IMainWidgetPlugin/1.0")
#endif
<2> Add the internal header file of the plug-in library ( Don't expose )
Q_PLUGIN_METADATA(IID IPlugin_iid FILE "mainwidget.json") This macro defines a parameter for the first time uuid, Make sure it's the only one , the second json It's a must , When the specified file cannot be found ,moc There will be errors , Even an empty file is ok .
Q_INTERFACE In another blog post, it is said that qobject_cast() Can carry out correctly QObject* Conversion to interface pointer , So here we add two class names inherited by this class Q_INTERFACES(IPlugin IMainWidgetPlugin).
#ifndef MAINWIDGETPLUGIN_H
#define MAINWIDGETPLUGIN_H
#include "interfaces/ipluginmanager.h"
#include"interfaces/MainWidget/imainwidget.h"
#include"mainwidget.h"
class MainWidgetPlugin :
public QObject,
public IPlugin,
public IMainWidgetPlugin
{
Q_OBJECT
#if QT_VERSION >= 0x050000
Q_PLUGIN_METADATA(IID IPlugin_iid FILE "mainwidget.json")
#endif
Q_INTERFACES(IPlugin IMainWidgetPlugin)
public:
MainWidgetPlugin();
~MainWidgetPlugin();
virtual QObject* instance() { return this; }
//IPlugin
virtual QUuid pluginUuid() const { return MAINWIDGET_UUID; }
virtual void pluginInfo(IPluginInfo *aPluginInfo);
virtual bool initConnections(IPluginManager *aPluginManager, int &aInitOrder);
virtual bool initObjects();
virtual bool initSettings();
virtual bool startPlugin();
//IMainWidgetPlugin
virtual IMainWidget *mainWidget() const;
virtual void showMainWidget();
virtual void showStartupDialog();
virtual void closeStartupDialog();
virtual bool isStartDialogVisible() const;
signals:
void mainWidgetCreated();
void aboutToSignOut();
protected slots:
void onAboutToClose();
void onMainWidgetAboutToDestory();
private:
IPluginManager *m_pluginManager = NULL;
MainWidget *m_mainWidget = NULL;
};
#endif // MAINWIDGETPLUGIN_HSuch a plug-in library project is encapsulated , Write business logic to generate corresponding dll that will do .
2. Loading of plug-in library
<1> The plug-in module reads
A loaded function is posted here ,PluginManager Class is a plug-in specially used to manage loading , You can see , The plug-in is successfully loaded. Use the general base class of the plug-ins IPlugin Accept the instance object of the plug-in , Then process this IPlugin Information is stored in customized PluginItem in , Finally, these plug-ins PluginItem Save as QHash<QUuid, PluginItem> m_pluginItems in .
struct PluginItem
{
IPlugin *plugin;
IPluginInfo *info;
QPluginLoader *loader;
QTranslator *translator;
};
void PluginManager::loadPlugins()
{
QDir pluginsDir(QApplication::applicationDirPath());
#if defined(Q_OS_MAC)
if (pluginsDir.dirName() == "MacOS") {
pluginsDir.cdUp();
pluginsDir.cd("Resources");
}
#endif
if(pluginsDir.cd(kPluginDir))
{
QString s = pluginsDir.absolutePath();
QString localeName = QLocale().name();
QDir tsDir(translationsPath());
loadCoreTranslations(tsDir,localeName);
QStringList files = pluginsDir.entryList(QDir::Files);
removePluginsInfo(files);
foreach (QString file, files)
{
//qDebug() << pluginsDir.absoluteFilePath(file);
QStringList error_module;
if (QLibrary::isLibrary(file) && isPluginEnabled(file))
{
QPluginLoader *loader = new QPluginLoader(pluginsDir.absoluteFilePath(file),this);
if (loader->load())
{
IPlugin *plugin = qobject_cast<IPlugin *>(loader->instance());
if (plugin)
{
plugin->instance()->setParent(loader);
QUuid uid = plugin->pluginUuid();
if (!m_pluginItems.contains(uid))
{
PluginItem pluginItem;
pluginItem.plugin = plugin;
pluginItem.loader = loader;
pluginItem.info = new IPluginInfo;
pluginItem.translator = NULL;
QTranslator *translator = new QTranslator(loader);
QString tsFile = file.mid(LIB_PREFIX_SIZE,file.lastIndexOf('.')-LIB_PREFIX_SIZE);
if (translator->load(tsFile,tsDir.absoluteFilePath(localeName)) || translator->load(tsFile,tsDir.absoluteFilePath(localeName.left(2))))
{
qApp->installTranslator(translator);
pluginItem.translator = translator;
}
else
delete translator;
plugin->pluginInfo(pluginItem.info);
savePluginInfo(file, pluginItem.info).setAttribute("uuid", uid.toString());
m_pluginItems.insert(uid,pluginItem);
}
else
{
error_module.append(file);
qInfo() << tr("Duplicate plugin uuid") << file << loader->errorString();
savePluginError(file, tr("Duplicate plugin uuid"));
delete loader;
}
}
else
{
error_module.append(file);
qInfo() << tr("Wrong plugin interface") << file << loader->errorString();
savePluginError(file, tr("Wrong plugin interface"));
delete loader;
}
} else {
error_module.append(file);
qInfo() << tr("load error") << file << loader->errorString();
savePluginError(file, loader->errorString());
delete loader;
Q_ASSERT(false);
}
}
if (!error_module.isEmpty()) {
//BfEventTrack::GetInstance()->SendBSoftStartError(error_module);
QString title = QString::fromUtf8(" Startup error ");
QString message =
QString::fromUtf8(" Update failed ");
QMessageBox::critical(nullptr, title, message);
quit();
return;
}
}
QHash<QUuid,PluginItem>::const_iterator it = m_pluginItems.constBegin();
while (it!=m_pluginItems.constEnd())
{
QUuid puid = it.key();
if (!checkDependences(puid))
{
unloadPlugin(puid, tr("Dependences not found"));
it = m_pluginItems.constBegin();
}
else if (!checkConflicts(puid))
{
foreach(QUuid uid, getConflicts(puid)) {
unloadPlugin(uid, tr("Conflict with plugin %1").arg(puid.toString())); }
it = m_pluginItems.constBegin();
}
else
{
++it;
}
}
}
else
{
qDebug() << tr("Plugins directory not found");
quit();
}
}<2> The plug-in module uses
From what we saved before QHash<QUuid, PluginItem> m_pluginItems Compare the class name to get the required interface pointer , Then normal access to the plug-in interface
// Get a single plug-in according to the plug-in name
QList<IPlugin *> PluginManager::pluginInterface(const QString &AInterface) const
{
//QList<IPlugin *> plugins;
if (!m_plugins.contains(AInterface))
{
foreach(PluginItem pluginItem, m_pluginItems)
if (AInterface.isEmpty() || pluginItem.plugin->instance()->inherits(AInterface.toLatin1().data()))
m_plugins.insertMulti(AInterface,pluginItem.plugin);
}
return m_plugins.values(AInterface);
}
// Acquired IPlugin direct qobject_cast Turn it into an instance that needs to be used
if (!m_mainWidgetPlugin) {
IMainWidgetPlugin* m_mainWidgetPlugin = nullptr;
IPlugin* plugin = NULL;
if (m_pluginManager) {
plugin = m_pluginManager->pluginInterface("IMainWidgetPlugin").value(0, NULL);
if (plugin) {
m_mainWidgetPlugin =qobject_cast<IMainWidgetPlugin*>(plugin->instance());
//IMainWidgetPlugin It's all there , You can use the interface in the plug-in
//m_mainWidgetPlugin-> Interface
}
}
}
边栏推荐
- Iptables mask access to a port of IP
- Golang---------小试牛刀 gin框架文件上传
- 单自由度系统的随机振动计算与仿真验证
- Base64 encoding and decoding principle and C language implementation
- marginalization
- ORA-01033
- PhpMyAdmin 4.8.1 remote file contains vulnerability [gwctf 2019] I have a database
- T100接口开发步骤简介
- Dwelling apartment rental system based on jsp+servlet
- MySQL common queries
猜你喜欢
随机推荐
二叉搜索树BST
[phantom engine UE] ue5 dynamic Pak resource loading method
Feign implements inter service and passes headers when calling
【Jmeter】Jmeter 设置默认语言为中文
基于JSP+Servlet的蜗居公寓租赁系统
职场必备 | 123页华为内部项目管理PPT
T100自定义应用使用说明(azzi650)
一条龙蛇形排序(我第一道笔试题)
PHP QRCode生成二维码
Simulation volume leetcode [general] 1996 Number of weak characters in the game
PhpMyAdmin 4.8.1 remote file contains vulnerability [gwctf 2019] I have a database
Binary tree, traversal
The writing method of like% variable% in Oracle SQL
XML文件删除掉注释
One dragon and snake sort (my first test question)
ORA-01033
解道--探索术
Detailed steps for T100 to develop a new two gear program
Opencv: convert video into continuous image frames
二叉树的广度遍历








