QLibrary: resolve gibt 0x0 -> interface darf nicht erben?

Alles rund um die Programmierung mit Qt
Antworten
ThomasS
Beiträge: 6
Registriert: 4. Februar 2014 15:28

QLibrary: resolve gibt 0x0 -> interface darf nicht erben?

Beitrag von ThomasS »

Hallo zusammen, ich bin neu im Forum. Zunächst einmal Danke fürs Lesen.

Ich nutze den QT Creator der Version 5.2 (mingw48 - opengl - x86).
Mein Programm soll eine dll während der Laufzeit laden. Es lässt sich sowohl kompillieren als auch ausführen. Jedoch gibt die resolve(..) Funktion in einem bestimmten Fall einen NULL - Zeiger zurück. Hier liegt das Problem, denn diesen bestimmten Fall brauche ich.



Zunächst der prinzipielle Aufbau des Programms:


Das Hauptprogramm benutzt Klassen, die als Unterprojekte angelegt und in Dlls (bzw. bei QT .a Dateien) untergebracht sind. Alles wird zur Kompillierzeit zusammen gelinkt.

-----------------------

// eine abstakte Klasse (eigenes Unterprojekt --> dll wird beim Kompillieren eingebunden)
class A : public QGraphicsItem
{
...
}

// eine weitere abstrakte Klasse (eigenes Unterprojekt --> dll wird beim Kompillieren eingebunden)
class B
{
...
}


Bis hier hin alles OK. Das gesamte Projekt lässt sich "builden" und ausführen ohne abzustürzen.

-----------------------


Nun zur dll, die während der Laufzeit geladen werden soll:


// eine nicht abstrakte Klasse, die von B erbt (und entsprechend alle virtuellen Funktionen implementiert)
// B ist also die Interface - Klasse
class SpecialB : public B
{
...
}

// dazu wird noch eine Funktion in dieser Dll definiert, die eine Instanz der Klasse SpecialB erzeugen soll
extern "C" MY_EXPORT SpecialB* Create(...Argumente...)
{
return new SpecialB(...Argumente...);
}

MY_EXPORT ist entsprechend der QT Hilfe definiert:
#ifdef Q_OS_WIN
#define MY_EXPORT __declspec(dllexport)
#else
#define MY_EXPORT
#endif


Auch dieses Projekt wird fehlerfrei gebaut und beim Ausführen des Hauptprogramms mittels QLibrary geladen.

-----------------------
-----------------------

Zum Verhalten:

Die Funktion "Create" soll aufgelöst werden, also: FUNC_TYPE create_func = (FUNC_TYPE)library->resolve("Create");

Dieser Befehl funktioniert problemlos, wenn die abstrakte Klasse B nicht von der abstrakten Klasse A erbt. (also das ": public A" löschen)

Es funktioniert aber nicht, (d.h. create_func == 0x0 ) wenn B von A erbt.
Es funktioniert ebenfalls nicht, wenn zwar B von A erbt, aber die Vererbung bei A von QGraphicsItem herausgenommen wird. (also das ": public QGraphicsItem" löschen - falls jemand einwenden möchte, dass QGraphicsItem ja auch Slots und der Gleichen hat, und es deswegen nicht funktioniert)

Instanzen von QGraphicsView und QGraphicsScene werden übrigens im Hauptprogramm erzeugt.
In dem QT Creator Beispiel "Elastic Nodes" sieht man zudem, dass Klassen, die von QGraphicsItem abgeleitet sind, kein Q_OBJECT makro benötigen. Daher muss auch das Interface (die abstrakte Klasse B) kein Q_OBJECT sein

Die Frage ist nun, warum darf B nicht von einer anderen Klasse (A) abgeleitet sein, nicht einmal dann, wenn sich diese Klasse (A) qualitativ nicht von B unterscheidet?
Was habe ich übersehen? Liegt es daran, dass durch die Vererbung von A an B automatisch auch A zur Interface - Klasse wird und SpecialB damit Funktionen zweier verschiedener Interface-Klassen implementiert? Falls ja, was hat das mit der Funktion "Create" zu tun?

Nochmals vielen Dank fürs Lesen und für evtl. hilfreiche Vorschläge!
ThomasS
Beiträge: 6
Registriert: 4. Februar 2014 15:28

