Problem with plugin signals/slots
I am developing under Windows and I have a Qt plugin project that produces a dll, and I have another app that can load that dll dynamically as a plugin via the usual Qt methods. Basically what I wanted to do was have the plugin report its status back to this app that's using it (i.e. the plugin emits a signal, the app receives it via a slot). So after I successfully detect and read in the plugin (i.e. the dll file), I do the usual connect call to set up the signal/slot (which returns true), but the connection doesn't seem to actually be working, as my slot code never gets executed in the app. I tried to strip down the pertinent code below.
UpgradeInterface.h (this is the interface a plugin extends):
Code:
class UpgradeInterface
: public QObject{
public:
virtual ~UpgradeInterface() {}
virtual bool performUpgrade() = 0;
signals:
void statusUpdate
(QString statusMsg
);
};
Q_DECLARE_INTERFACE(UpgradeInterface, "com.UpgradeInterface/1.0")
//----------------------------------------------------------
UpgradePlugin.h:
Code:
class UpgradePlugin
: public QObject,
public UpgradeInterface
{
Q_OBJECT
Q_INTERFACES(UpgradeInterface)
public:
bool performUpgrade();
signals:
void statusUpdate
(QString statusMsg
);
};
//----------------------------------------------------
UpgradePlugin.cpp:
Code:
bool UpgradePlugin::performUpgrade()
{
emit statusUpdate("Upgrade started!");
return true;
}
Q_EXPORT_PLUGIN2(UpgradePlugin, UpgradePlugin)
//-------------------------------------------------
The following is part of the app code that detects/loads the plugin.
MyDialog.h:
Code:
{
Q_OBJECT
//...
//...
protected slots:
void statusUpdateFromUpgradePlugin
(QString statusMsg
);
};
//------------------------------------------------------
MyDialog.cpp:
Code:
void MyDialog
::loadPlugins(QDir dir
) {
// Load dynamic plugins
{
QObject *plugin
= loader.
instance();
if (plugin)
{
UpgradeInterface * iUpgrade = qobject_cast<UpgradeInterface *>(plugin);
if (iUpgrade)
{
bool success
= connect(iUpgrade,
SIGNAL(statusUpdate
(QString)),
this,
SLOT(statusUpdateFromUpgradePlugin
(QString)));
// returns true iUpgrade->performUpgrade();
}
}
}
}
void MyDialog
::statusUpdateFromUpgradePlugin(QString statusMsg
) {
cout << statusMsg; // Never gets here!
}
Re: Problem with plugin signals/slots
AFAIK your code won't compile because for me code like this:
result in this:
Quote:
error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'QString' (or there is no acceptable conversion)
so I don't know how do you achieved compilation, but you can tell me how to do it :]
next thing is that maybe you forgot CONFIG += console or sth. Try using:
Code:
#include <QDebug>
...
qDebug() << statusMsg;
except for that everything should work in your code in my opinion
Re: Problem with plugin signals/slots
I don't actually have the "cout" statement in my code... it was there just as a generic line of code. So my code does actually compile :). Put anything you want there... the point I was trying to illustrate is that it simply doesn't ever get there. I put break points, try to pop up message dialogs, etc. so I know it does not actually execute... thx.
Re: Problem with plugin signals/slots
Hi,
try to add Q_OBJECT to the UpgradeInterface declaration. It works written in that way in my code, I hope it will help you.
have a nice day
Re: Problem with plugin signals/slots
ok, I've done some research and I think, like my preposter, that you should add Q_OBJECT macro in interface declaration, and you should not redefine signal in implementation, just emit it.
Re: Problem with plugin signals/slots
Hmm when I add Q_OBJECT, now when I compile my UpgradePlugin project, I get:
Error 3 error LNK2001: unresolved external symbol "public: virtual struct QMetaObject const * __thiscall UpgradeInterface::metaObject(void)const " (?metaObject@UpgradeInterface@@UBEPBUQMetaObject@@ XZ) UpgradePlugin.obj UpgradePlugin
Error 4 error LNK2001: unresolved external symbol "public: virtual void * __thiscall UpgradeInterface::qt_metacast(char const *)" (?qt_metacast@UpgradeInterface@@UAEPAXPBD@Z) UpgradePlugin.obj UpgradePlugin
Error 5 error LNK2001: unresolved external symbol "public: virtual int __thiscall UpgradeInterface::qt_metacall(enum QMetaObject::Call,int,void * *)" (?qt_metacall@UpgradeInterface@@UAEHW4Call@QMetaOb ject@@HPAPAX@Z) UpgradePlugin.obj UpgradePlugin
Error 6 fatal error LNK1120: 3 unresolved externals ..\UpgradePlugin.dll UpgradePlugin
Re: Problem with plugin signals/slots
Hmm when I call emit from the class that implements UpgradeInterface (UpgradePlugin), no luck :(. Keep in mind UpgradePlugin is its own separate project (and produces a dll) and references the same UpgradeInterface.h file as the app (exe) project does... not that that helps, just reiterating...
Error 3 error LNK2019: unresolved external symbol "protected: void __thiscall UpgradeInterface::statusUpdate(class QString)" (?statusUpdate@UpgradeInterface@@IAEXVQString@@@Z) referenced in function "public: virtual bool __thiscall UpgradePlugin::performUpgrade(void)" (?performUpgrade@UpgradePlugin@@UAE_NXZ) UpgradePlugin.obj UpgradePlugin
Error 4 error LNK2001: unresolved external symbol "public: virtual struct QMetaObject const * __thiscall UpgradeInterface::metaObject(void)const " (?metaObject@UpgradeInterface@@UBEPBUQMetaObject@@ XZ) UpgradePlugin.obj UpgradePlugin
Error 5 error LNK2001: unresolved external symbol "public: virtual void * __thiscall UpgradeInterface::qt_metacast(char const *)" (?qt_metacast@UpgradeInterface@@UAEPAXPBD@Z) UpgradePlugin.obj UpgradePlugin
Error 6 error LNK2001: unresolved external symbol "public: virtual int __thiscall UpgradeInterface::qt_metacall(enum QMetaObject::Call,int,void * *)" (?qt_metacall@UpgradeInterface@@UAEHW4Call@QMetaOb ject@@HPAPAX@Z) UpgradePlugin.obj UpgradePlugin
Error 7 fatal error LNK1120: 4 unresolved externals ..\UpgradePlugin.dll UpgradePlugin
Re: Problem with plugin signals/slots
nmake clean + qmake again :]
this works for me:
interface.h:
Code:
#ifndef INTERFACE_H
#define INTERFACE_H
#include <QtPlugin>
class PluginInterface
: public QObject{
Q_OBJECT
public:
virtual void someMethod() = 0;
signals:
void someSignal();
};
Q_DECLARE_INTERFACE(PluginInterface, "pl.faldzip.PluginInterface")
#endif // INTERFACE_H
myplugin.h:
Code:
#ifndef MYPLUGIN_H
#define MYPLUGIN_H
#include "plugin1_global.h"
#include "interface.h"
class MyPlugin : public PluginInterface
{
Q_OBJECT
Q_INTERFACES(PluginInterface)
public:
void someMethod();
};
#endif // MYPLUGIN_H
myplugin.cpp:
Code:
#include "myplugin.h"
MyPlugin
::MyPlugin(QObject *parent
) : PluginInterface(parent)
{
}
void MyPlugin::someMethod()
{
emit someSignal();
}
Q_EXPORT_PLUGIN2(myplugin, MyPlugin);
and this was one project (with pro file containing TEMPLATE = lib and CONFIG += plugin),
and second project - app project:
main.cpp:
Code:
#include <QtGui>
#include <QtCore>
#include <QtPlugin>
#include "interface.h"
{
Q_OBJECT
public:
SomeClass
(PluginInterface
*pi,
QObject *parent
= 0) : QObject(parent
), m_pi
(pi
) { connect(m_pi,
SIGNAL(someSignal
()),
SLOT(someSlot2
()));
}public slots:
void someSlot() { m_pi->someMethod(); }
void someSlot2() { qDebug("someSlot2"); }
private:
PluginInterface *m_pi;
};
int main(int argc, char *argv[])
{
PluginInterface *pi = qobject_cast<PluginInterface *>(obj);
if (!pi)
{
qDebug("plugin error");
return 1;
}
SomeClass sc(pi, &pb);
pb.connect(&pb, SIGNAL(clicked()), &sc, SLOT(someSlot()));
pb.show();
return a.exec();
}
#include "main.moc"
so it shows a button, and when I click on it, it's callingSomeClass::someSlot() which is calling PluginInterface::someMethod(), whis is emitting someSignal() connected to someSlot2() so the "someSlot2" appears on the screen.
Re: Problem with plugin signals/slots
Thanks for the help... finally got it!
One problem was the Q_OBJECT thing... but after adding that I got some link errors, as I mentioned. Basically I reorganized my projects so that the UpgradeInterface was in its own separate project (lib), and I had the plugin project and app project both reference that project. Works :)