Polymorphes QWidget über dll

Alles rund um die Programmierung mit Qt
nuke160
Beiträge: 22
Registriert: 3. August 2009 11:24

Polymorphes QWidget über dll

Beitrag von nuke160 »

Hallo,

ich versuche gerade, eine polymorphe Klasse zu erstellen. Ist auch kein Problem, funktioniert soweit einwandfrei. Wenn ich untenstehenden Code so in eine Headerdatei einfüge, funktioniert alles. Jetzt möchte ich jedoch die untere Klasse testNode in ein separates Projekt (dynamische Bibliothek) einfügen. Uns sobald ich das tue, kommen bei mir linker fehler:

Code: Alles auswählen

moc_linnodes.obj : error LNK2001: Nicht aufgelöstes externes Symbol ""public: static struct QMetaObject const linNode::staticMetaObject" (?staticMetaObject@linNode@@2UQMetaObject@@B)".

Code: Alles auswählen

class linNode : public QWidget
{
   Q_OBJECT
public:
   linNode(QWidget* parent = 0, Qt::WindowFlags f = 0);
   virtual const bool isInit() = 0;
public slots:
   virtual void testslot() = 0;
};

class testNode : public linNode
{
   Q_OBJECT
public:
   testNode(QWidget* parent = 0, Qt::WindowFlags f = 0);
   const bool isInit();
public slots:
   void testslot();
};
Leider weiss ich überhaupt nicht wo ich zu suchen habe, bin dankbar für jeden Hinweis...
Achja, ich verwende Visual Studio 2005 mit Qt integration, falls das relevant ist.
Und bevor ich Schelte bekomm, dies sei kein Qt Problem, sobald das Q_OBJECT und natürlich die slots aus den Klassen raus sind, funktionierts.
Zuletzt geändert von nuke160 am 25. August 2009 12:18, insgesamt 1-mal geändert.
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

moc wird nicht ausgeführt bzw. das erzeugte moc-file wird nicht kompiliert.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Jetzt möchte ich jedoch die untere Klasse testNode in ein separates Projekt (dynamische Bibliothek) einfügen
testNode ist von linNode abgeleitet
Das heisst, wenn deine Dll Objecte vom typ testNode erstellen und exportieren soll / muss, braucht es aus den code um linNode zu erstellen. (abgeleitet heisst, es nutzt als parent ein object vom typ der abgeleiteten klasse).
das heisst, deine dll braucht den code von linNode ! zum compile/linkzeitpunkt.
Sprich du musst der dll also auch lineNode geben, entweder als cpp Datei im dll project, oder als gelinkter code aus ner statischen biblothek (.lib beim VS)
wo erzeugst du denn die instanz von testNode ? ich hoffe du bist in ner exportierten funktion von der dll ?

Ansonsten siehe Christian, aber das sollt der VS schoen von alleine machen, eigentlich ^^

Ciao ....
Zuletzt geändert von RHBaum am 25. August 2009 12:30, insgesamt 1-mal geändert.
nuke160
Beiträge: 22
Registriert: 3. August 2009 11:24

Beitrag von nuke160 »

Danke, jetzt weiss ich wo ich suchen muss, auch wenn ich keine Ahnung hab wie das Problem zu beheben ist...
Ich dachte es reicht, wenn ich die Headerdatei, wo ja linNode deklariert ist, includiere.

Gruß
nuke160
nuke160
Beiträge: 22
Registriert: 3. August 2009 11:24

Beitrag von nuke160 »

Die Instanz von testNode wird in der Library erstellt,
es gibt dort zwei export Funktionen, einmal createNode und releaseNode.

Witzig ist, dass ohne Q_OBJECT alles ohne weiteres funktioniert, nur sobald ich slots und signals verwende, gehts nimma.

Gruß
nuke160
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Neee, aber sollt eigentlich logisch sein.
Nen Object muss da(in der uebersetzungseiheit) der code liegen, wo es instanziiert wird.
richtig exportieren kannst du nur funktionspointer (funtionseinsprungpunkte ) zeiger und PODS /Structs keinen Code !!!

