Chargement...
 
Ecriture de d'un plug-in

Présentation

Introduction


Cet article explicite comment mettre en oeuvre un plugin en QT4, c'est à dire comment :

  • écrire un plugin
  • comment l'appeler


Rappelons qu'un plugin est une librairie dynamique qui va être appelée par le programme lorsqu'il aura besoin d'une fonction contenue dans cette librairie.

Nous allons bâtir un exemple le plus simple possible afin de rester didactique.
L'exemple donné fonctionne sous Linux mais son adaptation sous Windows et Mac est très simple, elle sera donnée en commentaire.

Exemple


Nous allons faire un programme qui va instancier une classe chargée :

  • de charger la librairie
  • appeler la seule et unique procédure de notre librairie (une seule c'est plus simple à comprendre)


Nous allons d'abord nous occuper de la partie chargement du plugin en faisant en sorte qu'il ne soit pas présent histoire de séparer la partie appel de l'écriture.


Réalisation

Programme main


main.cpp contient :

#include <QCoreApplication>
#include "callplugin.h"
#include "interface.h"

int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
qDebug("Call Plugin ? ");
callplugin plugin;
plugin.callslideshow();
return 0;
}

  • Nous activons les message par un qDebug("call plugin ?") qui va afficher à l'écran Call plugin ? suivi de yes ou de no en fonction du bon déroulement des choses. Mais pour le moment on pose juste la question.

  • la classe callplugin est définie dans callplugin.h et elle est instanciée par l'objet plugin

  • dans la classe callplugin une méthode callslideshow() est appelée.


Regardons ce que contient la classe callplugin en mettant de côté pour le moment la ligne #include "interface.h" qui est la plus importante.

Notons au passage que pour l'instant rien de ce qui a été exposé ne concerne la mise en oeuvre de plug-in et tout cela ne devrait dont pas poser de problème de compréhension.

Classe d'appel du plug-In

Regardons la définition du header

#ifndef CALLPLUGIN_H
#define CALLPLUGIN_H
#include "interface.h"

class callplugin
{
public:
callplugin();
~callplugin() ;
bool loadplugin();
void callslideshow();
private:
Interface *interface;
};
#endif

  • passons sous silence les #define et autre directives qui sont classiques dans les définitions de header
  • on voit que la classe callplugin comprend un constructeur callplugin, un destucteur, la méthode de chargement de plugin et la procedure d'appel de la procédure "distante".
  • la varable pointant sur Interface est déclarée

Le code de la classe

#include <QtCore>
#include <QPluginLoader>
#include "callplugin.h"

callplugin::callplugin() {
if ( !loadplugin() )
qDebug( "No ! Could not load any plugin");
else
qDebug ("Yes !");
}

callplugin::~callplugin() {
}

void callplugin::callslideshow(){
qDebug(qPrintable(interface->slideshow()));
}

bool callplugin::loadplugin()
{
QDir pluginsDir(qApp->applicationDirPath());
pluginsDir.cd("plugins");
foreach (QString fileName, pluginsDir.entryList(QDir::Files)) {
QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
QObject *plugin = pluginLoader.instance();
if (plugin) {
interface = qobject_cast<Interface *>(plugin);
if (interface) return true;
}
}
return false;
}

  • le constructeur va essaye de charger les plugins et afficher yes ou no.
  • la péthode de chargement du plugin loadplugin est un peu sofistiquée car elle va essayer de charger tout ce qui se présente dans le répertoire plugins, par contre elle ne prend pas en compte les répertoire windows ou MacoSX et suppose que les plugins sont sous le répertoire plugins au niveau de l'éxecutable
  • on voit que le pointeur interface dont nous n'avons pas encore vu la définition est est casté sur l'objet plugin.
  • c'est ce même pointeur qui est appelé par interface->slideshow() dans la méthode callplugin.


Regardons à quoi ressemble la définition de l'interface.

Interface d'appel

#ifndef ECHOINTERFACE_H
#define ECHOINTERFACE_H
#include <QString>
class Interface
{
public:
virtual ~Interface() {}
virtual QString slideshow() = 0;
};
QT_BEGIN_NAMESPACE
Q_DECLARE_INTERFACE(Interface,
"com.trolltech.Plugin.EchoInterface/1.0");
QT_END_NAMESPACE
#endif

  • la classe interface comprend le destructeur et l'appel de la function qui retrourne un qString. Ces deux déclarations sont précédées du mot virtuel car elles sont déclarées dans le plugin.

  • Ensuite les primitives doivent figurer telles quelles.

Le fichier pro de l'appel

SOURCES += main.cpp \
callplugin.cpp
TEMPLATE = app
CONFIG += warn_on \
thread \
qt
TARGET = slideshow
DESTDIR = ../bin
QT -= gui
HEADERS += interface.h \
callplugin.h


Apres compilation via qmake vous devez avoir un problème d'appel avec le message no mais vous devez pouvoir lancer la première partie.
Construisons maintenant le plug in .

Fabrication du plugin


Dans un autre répertoire il faut définir trois fichiers :

#ifndef SLIDESHOW_H
#define SLIDESHOW_H
#include <QObject>
#include "../src/callplugin.h"
#include "../src/interface.h"

class Slideshow : public QObject, Interface
{
Q_OBJECT
Q_INTERFACES(Interface)

public:
QString slideshow();
} ;
#endif

  • on voit que les chemins de callplugin.h et de interface.h ont été placés pour récupérer les informations contenues dans ces deux fichiers
  • la méthode slideshow va enfin être définie

Code de la classe Slideshow

#include <QtGui>
#include "slideshow.h"
#include "../src/callplugin.h"
#include "../src/interface.h"
QString Slideshow::slideshow()
{
return "coucou";
}
Q_EXPORT_PLUGIN2(callplugin, Slideshow);

le fichier pro

TEMPLATE = lib
SOURCES += slideshow.cpp
HEADERS += slideshow.h


Une fois le qmake et le make fait vous devez mettre la librairie resultante dans le répertoire plugins/ qui lui même se trouve au niveau de l'exécutable et tout doit fonctionner



Changer de langue

Anglais (English, en)Français (fr)

Recherche