Utilizzo di una DLL basata su Qt in un’applicazione non Qt

Lo sto facendo bene?

Un mio cliente ha un gruppo in cui sto sviluppando roba client-server basata su Qt con un sacco di cose e prese di widget divertenti.

Un altro gruppo all’interno dell’azienda desidera utilizzare una versione integrata delle classi del fornitore di dati client basate su QTcpSocket. (Che in pratica suona come suona, fornisce dati dal server ai display client)

Tuttavia, quel gruppo ha un’enorme applicazione costruita principalmente con MFC e che semplicemente non cambierà molto presto. La DLL basata su Qt è anche in fase di caricamento in ritardo in modo che possa essere distribuita senza questa funzionalità in determinate configurazioni.

Ho funzionato, ma è un po ‘hacky. Ecco la mia soluzione al momento:

Il costruttore della class wrapper DLL chiama QCoreApplication :: instance () per vedere se è NULL o no. Se è NULL, presuppone che si trovi in ​​un’app non Qt e crea un’istanza QCoreApplication di sua proprietà:

if (QCoreApplication::instance() == NULL) { int argc = 1; char* argv[] = { "dummy.exe", NULL }; d->_app = new QCoreApplication(argc, argv); // safe? } else d->_app = NULL; 

Quindi imposterà un timer Windows per chiamare occasionalmente processEvents ():

 if (eventTimerInterval > 0) { // STATE: start a timer to occasionally process the Qt events in the event queue SetTimer(NULL, (UINT_PTR)this, eventTimerInterval, CDatabaseLayer_TimerCallback); } 

Il callback chiama semplicemente la funzione processEvents () utilizzando il timerID come puntatore all’istanza della class. I documenti SetTimer () dicono che quando HWND è NULL ignora il timerID, quindi questo sembra essere perfettamente valido.

 VOID CALLBACK BLAHBLAH_TimerCallback(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { ((BLAHBLAH*)idEvent)->processEvents(); // basically just calls d->_app->processEvents(); } 

Quindi distruggo l’istanza QCoreApplication come l’ultima cosa nel distruttore.

 BLAHBLAH::~BLAHBLAH() { .. other stuff QCoreApplication* app = d->_app; d->_app = NULL; delete d; if (app != NULL) delete app; } 

Se l’applicazione di hosting desidera effettuare il time delle chiamate per processEvents (), può passare 0 in per eventTimerInterval e chiamare BLAHBLAH :: processEvents () stesso.

Qualche idea su questo? Portare l’app su Qt non è un’opzione. Non è nostro.

Sembra funzionare, ma ci sono probabilmente diverse supposizioni che vengono interrotte qui. Posso semplicemente build una QCoreApplication con argomenti fittizi del genere? La coda degli eventi è sicura per operare in questo modo?

Non voglio che questo mi esploda in faccia dopo. Pensieri?

Studiando il codice Qt sembra che QCoreApplication sia necessario per inviare messaggi a livello di sistema come gli eventi del timer. Cose come segnale / slot e persino QThreads non dipendono da esso a meno che non siano correlate a quei messaggi di sistema. Ecco come faccio questo in una libreria condivisa (in modo cross platform usando Qt stesso) e in effetti faccio call exec , perché processEvents () da solo non elabora tutto.

Ho uno spazio dei nomi globale:

 // Private Qt application namespace QAppPriv { static int argc = 1; static char * argv[] = {"sharedlib.app", NULL}; static QCoreApplication * pApp = NULL; static QThread * pThread = NULL; }; 

Ho un metodo OpenApp in un QObject (che è moc’ed) come questo:

 // Initialize the app if (QAppPriv::pThread == NULL) { // Separate thread for application thread QAppPriv::pThread = new QThread(); // Direct connection is mandatory connect(QAppPriv::pThread, SIGNAL(started()), this, SLOT(OnExec()), Qt::DirectConnection); QAppPriv::pThread->start(); } 

Ed ecco lo slot OnExec :

 if (QCoreApplication::instance() == NULL) { QAppPriv::pApp = new QCoreApplication(QAppPriv::argc, QAppPriv::argv); QAppPriv::pApp->exec(); if (QAppPriv::pApp) delete QAppPriv::pApp; } 

Finora sembra funzionare bene, non sono sicuro di dover eliminare l’app alla fine, aggiornerò la mia risposta se trovo qualcosa.

La Documentazione Qt per 4.5.2 afferma che gli argomenti di QCoreApplication devono avere una durata purché l’object dell’applicazione, quindi non si dovrebbero usare le variabili locali.

A parte quella piccola cosa:

Sono alle prese con lo stesso problema, e tutto sembra funzionare anche per me. Raccomanderei di stare molto attento al tempo di scaricamento / uscita, tuttavia, dal momento che se si utilizza il ciclo degli eventi da un’altra applicazione e tale ciclo di eventi viene interrotto prima che la libreria venga scaricata, possono verificarsi tutti i tipi di ctriggers cattiveria quando si tenta di chiudere () socket ed eliminare QObjects.