Qt 插件学习(二)
来源:互联网 发布:qq业务站qv3源码 编辑:程序博客网 时间:2024/06/03 22:48
接前面的Qt插件学习(一),继续学习插件的 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
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() 中被使用的。
参考http://doc.qt.nokia.com/4.7/tools-echoplugin.html
http://doc.qt.nokia.com/4.7/plugins-howto.html
http://doc.qt.nokia.com/4.7/qpluginloader.html
- Qt 插件学习(二)
- Qt 插件学习
- Qt 插件学习(一)
- QT插件学习
- Qt插件学习
- <二> Qt更新sqlite3插件
- Qt Lighthouse学习(二)
- QT学习(二)
- Qt Lighthouse学习(二)
- QT学习二:工具栏
- Qt学习笔记(二)
- Qt学习小记(二)
- Qt学习笔记二
- Qt插件机制的学习
- Qt插件机制的学习
- Qt插件机制的学习
- 【Qt编程】Qt学习笔记<二>
- QT model/view 学习二
- 计算机管理本地用户和组不显示用户列表
- Qt 插件学习(一)
- 回顾蹒跚学步的我(上)
- 打印单词长度的直方图--C语言的多种实现
- 三维消隐算法
- Qt 插件学习(二)
- POJ 1228 Grandpa's Estate 【计算几何:凸包,andrew】
- Oracle常用语句
- C++ 引用的一点点猜想
- 如何给Android的apk重新签名
- 单例模式的七种实现
- Linux救援模式应用
- Qt插件机制的学习
- 数据挖掘的十大挑战