Seite 1 von 1

Plugin in Qt programmieren

Verfasst: 11. Februar 2010 10:55
von anno1988
Hallo zusammen,

es gibt ja diese Anleitung wie man in Qt Plugins programmieren kann.

Allerdings will ich nur ein Konsolenprogramm schreiben, in dem ich Plugins verwenden will.

Jetzt habe ich noch nie Plugins programmiert bzw. diese in ein Programm eingebunden. So weit ich gesehen habe sind diese Plugins vornehmlich für eine GUI vorgesehen.

Wie würdet ihr es machen, in ein Konsolenprogramm plugins zu programmieren?

gruß anno1988

Verfasst: 11. Februar 2010 11:11
von MichaelS
Moin,

ich habe es zwar noch nicht getestet, da Dich aber niemand zwingt, in Deinem Plugin GUI-Elemente zu verwenden, sollte es problemlos möglich sein, Plugins auch in Konsolenanwendungen zu verwenden.

Gruß Michael

Verfasst: 11. Februar 2010 11:36
von RHBaum
So weit ich gesehen habe sind diese Plugins vornehmlich für eine GUI vorgesehen.
Kann man so ned verallgemeinern.
Der groesste Teil meiner Plugins, die ich schreiben durfte, vermeiden es strikt eine (eigene) GUI zu haben.
Die daten die die teile brauchen, lassen sie sich durch mehr oder weniger Abstrakte generische Optionsmethoden geben.

Hat den Vorteil das das Anwenderprogramm die GUI zum konfigurieren oder aehnlichen bauen muss. Dann sieht alles wenigstens gleich aus.
Und wenn man keine grafische methode zum konfigurieren will, laessts man eben einfach durch ini files von der App her einstellen.

wichtig beim arbeiten mit Plugins, die schnittstellen soweit wie geht frei von binaeren abhaengigkeiten halten.
Die hohe schule und damit das unkomplizierteste sind reine C Schnittstellen ! Finden aber C++ Programmierer tendentiell eher doof ! ^^
Was ueberhaupt ned geht, sind klassendefinitionen mit Implementierungen rueberschicken, sowie templates soweiso.
Betrifft so klassen wie QString, und erst recht std::string.

Nen guter kompromiss ist reine Protokollklassen zu verwenden. Also 100% abstrakte klassen. Das einzig binaere was dann zu problemen fuehren kann sind die vtable, und die Namen der Symbole die generiert werden. Zum glueck ist das oft bei c++ compileren ueber mehrere versionen hinweg eindeutig, aber leider nicht gleich zwischen unterschiedlichen compilern. Nen gcc wirst da nie mit nem VS zum kooperieren kriegen .... Unter linux eh ned so das problem, da dort nen systemkompiler hasst.

Ich wuerde Dir aber noch folgendes empfehlen :
Programme (Plugins) ohne GUI ? warum dann die QT ???
OK, die qt bringt paar annehmlichkeiten im bereich stringverarbeitung und Kommunikation (sockets).
Aber der riesen nachteil der QT:
iss sie dynamisch gelinkt, laeufst du in "versionsprobleme" früher oder spaeter. Lauft deine App und dein Plugin unter unterschiedlichen QT versionen, kann sich das beissen, und zwar boese.
Auch wenn du keine QT Klassen exportiert hasst ...
Besser ist dann, die QT statisch zu linken. Das funktioniert soweit ganz gut, er baut halt nur ab und ann 2 unnerschiedliche qApp (benutzen irgendwie Globale variablen die mit versionsnamen genereirt werden) instanzen, das muss man im hinterkopf behalten, aber prinzipiell funktioniert das.
Nur werden plugins mit der statischen qt recht fett ^^
Und es gibt andere libs fuer das begrenzte einsatzgebiet, am besten sind da eh headerimplementierungen, ala stl, boost, etc ...

Vieles sind aber eher windows-probleme, *nixe iss da wesentlich robuster weil immer selber compiler und version :-)

Ciao ...

Verfasst: 11. Februar 2010 22:27
von anno1988
ja das stimmt schon, die plugins von qt sind vielleicht wirklich nicht das richtige.

allerdings habe ich keine vorstellung davon wie ich so eine pluginstruktur in c++ aufbauen soll, so dass mein programm diese auch ladet und sie dann auch benutzt usw...

gut wäre es, wenn es irgendwo ein tutorial gäbe, das mir das ganze mal zeigt.

ich habe allerdings noch nichts über dieses thema gefunden.

ist wahrscheinlich einfach zu speziell.

Verfasst: 12. Februar 2010 11:05
von RHBaum
Naja, gibt mehrere Stufen von Pluginkonzepten.

Die einfachste iss die rohe aber optinale Dll. iss sie vorhanden, wird ne funktion freigeschalten, wenn nicht, funktioniert der Rest der applikation trotzdem noch.

Nen vollstaendiges Plugin geht natuerlich weiter. besteht aus 2 teilen. nen statischer Manager für die Applikation selbst, der die eigentlichen plugins verwaltet, und die Plugins selbst.