Re: QLibrary: resolve gibt 0x0 -> interface darf nicht erben

Beitrag von ThomasS »

OK, habe nun in meiner Verzweiflung entsprechend aller #includes, die ich in den betreffenden Unterprojekten gemacht habe auch die zugehörigen Bibliotheken in die jeweiligen .pro-Dateien eingefügt. Das hat das Problem offenbar behoben. Es war also mal wieder eines dieser fiesen Linker-Probleme, obwohl ich beim Bauen des Projektes keine Linker-Fehler bekommen hatte. Sehr gemein, aber

gelöst...
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Re: QLibrary: resolve gibt 0x0 -> interface darf nicht erben

Beitrag von RHBaum »

warum um himmelswillen machst du das ?
extern "C" MY_EXPORT SpecialB* Create(...Argumente...)
{
return new SpecialB(...Argumente...);
}
Du schreibst Klassen Interfaces die von QOBject abgeleitet sind und damit ne ganze latte an statischen gedoens mit verpasst bekommen :-)
Damit hasst du deine Seele sowieso schon an den Compiler und an die QT verkauft !?
Macht an wenigen Stellen sinn ... deine dll's werden vom compiler / version und der QT Version und deren Kompatiblitaeten abhaengig. D.h. du solltest App und diese Dlls immer in einem rutsch erstellen und auch wirklich unter deiner Kontrolle haben ... nen Pluginkonzept wird das hoffentlich nicht ?

was versuchst du dann mit dem extern "C" noch zu retten ???

schreib ne statische creatorfunktion an die Klasse und gut ist.
Die klassen selber muessen ja eh schon entsprechende Exporteintraege haben ... sonst koenntest keine methoden der Klassen von ausserhalb der dlls callen.

und selbst nen new von ausserhalb der Dll ist in deiner Konstellation "legal", weil auf das new/delete ueber dll grenzen musst dich eh durch den Qt mechanismus eh verlassen koennen ...
oder wer destroyt deine Objekte ?

Ciao ....
ThomasS
Beiträge: 6
Registriert: 4. Februar 2014 15:28

Re: QLibrary: resolve gibt 0x0 -> interface darf nicht erben

Beitrag von ThomasS »

Hallo RH

Danke fürs Lesen. Sorry, ich dachte, dass ich eine eMail Benachrichtigung bekommen würde, sobald jemand antwortet...

Zu deinem Kommentar:

Nein, die Klasse ist letztlich von QGraphicsItem (QWidget) abgeleitet. Nicht ganz so mächtig wie QObject, aber die Latte mit statischem Gedoens kommt trotzdem mit.
Natürlich ist das ein Plugin-Konzept, aber nur für mich und auf sehr "wackeligen Beinen", ich weiß. Es ist nicht vorgesehen, dass Dritte daran arbeiten.

Ehrlich gesagt bin ich froh, dass ich durch Internetrecherche überhaupt einen Weg gefunden habe um mein Problem zu lösen. Da ich keine tiefergehenden Informatikkentnisse habe, kenne ich keine "Best Practices" - Methoden um ein Plugin-Konzept aufzuziehen.

Mir ist nicht bewusst, dass ich mit dem extern "C" irgendetwas "rette" (für mich ist das der einzige Weg, Funktionen aus dlls zu exportieren) und es wäre mir durchaus lieb, wenn ich mit QT eine Möglichkeit hätte, dynamische Inhalte Schrift und Linien usw. ohne QGraphicsItem und den ganzen Aufbau zu zeichnen. Leider habe ich mit QT keine Möglichkeit gefunden um es so wie in VS2010 zu realisieren.

Früher hatte ich ein ähnliches Plugin-Konzept in VS2010 aufgebaut. Aber die Plugin-Klassen waren nicht von irgendeinem mächtigen Objekt abgeleitet. Stattdessen konnte ich über einen Pointer auf ein CWnd einfach mit TextOut() und co. operieren. Dadurch waren die Klassen absolut leichtgewichtig.

Wenn dann alles gezeichnet war: BitBlt und voila!
Wunderbar anzusehen und flüssig. Aber eben gebunden an MFC. Dann doch lieber QT.

Welche anderen Möglichkeiten habe ich denn und wie würde ich das mit dem Plugin-Konzept besser machen?
Wie verkaufe ich meine Seele denn nicht an QT? Ich arbeite ja mit dem QT Creator.

