Usar una DLL basada en Qt en una aplicación que no sea Qt

¿Lo estoy haciendo bien?

Un cliente mío tiene un grupo en el que estoy desarrollando cosas de servidor-cliente basadas en Qt con muchas cosas divertidas y sockets de widgets.

Otro grupo dentro de la compañía quiere usar una versión empaquetada de las clases de proveedor de datos de cliente basadas en QTcpSocket. (Que básicamente hace lo que parece, proporciona datos del servidor a las pantallas del cliente)

Sin embargo, ese grupo tiene una gran aplicación construida principalmente con MFC, y eso simplemente no va a cambiar pronto. La DLL basada en Qt también carga el retraso para que pueda implementarse sin esta característica en ciertas configuraciones.

Lo tengo funcionando, pero es un poco raro. Aquí está mi solución en este momento:

El constructor de la clase contenedora DLL llama a QCoreApplication :: instance () para ver si es NULL o no. Si es NULL, supone que está en una aplicación que no es Qt y crea una instancia de QCoreApplication propia:

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

A continuación, configurará un temporizador de Windows para ocasionalmente llamar a 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); } 

La callback simplemente llama a la función processEvents () utilizando el ID de tiempo como un puntero a la instancia de clase. SetTimer () dice que cuando HWND es NULL ignora el ID de tiempo, por lo que parece ser perfectamente válido.

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

Luego destruyo la instancia de QCoreApplication como la última cosa en el destructor.

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

Si la aplicación de alojamiento desea sincronizar las llamadas a processEvents (), puede pasar 0 in para eventTimerInterval y llamar a BLAHBLAH :: processEvents ().

Tiene alguna idea sobre esto? Transferir esa aplicación a Qt no es una opción. No es nuestro

Parece que funciona, pero probablemente hay varias suposiciones que se rompen aquí. ¿Puedo simplemente construir una QCoreApplication con argumentos ficticios como ese? ¿La cola de eventos es segura para operar de esta manera?

No quiero que me explote en la cara más tarde. ¿Pensamientos?

Al estudiar el código Qt, parece que QCoreApplication es necesaria para enviar mensajes a nivel de todo el sistema, como los eventos del temporizador. Cosas como signal / slots e incluso QThreads no dependen de él a menos que estén relacionados con esos mensajes de todo el sistema. Aquí es cómo hago esto en una biblioteca compartida (de forma cruzada usando Qt) y realmente llamo a exec , porque processEvents () solo no procesa todo.

Tengo un espacio de nombre global:

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

Tengo un método OpenApp en un QObject (que se moc’ed) de esta manera:

 // 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(); } 

Y aquí está la ranura OnExec :

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

Hasta ahora parece estar funcionando bien, no estoy seguro si necesito eliminar la aplicación al final, actualizaré mi respuesta si encuentro algo.

La documentación de Qt para 4.5.2 dice que los argumentos para QCoreApplication necesitan tener una vida útil tan larga como el objeto de la aplicación, por lo que no debería usar variables locales.

Aparte de esa pequeña cosa:

Estoy lidiando con el mismo problema, y ​​todo parece funcionar para mí también. Sin embargo, recomendaría ser muy cuidadoso en el momento de la descarga / salida, ya que si está utilizando el bucle de eventos de otra aplicación y ese bucle de eventos se detiene antes de que se descargue su biblioteca, todo tipo de desagradables problemas pueden ocurrir cuando intenta cerrar () sockets y eliminar QObjects.