wenn du deinen TestNode in der dll voll auskodiert hasst, ist es intern auch ned trivial, die new und delete funktionen fuer die klassen zu exportieren (das delete ruft die Qt meist selbst auf, da kannst meist nix selber zwischenhaengen, oder nur mit viel aufwand) .

die qt-dll projecte machen das aber fuer dich gleich, wenn du ne qt lib erstellst.
aber du kannst die dll dann ned selber binden und anziehen, sondern musst das immer ueber die mitgenerierte exportlib machen.
Also ne dll bauen die QObjecte exportiert, und einfach nur deren header nehmen und in der exe bekanntmachen, dann die dll selber dynamisch anziehen mit nem loadlibrary .... hat bei mir nie funktioniert ^^
ich brauchte immer die exportlibs ....

Ciao ...
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Warum wbrauchst du die klassen eigenlich in ner dll ?
warum ned in ner Lib ?

Ciao....
nuke160
Beiträge: 22
Registriert: 3. August 2009 11:24

Beitrag von nuke160 »

Tut mir leid, versteh ich wirklich nicht.
Was soll daran nicht funktionieren?

Code: Alles auswählen

   
extern "C" LINNODES_EXPORT linNode* createNode(QString nodeName)
   {
      linNode* node = 0;
      if(nodeName == "testNode")
      {
         node = new testNode;
      }
      return node;
   }
Oder meinst du etwas völlig anderes, was meinst du zum Beispiel mit anziehen?
nuke160
Beiträge: 22
Registriert: 3. August 2009 11:24

Beitrag von nuke160 »

RHBaum hat geschrieben:Warum wbrauchst du die klassen eigenlich in ner dll ?
warum ned in ner Lib ?.
Damit das Hauptprojekt nicht neu kompiliert werden muss, falls mal neue Knoten hinzugefügt werden.
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

Code: Alles auswählen

moc_linnodes.obj : error LNK2001: Nicht aufgelöstes externes Symbol ""public: static struct QMetaObject const linNode::staticMetaObject" (?staticMetaObject@linNode@@2UQMetaObject@@B)". 
hast du evt. die Header der DLL in der Profile des Hauptptojektes (also der Applikation) eingetragen (bei den HEADERS)? Das waere natuerlich falsch... (moc muss ja nur im Projekt der Library ausgefuehrt werden, nicht auch bei der Applikation).
nuke160
Beiträge: 22
Registriert: 3. August 2009 11:24

Beitrag von nuke160 »

solarix hat geschrieben: hast du evt. die Header der DLL in der Profile des Hauptptojektes (also der Applikation) eingetragen (bei den HEADERS)? Das waere natuerlich falsch... (moc muss ja nur im Projekt der Library ausgefuehrt werden, nicht auch bei der Applikation).
Gute idee, aber nein, habe ich leider nicht, mein Hauptprojekt weiss nichts von der Library.
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Oder meinst du etwas völlig anderes, was meinst du zum Beispiel mit anziehen?
anziehen == instantieiren

neee iss scho richtig wie du es machst ....
was ich meine, ist du darfst dann so den autodelete mechanismus nicht von der qt nutzen ... also sprich mit
new testNode(QObject *) instanzieiren, und das loeschen der qt ueberlassen .... weil die loescht aus deiner exe raus.
wichtig ist noch, unabhaengig von der qt: new und delete muessen immer in der selben uebersetzungseinheit erfolgen. also new in der dll und delete aus der exe raus gibt dir undefiniertes verhalten
Damit das Hauptprojekt nicht neu kompiliert werden muss, falls mal neue Knoten hinzugefügt werden.
Das ist ein gutes Motiv fuer eine dll ....
Aber muessen deine Knoten unbeding qt objecte sein ? bringt dir signal / slot mechanismus so viel ?
und noch was .... fuer signal / slots (intern sind das events) brauchst du die oder eine Instanz von QApplication in der dll !!!!
willst du events über die dll drueber hinaus feuern, muss die dll die qApp von deiner exe kennen !