Gruß
Thomas

PS.: QPluginLoader usw. habe ich nicht zum Laufen bekommen. QLibrary war das Einzige, das funktionierte
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: QLibrary: resolve gibt 0x0 -> interface darf nicht erben

Beitrag von Christian81 »

Da mit die Export-Definitionen komisch vorkommen würde ich gern wissen was Du mit
und in Dlls (bzw. bei QT .a Dateien)
meinst ...
.dll - dynamische library
.a / .lib - statische library, vielleicht auch statische import-Library wenn daneben eine .dll erzeugt wird.

Wenn also class B von class A erbt und in einer eigenen dynamischen Library liegt, dürfte es unter Windows gar nicht linken da class A nicht exportiert wurde.

Wo hast Du das mit MY_EXPORT her? Qt-Hilfe? Hoffe ich nicht ... richtig ist

Code: Alles auswählen

#include <qglobal.h>

#ifdef MAKE_MY_LIBRARY
 # define MY_EXPORT Q_DECL_EXPORT
#else
 # define MY_EXPORT Q_DECL_IMPORT
#endif
Beim Bauen muss dann MAKE_MY_LIBRARY definiert sein, beim Benutzen entsprechend nicht.

Und automatisch eine EMail bekommt man, wenn man es aktiviert hat. [:)]
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
ThomasS
Beiträge: 6
Registriert: 4. Februar 2014 15:28

Re: QLibrary: resolve gibt 0x0 -> interface darf nicht erben

Beitrag von ThomasS »

Die meisten Bibliotheken werden statisch in mein Hauptprogramm gelinkt, aber es werden während der Laufzeit eben noch Module geladen (.dll), die von einigen der statisch verlinkten Bibliotheken erben. Jede dll exportiert eine Funktion "Create" und wenn ich die aufrufe, erzeugt mir diese Funktion eine Instanz der Klasse, die in der Blibliothek definiert ist. Da der genaue Klassenname ja in der dll steht, aber dem Hauptprogramm nicht bekannt ist, wüsste ich jetzt nicht, wie ich auf anderem Weg eine Instanz einer Klasse (die in der dll definiert ist) bekommen könnte.

es sieht im wesentlichen so aus, dass ich im Hauptprogramm schreibe:

Code: Alles auswählen

Symbol* sml = Create(..bla bla parameter..);
in der dll wird aber aufgerufen:

Code: Alles auswählen

extern "C" SpecialSymbol* Create(..bla bla parameter..)
{
    return new SpecialSymbol(..bla bla parameter);
}
wobei SpecialSymbol ja von Symbol erbt, womit die Zuweisung im Hauptprogramm legitim ist.


Das mit dem MY_EXPORT steht tatsächlich so in der QT Hilfe als Besipiel zur Verwendung der funktion resolve(..), die zur Klasse QLibrary gehört. (s.u.)


Funktioniert jetzt auch wieder ohne Probleme.

Beste Grüße
Thomas


Auszug aus der QT Hilfe:

QFunctionPointer QLibrary::resolve(const char * symbol)
Returns the address of the exported symbol symbol. The library is loaded if necessary. The function returns 0 if the symbol could not be resolved or if the library could not be loaded.

Example:

Code: Alles auswählen

typedef int (*AvgFunction)(int, int);

AvgFunction avg = (AvgFunction) library->resolve("avg");
if (avg)
    return avg(5, 8);
else
    return -1;
The symbol must be exported as a C function from the library. This means that the function must be wrapped in an extern "C" if the library is compiled with a C++ compiler. On Windows you must also explicitly export the function from the DLL using the __declspec(dllexport) compiler directive, for example:

Code: Alles auswählen

extern "C" MY_EXPORT int avg(int a, int b)
{
    return (a + b) / 2;
}
with MY_EXPORT defined as

Code: Alles auswählen

#ifdef Q_OS_WIN
#define MY_EXPORT __declspec(dllexport)
#else
#define MY_EXPORT
#endif
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: QLibrary: resolve gibt 0x0 -> interface darf nicht erben

Beitrag von Christian81 »

Solange das Define in der Source-Datei und nicht im Header steht ist das auch ok.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Antworten