2

I have a Qt application that allows custom plugins (loaded with QPluginLoader), and these plugins can implement some interfaces, and declare with the Q_INTERFACES() macro.

If you look at Qt's documentation linked below, I'm talking about the "low-level" API: http://doc.qt.io/qt-5/plugins-howto.html

Now, this is my question: after I load a plugin with QPluginLoader, is there a way to enumerate all the interfaces it implements? Basically, is there a way to enumerate what the plugin declares in the Q_INTERFACES() macro from the main app loading the plugin?

The application currently works with both Qt4 and Qt5, but a solution that works only with Qt5 would be acceptable as well.

Daniele
  • 410
  • 7
  • 19
  • Qt definitely creates meta data for the interfaces, but I don't seem to find any way to iterate through it. – dtech Apr 25 '16 at 20:02
  • @ddriver The meta data is created in a very implicit fashion: moc generates code that lets you cast the `QObject` to an instance of the interface, iff you know the interface's name. The data is not retained in any other fashion: there's no list of interfaces anywhere :( – Kuba hasn't forgotten Monica Apr 25 '16 at 20:06
  • Well, it does have to store the actual strings for the names, since the meta system works with string literals and does runtime lookups, it is just a serious omission in the design of the meta system that this data is not structured in some more useful way. I also don't like the fact it is generated for everything, it would be better if you could specify what kind of meta data you want for a particular object. – dtech Apr 25 '16 at 20:08

1 Answers1

2

Unfortunately, Qt doesn't explicitly keep the list of interfaces :(

The best you can do is to attempt to cast the QObject * instance() returned by the plugin loader to a given interface given either using a class name or using its IID, using qt_metacast, i.e. loader.instance()->qt_metacast("IFoo"). If the result is non-zero, then the given class implements the interface.

Alternatively, you can add each interface as class info, and you can then enumerate them:

class Impl : public QObject {
  Q_OBJECT
  Q_INTERFACES(IFoo IBar)
  Q_CLASSINFO("Interface", "IFoo")
  Q_CLASSINFO("Interface", "IBar")
}

QStringList interfaces(QObject * obj) {
  QStringList result;
  auto count = obj->metaObject()->classInfoCount();
  for (int i = 0; i < count; ++i) {
    auto info = obj->metaObject()->classInfo(i);
    if (strcmp(info.name(), "Interface") == 0)
      result << QString::fromLatin1(info.value());
  }
  return result;
}

If you wish to depend on this functionality, you'd want to modify your copy of moc to generate relevant classinfo automatically from Q_INTERFACES. IIRC it's just a few lines worth of a change, I've done something like that at some point.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • If you are the one who gets to implement the plugins, you might as well put a `virtual QStringList interfaces()` in a `InterfaceInfo` interface and include that in each plugin and manually implement. – dtech Apr 25 '16 at 20:44
  • Thanks for the answer! It's too bad that Qt doesn't provide a way to enumerate interfaced. For context, my goal was to create a map from all available interfaces to all the plugin that implement them, so anybody who wants to interact with a given interface could query all the available plugins. This way, I could (among other things) implement a plugin dependency system. – Daniele Apr 26 '16 at 18:18
  • I guess, then, I have two options: either I freeze the list of available interfaces, and for each plugin, try each interface one by one and see if I can cast the plugin object to it, or I use the CLASSINFO as suggested (and yes, our team is also the one writing the plugins). I'm definitely not patching moc though, no resources to maintain that ;) – Daniele Apr 26 '16 at 18:22