Wir nutzen hier das konzept der Pluginfactory. Das heist, jedes Plugin hat seine eigene Pluginfactory. diese Factory haelt (verwaltungsdaten)daten über das plugin und kann es halt erzeugen. Weiterhin bestimmt die Factory ob ein plugin pro prozess multiinstanziable iss oder nicht (singleton)

Funktionieren tut das folgendermassen.

Es gibt eine IPluginFactory Schnittstelle. diese enthaelt die daten über das Plugin sowei den "Typ" bzw die Schnittstellen, die das Plugin unterstuetzt. weiterhin noch author ne beschreibung etc.
jede PluginDll kann ein oder mehrere Pluginfactories haben.
die dll selber hat genau 2 exportierte funktionen, size_t getPluginFactoryCount() und IPluginFactory * getPluginFactory(size_t index)

So checkt der PluginManager, ob die dll nen plugin ist, in dem er mit getProcAdress("getPluginFactory") und getProcAdress("getPluginFactoryCount") gueltige funktionspointer fuer die funktionen bekommt. Wenn nicht, iss die dll fuer ihn kein plugin.

Die Factories selber sind quasi "global" in der Dll, werden damit sofort beim erzeugen angelegt. Da die factories nur meta informationen enthalten, werden die auch flott erzeugt. Wichtig iss halt nur, das die pluginfactory allein schon alle daten haelt, die die Application braucht um entscheiden zu koennen ob sie ein plugin nutzen kann / muss oder nicht.
Nichts iss schlimmer als wenn man im vorhinaus das Plugin erzeugen muss um an daten zu kommen, und die App dann anhand der Daten entscheidet neee, brauch ich doch ned, ich entlad das mal wieder.

Die Pluginfactory erzeugt dann die Plugins selber.
Die Plugins sind alle von IPlugin abgeleitet. Damit hat man ein haendle zum verwalten aller plugins. Jede factory kann damit Ihr (und damit nur einen typ) erzeugen.
Sieht bei uns so aus:
IPlugin * IPluginFacotory::createPlugin()
Weiterhin unterscheidet die factory, ob sie ein neues plugin erzeugt, oder nen zeiger (referenzgezaehlt) auf ein scho vorhandenes Plugin rausgibt.
Zu jedem creaete gehoert dann natuerlich das zugehoerige void IPluginFacotory::releasePlugin(IPlugin * P)

das Plugin selber kann ned viel.
Wichtig: die eigentlichen typisierten arbeitsschnittstellen der Plugins sind nicht von IPlugin abgeleitet. Und ein plugin kann mehrere (nicht miteinander verwandte) schnittstellen unetrstuetzen.
Beispielsweisse wenn man ein Plugin fuer einen Converter hat, die Schnittstelle dazu IConvert ist, kommt man bei uns ueber eine "cast" methode drauf. das cast iss syntaktisch schlecht gewaehlt, besser sollte es "queryInterface" heissen. aber dinge sind halt gewachsen.

die Signatur ist:
void * IPlugin::cast(const char * InterfaceName, unsigned int InterfaceVersion);

jedes Interface bekommt bei uns 2 statische memberfunktionen, die den namen des interfaces rausruecken sowie die Verion der schnittstelle,

sieht quasi ungefaehr so aus:

Code: Alles auswählen

const char * const ICONVERT_INTERFACENAME =  "IConvert";
const unsigend int ICONVERT_INTERFACEVERSION = 0x00010012;

class IConvert
{
public: 
    static const char * InterfaceName() {return ICONVERT_INTERFACENAME;}
    static unsigned int InterfaceVersion() {return ICONVERT_INTERFACEVERSION;}
    /// .... 
   /// hier dann die abstrakten funktionen die das interface so braucht. 
}
damit laesst sich das cast recht bequem aufrufen:

Code: Alles auswählen

IConvert * pConverter = reinterpret_cast<IConvert *>(pPlugin->cast(IConvert::InterfaceName(),IConvert::InterfaceVersion())); 
Das wiederum laesst sich super templatisieren ^^


Der PluginManager selber iss ne lib die man in ne application einbindet. dem gibt man ein oder mehrere verzeichnisse, daraus laed er sich alle plugins und baut ne interface / type map auf.
den Manager fragt man dann nach allen PluginFactories fuer eine bestimmte schnittstelle oder einen bestimmten typ und natuerlich Version ab ... und die app laesst dann den user entscheiden, welches plugin verwendet wird, falls notwendig.

oder es ist ein mechanismuss dahinter, der selber das beste plugin rausfindet (bei dateiconverter z.b. probt er durch).

Wird das plugin dann gebraucht, wird es erst dann aus dern factory erzeugt.

So machen wir es, wobei wir ziemlich extensiv plugins auf c++ basis verwenden.
vielleicht hilft dir das ...
gibt auch andere techniken ... com basiert z.b.

Ciao ...