2012-06-15 11 views
8

Ich muss eine Qt-GUI von einer DLL aussetzen DLLStart und DLLStop. Der normale (.exe) Ansatz in Haupt ist wie folgt:Starten von Qt GUI von dll (in DLLStart Funktion)

int main(int argc, char *argv[]) { 
    QApplication a(argc, argv); Dialog w; 
    w.show(); 
    return a.exec(); 
} 

Das Problem ist die Blockierung a.exec() Anruf, da in den dll DLLStart sofort zurückgeben muß (siehe unten). Irgendeine Abhilfe für dieses? Bemerkung: Die Frage ist eine gemeinsame Basis mit "Adding a Qt GUI to a Dynamic Library", aber es ist kein exaktes Duplikat.

/** start module */ 
int __stdcall DLLStart(void) { 
    .. 
    QApplication qaDll(ac, av); Dialog w; 
    w.show(); 
    qaDll.exec(); 
    return 0; // never reached 
} 

/** stop module */ 
void __stdcall DLLStop(void) { } 
+1

Weiß nicht. Ich kann Ihnen nur vorschlagen, dass Sie sich window_qt.cpp im opencv.org-Code ansehen. Es verwendet Qt, um ein einzelnes Fenster mit seiner eigenen Ereignisschleife als Teil einer Nicht-Qt-Bibliothek anzuzeigen. –

+1

Wird 'DllStart' von' DllMain' aufgerufen? Oder vom anrufenden Prozess angerufen? – Synxis

+0

@MB ein Hinweis, wo im Rep (http://code.opencv.org/projects/opencv/repository) diese Datei befindet. Suche findet es nicht, wird eine Beute darin haben. –

Antwort

12

Eine Möglichkeit, unter Windows funktioniert, ist QApplication in einem separaten QThread zu starten. Es ist nicht portierbar - unter OS X funktioniert es nicht (ich forsche nach einer Lösung).

Sie benötigen jedoch keinen separaten Thread. Wenn Sie Ihren Code in eine laufende Anwendung injizieren, hat er bereits eine Ereignisschleife. Sie müssen nur ein globales Objekt QApplication erstellen und fertig. Die Ereignisschleife wird bereits ausgeführt. Sie müssen also nicht exec() anrufen. Qt's Fenster integrieren sich in die native Event-Schleife, und an dieser Front ist alles gut.

Sie do need einmal anrufen QCoreApplication::processEvents. Es wird die aktuelle Anwendungsinstanz in die Windows-Ereignisschleife integrieren, und das war's.

So Ihr Startcode könnte wie folgt aussehen:

int * argc = nullptr; 
char ** argv = nullptr; 
QApplication * app = nullptr; 
MainWindow * win = nullptr; 

static void startup() { 
    argc = new int(1); 
    argv = new char*[1]; 
    argv[0] = strdup("dummy"); 
    auto app = new QApplication(*argc, argv); 
    auto w = new MainWindow; 
    w->show(); 
    app->processEvents(); 
} 

static void shutdown() 
{ 
    delete win; 
    delete app; 
    free argv[0]; 
    delete [] argv; 
    delete argc; 
} 

Die startup() und shutdown() soll (auf Prozess befestigen und lösen) zu geeigneten Zeitpunkt aufgerufen werden.


Alte Antwort folgt. Dies ist nicht mehr ganz auf dem neuesten Stand.

Ein kurzes Beispiel ist unten, für ein komplettes in sich abgeschlossenes Beispiel siehe meine other answer.

Es ist nicht tragbar und deshalb rät die Qt-Dokumentation davon ab. Es funktioniert gut unter Windows. Der Hauptthread ist keine Magie - nicht unter Windows. Cocoa auf OS X ist in einer Weise ungeschickt und macht es unmöglich, scheinbar :(.

Beachten Sie, dass, wenn die Anwendung, die die DLL lädt bereits verwendet Qt, dann nichts weiter zu tun. Stellen Sie sicher, dass Sie Ihre DLL kompilieren derselbe C++ - Compiler, Verknüpfung mit der gleichen C++ - Laufzeit und Verwendung einer Version von Qt, die binär mit der von der Anwendung verwendeten Version kompatibel ist Sie brauchen dann keine eigene Instanz von QApplication Um eine nützliche Arbeit zu erledigen, zeigen Sie ein Widget an oder einige QObjects mit Timer instanziiert, die sie beschäftigt bekommen Sie auch QMetaObject::invokeMethod(obj, "mySlot", Qt::QueuedConnection) statt mit Timer verwenden können:.. der Anruf, wenn die Steuerung kehrt zu der Ereignisschleife gemacht werden

Wenn das nicht möglich ist, dann unter das ist Ihre einzige Option, Wo Es geht mir gut, soweit ich das beurteilen kann.

Beachten Sie, dass ich hier ein wenig sarkastisch bin: Die Bedingungen im vorherigen Absatz werden möglicherweise zuverlässig erfüllt, wenn Sie der Autor der Anwendung sind, die die DLL verwendet. Sonst - vergiss es.

class AppThread : public QThread { 
    int & argc; 
    char ** argv; 
    int result; 
    void run() { 
    QApplication a(argc, argv); 
    Dialog d; 
    d.show(); 
    result = a.exec(); 
    } 
public: 
    AppThread(int & argc_, char ** argv_) : argc(argc_), argv(argv_) {} 
} 

int __stdcall DLLStart(void) { 
    AppThread * thread = new AppThread(argc, argv); 
    thread->start(); 
    return 0; 
} 

void __stdcall DLLStop(void) { 
    qApp->thread()->quit(); 
    qApp->thread()->wait(); 
} 
+0

Werde dies überprüfen, danke bis jetzt! –

+0

Funktioniert es wirklich? http://doc.qt.nokia.com/4.7-snapshot/thread-basics.html#gui-thread-and-worker-thread sagt, dass du keine Widgets in nicht primären Threads haben kannst, obwohl ich keine Ahnung habe, wie das geht verhält sich, wenn Ihre Hauptanwendung 'QApplication' nicht definiert. Und was ist, wenn die Hauptanwendung oder eine andere Bibliothek bereits qt verwendet? –

+0

Es ist kein Problem, mehrere Instanzen von QApplication zu haben, solange sie isoliert sind, wie es passieren wird, wenn Sie mehrere Threads haben, einen pro Binärmodul (DLL oder EXE), von denen jeder seine eigene Kopie von Qt hat. Die "Haupt-App" ist in keiner Weise besonders, es ist nur ein weiteres Binär-Modul im Adressraum des laufenden Prozesses. Wenn Ihre DLL nicht mit der gleichen Instanz von Qt verknüpft ist wie die EXE, ist sie in Ordnung. In der Regel wird Ihre DLL eine C-DLL sein, und Sie werden nicht einmal garantiert, dass Sie mit der gleichen C++ - Laufzeit verlinken. Verdammt, Sie können die EXE und DLL nicht mit ABI-kompatiblen C++ - Compilern garantieren. –