deswegen, wenn ich plugins schreibe, mach ich fast alles aussschliesslich ueber interfaces. Also meine exportierten Klassen sind fast immer nur reine abstrakte klassen.

Probleme wenn du klassen ueber die dll schnittstelle schickst, muessen alle signatueren 100% uebereinstimmen. bei abstrakten methoden iss das recht gegeben. der vorteil bei rein abstrakten klassen ist, dass die definition der methoden allein schon durch die polymorphie weiterdeligiert wird, und zwar in deine dll hinein. von ner abstrakten klasse musst, bzw darfst du ueberhaupt keinen code kennen ^^

Aber exportier mal z.b. nen std::string. sieht aufn ersten blick easy aus. du linkst aber dann die dll und die exe mit der c++ runtime. und die wissen beide genau wie der std::string aufgebaut ist, um damit zu arbeiten. solange das 100% uebereinstimmt, iss das kein problem .... ansosnten kommts zum supergau :-)

wie koennen nu unterschiede in der binaerdefinitionen (signaturen) entstehen ???
ohja, da gibts viele fallstricke.
compilerflags !!! es gibt flags die beeinflussen die ausrichtung der variablen am speicher. benutzt deine dll andere flags (die das beeinflussen) als deine exe ... knallts da gewaltig.

unterschidliche versionen der bibliotheken, wenn die zugelinkt werden.

benutz mal ne dll die mit ner multithreaded runtime uebersetzt wird, und link die zu ner exe die mit singlethread uebersetzt wurde. wenn dann ausdefinierte klassen ueber die schnittstelle schickst, aua ! genau so debug und release versionen. ausdefinierte klassen -> crash.

unterschiedliche qt verionen, selbes problem !

du hasst aber dll und exe selber in der hand (das iss nen riesen vorteil). mit strengen konventionen kannst da scho was erreichen.
trotzdem isses ned trivial ...
wenn deine dll austauschbar bleibt ... musst du die zugehoerigkeit dll-exe ziemlich restrikt gestalten. beispielsweisse du baust ne neue exe mit ner neuen qt version ... baust dann auch die dll mit neu.
alles kein problem, biss der user selbst auf die idee kommt, und die dlls austauscht. dannn hasst wieder den konflikt (DLL versionen checken !!!) ....

deswegen solltest da echt genau abewaegen was machst ... und ob dir dein weg beim programmieren so viel vorteile bringt, das es die nachteile der versionspflege und des kompatiblitaetsmanagments hinterher aufwiegt.

wenn du zu der exe soweiso immer die richtige dll pflegen musst und andersrum, ist der Vorteil deiner dll eigentlich marginal ....

Ciao ...
Zuletzt geändert von RHBaum am 25. August 2009 14:28, insgesamt 1-mal geändert.
nuke160
Beiträge: 22
Registriert: 3. August 2009 11:24

Beitrag von nuke160 »

Danke für deine Antwort. Vielleicht hast du Recht und ich sollte lieber statische Bibliotheken verwenden, ich möchte jedoch nur ungern von der dynamischen Bibliothek wegrennen, nur weil ich nicht richtig programmieren kann.
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Ich sehe gerade das ja die Export-Definition fehlt... -> Foren-Suche nach Q_DECL_EXPORTS oder eben ne statische lib benutzen.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
nuke160
Beiträge: 22
Registriert: 3. August 2009 11:24

Beitrag von nuke160 »

Aber muessen deine Knoten unbeding qt objecte sein ? bringt dir signal / slot mechanismus so viel ?
Ja, signal / slot ist überaus wichtig für jeden Knoten.
und noch was .... fuer signal / slots (intern sind das events) brauchst du die oder eine Instanz von QApplication in der dll !!!!
willst du events über die dll drueber hinaus feuern, muss die dll die qApp von deiner exe kennen !
Wie ist das präzise gemeint? Und: Kann darin die Fehlermeldung begründet liegen?
Antworten