Q_DECLARE_INTERFACE(InterfaceClassName, InterfaceId)
This macro associate the given InterfaceId to the interface class called InterfaceClassName.The macro is normally used right after the interface definition:
| class MyInterface {};
Q_DECLARE_INTERFACE(MyInterface, "me.debao.qt.myinterface")
|
Q_DECLARE_INTERFACE is a macro that defines helper function that make qobject_cast(QObject *object) return a IFace pointer.
| # 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)); }
|
InterfaceId is used in the function QObject::qt_metacast(InterfaceId)
. But, how does this function work?
Q_INTERFACES(...)
This macro tells Qt which interfaces the class implements.
| class PluginObject : public QObject, public MyInterface
{
Q_OBJECT
Q_INTERFACES(MyInterface)
public:
...
};
|
When moc find Q_INTERFACES, it will generate a function called qt_metacast()
| void *PluginObject::qt_metacast(const char *iname)
{
if (strcmp(iname, "PluginObject")==0) return this;
if (strcmp(iname, "MyInterface")==0) return static_cast<MyInterface *>(this);
if (strcmp(iname, "me.debao.qt.myinterface")==0) return static_cast<MyInterface *>(this);
//...
}
|
This macro is being used to declare meta data which will be part of plugin. Then these data can be obtained without load the plugin.
NOTE: The plugin IID has nothing todo with the INTERFACES IID.
| class PluginObject : public QObject, public MyInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "me.dabao.qt.myplugin" FILE "abc.json")
Q_INTERFACES(MyInterface)
public:
...
};
|
When moc encounter the macro, it will generate char array to store the meta data(IID string, FILE contents and other infomation such as QTVERSION) and a macro to export the plugin.
| static const unsigned char qt_pluginMetaData[] = {
'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', ' ',
0x71, 0x62, 0x6a, 0x73, 0x01, 0x00, 0x00, 0x00,
0xe0, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
0xcc, 0x00, 0x00, 0x00, 0x1b, 0x03, 0x00, 0x00,
//...
};
QT_MOC_EXPORT_PLUGIN(EchoPlugin, EchoPlugin)
|
In macro QT_MOC_EXPORT_PLUGIN, two C functions get exported.
1
2
3
4
5
6
7
8
9
10
11
12
13 | #define Q_PLUGIN_INSTANCE(IMPLEMENTATION) \
{ \
static QT_PREPEND_NAMESPACE(QPointer)<QT_PREPEND_NAMESPACE(QObject)> _instance; \
if (!_instance) \
_instance = new IMPLEMENTATION; \
return _instance; \
}
# define QT_MOC_EXPORT_PLUGIN(PLUGINCLASS, PLUGINCLASSNAME) \
Q_EXTERN_C Q_DECL_EXPORT \
const char *qt_plugin_query_metadata() \
{ return (const char *)qt_pluginMetaData; } \
Q_EXTERN_C Q_DECL_EXPORT QT_PREPEND_NAMESPACE(QObject) *qt_plugin_instance() \
Q_PLUGIN_INSTANCE(PLUGINCLASS)
|
Magic in moc
All the magic of this macro can be found in the source code of moc:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 | void Generator::generatePluginMetaData()
{
if (cdef->pluginData.iid.isEmpty())
return;
// Write plugin meta data #ifdefed QT_NO_DEBUG with debug=false,
// true, respectively.
QJsonObject data;
const QString debugKey = QStringLiteral("debug");
data.insert(QStringLiteral("IID"), QLatin1String(cdef->pluginData.iid.constData()));
data.insert(QStringLiteral("className"), QLatin1String(cdef->classname.constData()));
data.insert(QStringLiteral("version"), (int)QT_VERSION);
data.insert(debugKey, QJsonValue(false));
data.insert(QStringLiteral("MetaData"), cdef->pluginData.metaData.object());
fputs("\nQT_PLUGIN_METADATA_SECTION const uint qt_section_alignment_dummy = 42;\n\n"
"#ifdef QT_NO_DEBUG\n", out);
writePluginMetaData(out, data);
fputs("\n#else // QT_NO_DEBUG\n", out);
data.remove(debugKey);
data.insert(debugKey, QJsonValue(true));
writePluginMetaData(out, data);
fputs("#endif // QT_NO_DEBUG\n\n", out);
// 'Use' all namespaces.
int pos = cdef->qualified.indexOf("::");
for ( ; pos != -1 ; pos = cdef->qualified.indexOf("::", pos + 2) )
fprintf(out, "using namespace %s;\n", cdef->qualified.left(pos).constData());
fprintf(out, "QT_MOC_EXPORT_PLUGIN(%s, %s)\n\n",
cdef->qualified.constData(), cdef->classname.constData());
}
|
All the data can be retrieved through QPluginLoader before we really load the library.
| QJsonObject QPluginLoader::metaData() const
|
For example:
| QPluginLoader pluginLoader(fileName);
QString iid = pluginLoader.metaData().value("IID").toString();
if (iid == "my_plugin_iid") {
pluginLoader.load();
//...
}
|
Reference
- http://qt-project.org/wiki/QtPlugins