Qt 插件学习(二)
发布日期:2021-10-03 22:59:35 浏览次数:43 分类:技术文章

本文共 3640 字,大约阅读时间需要 12 分钟。

接前面的,继续学习插件的 lower level api

这次,直接写个小例子吧:

接口

程序要能感知插件,需要程序和插件共同遵守某种规则。于是定义一个共同的接口

//mathinterface.h

#include <QtCore/QtPlugin>

class MathInterface

{

public:

virtual ~MathInterface() {}

virtual int math(int v) = 0;

};

Q_DECLARE_INTERFACE(MathInterface, "com.example.Plugin.MathInterface/0.1");

这儿用到的这个宏的定义在qobject.h中:

#define Q_DECLARE_INTERFACE(IFace, IId) \

template <> inline const char *qobject_interface_iid<IFace *>() \

{ return IId; } \

template <> inline IFace *qobject_cast<IFace *>(QObject *object) \

{ return reinterpret_cast<IFace *>((object ? object->qt_metacast(IId) : 0)); } \

template <> inline IFace *qobject_cast<IFace *>(const QObject *object) \

{ return reinterpret_cast<IFace *>((object ? const_cast<QObject *>(object)->qt_metacast(IId) : 0)); }

注意,这儿用到了

qt_metacast()稍后会看到这个函数在何处被定义。

使用插件

//main.cpp

#include <QtCore>

#include "mathinterface.h"


int main(int argv, char *args[])

{

QCoreApplication app(argv, args);

QDir pluginsDir(qApp->applicationDirPath());

foreach (QString fileName, pluginsDir.entryList(QDir::Files)) {

QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));

QObject *plugin = pluginLoader.instance();

if (plugin) {

MathInterface *interface = qobject_cast<MathInterface *>(plugin);

if (interface) {

qDebug()<<interface->math(10);

}

}

}

return app.exec();

}

遍历一个路径(比如这儿的可执行程序所在目录),依次用 QPluginLoader 进行加载,如果加载成功且转换成接口指针成功,则调用接口的函数。

这儿用了一个 qobject_cast 进行类型转换。是不是很神奇:这儿转换的类型不是我们一直坚信的 QObject 或其子类。这用的是我们接口定义时的宏。

插件定义

头文件

//plugin1.h

#include <QtCore/QObject>

#include "mathinterface.h"


class Plugin1:public QObject, public MathInterface

{

Q_OBJECT

Q_INTERFACES(MathInterface)

public:

Plugin1(QObject *parent=NULL);

int math(int v);

};

cpp文件

//plugin1.cpp

#include "plugin1.h"

Plugin1::Plugin1(QObject *parent)

:QObject(parent)

{

}

int Plugin1::math(int v)

{

return 100*v;

}

Q_EXPORT_PLUGIN2(plugin1, Plugin1);

这儿出现的新的宏是:Q_INTERFACES(MathInterface)

这是个moc处理的宏,moc的结果中包含下面的代码:

void *Plugin1::qt_metacast(const char *_clname)

{

if (!_clname) return 0;

if (!strcmp(_clname, qt_meta_stringdata_Plugin1))

return static_cast<void*>(const_cast< Plugin1*>(this));

if (!strcmp(_clname, "MathInterface"))

return static_cast< MathInterface*>(const_cast< Plugin1*>(this));

if (!strcmp(_clname, "com.example.Plugin.MathInterface/0.1"))

return static_cast< MathInterface*>(const_cast< Plugin1*>(this));

return QObject::qt_metacast(_clname);

}

从这儿可以看出前面的qobject_cast是如何通过调用qt_metacast来起作用的。

pro文件

为了完整,看一下程序和插件分别对应的pro文件

  • project.pro
  • app/
    • app.pro
    • main.cpp
    • mathinterface.h
  • plugin1/
    • plugin1.pro
    • plugin1.h
    • plugin1.cpp

#app.pro

HEADERS = mathinterface.h

SOURCES = main.cpp

CONFIG += console

TARGET = main

DESTDIR = ../

#plugin1.pro

TEMPLATE = lib

CONFIG += plugin

INCLUDEPATH += ../app

HEADERS = plugin1.h

SOURCES = plugin1.cpp

DESTDIR = ../

其实Qt自带的Manual和例子讲得很清楚了,本文中不过提了一点用得到宏是如何工作的。

QPluginLoader

使用插件是通过QPluginLoader来完成的。

回想上一篇中提到 Q_EXPORT_PLUGIN2(PluginName, ClassName) 展开后的两个函数:

static const char qt_plugin_verification_data[] = \

"pattern=QT_PLUGIN_VERIFICATION_DATA\n" \

"version=4.7.0\ndebug=false\nbuildkey=xxx";


extern "C" Q_DECL_EXPORT const char * qt_plugin_query_verification_data()

{

return qt_plugin_verification_data;

}


extern "C" Q_DECL_EXPORT qt_plugin_instance()

{

static QPointer<QObject> _instance;

if (!_instance)

_instance = new ClassName;

return _instance;

}

QPluginLoader 正是借助这两个接口函数,来判断我们的插件是否有效的。看一下load的源码:

这儿的d是 QLibraryPrivate 的实例

bool QPluginLoader::load()

{

if (!d || d->fileName.isEmpty())

return false;

if (did_load)

return d->pHnd && d->instance;

if (!d->isPlugin())

return false;

did_load = true;

return d->loadPlugin();

}

两个接口函数是分别在 d->isPlugin() 和 d->loadPlugin() 中被使用的。

参考

转载地址:https://blog.csdn.net/lclflash/article/details/8856770 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Qt插件机制的学习
下一篇:Qt 插件学习(一)

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2024年04月22日 05时10分16秒