2012-06-15 9 views
8

Tengo que iniciar una GUI de Qt desde un dll exponiendo DLLStart y DLLStop. El enfoque normal (.exe) en el principal es el siguiente:Iniciando GUI de Qt desde dll (en la función de inicio de DLLS)

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

El problema es la a.exec() bloqueo de llamadas, ya que en la DLL DLLStart necesita volver inmediatamente (véase más adelante). ¿Alguna solución para esto? Observación: La pregunta es compartir algo en común con "Adding a Qt GUI to a Dynamic Library", pero no es un duplicado exacto.

/** 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

No lo sé. Solo puedo sugerir que te guste en window_qt.cpp en el código de opencv.org. Utiliza Qt para mostrar una sola ventana con su propio bucle de eventos como parte de una biblioteca que no es de Qt. –

+1

¿Se llama a 'DllStart' desde' DllMain'? ¿O llamado desde el proceso de llamada? – Synxis

+0

@MB, cualquier pista en la que se encuentre el representante (http://code.opencv.org/projects/opencv/repository). La búsqueda no lo encuentra, tendrá un botín. –

Respuesta

12

Una forma en que funciona en Windows es comenzar QApplication en una separada QThread. No es portátil, no funciona en OS X (estoy investigando una solución).

Pero, no necesita un hilo por separado. Si inyectas tu código en una aplicación en ejecución, ya tiene un bucle de evento. Solo necesita crear un objeto global QApplication y listo. El ciclo de eventos ya se está ejecutando, por lo que no es necesario que llame al exec(). Las ventanas de Qt se integran con el bucle de eventos nativo, y todo es bueno en ese frente.

Usted do need para llamar al QCoreApplication::processEvents una vez. Integrará la instancia de la aplicación actual en el bucle de eventos de Windows, y eso es todo.

lo tanto, su código de inicio podría ser como sigue:

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; 
} 

El startup() y shutdown() deberían ser llamados en los momentos apropiados (en proceso de unir y separar).


Respuesta antigua a continuación. Esto ya no está completamente actualizado.

Un breve ejemplo está debajo, para un ejemplo autónomo completo vea mi other answer.

No es portátil y por eso la documentación de Qt desaconseja su uso. Funciona bien en Windows. El hilo principal no es mágico, no en Windows. Cocoa en OS X es torpe en cierto modo y lo hace imposible, aparentemente :(.

Tenga en cuenta que si la aplicación que carga el archivo DLL ya usa Qt, entonces no hay nada más que hacer. Asegúrese de compilar el archivo DLL con el mismo compilador de C++, el enlace contra el mismo tiempo de ejecución de C++, y utiliza una versión de Qt que es binaria compatible con la utilizada por la aplicación. Entonces no necesita su propia instancia de QApplication. Para hacer un trabajo útil, muestre un widget o una instancia de alguna QObjects con temporizadores que conseguirá ocupados también puede utilizar QMetaObject::invokeMethod(obj, "mySlot", Qt::QueuedConnection) en lugar de utilizar los temporizadores:.. se realizará la llamada cuando el control vuelve al bucle de eventos

Si eso no es posible, entonces el siguiente es su única opción. Wo Está bien, por lo que puedo decir.

Tenga en cuenta que soy un poco sarcástico aquí: Las condiciones en el párrafo anterior se cumplirán de forma confiable tal vez si usted es el autor de la aplicación que utiliza el DLL. De lo contrario, olvídate de eso.

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

Comprobaré éste, ¡gracias hasta ahora! –

+0

¿Realmente funciona? http://doc.qt.nokia.com/4.7-snapshot/thread-basics.html#gui-thread-and-worker-thread dice que no puedes tener widgets en amenazas no primarias, aunque no tengo idea de cómo esto se comporta si su aplicación principal no define 'QApplication'. ¿Y qué pasa si la aplicación principal, o alguna otra lib ya usa qt? –

+0

No es un problema tener varias instancias de QApplication siempre que estén aisladas, como sucederá si tiene varios hilos, uno por cada módulo binario (DLL o EXE), cada uno con su propia copia de Qt. La "aplicación principal" no es especial de ninguna manera, es solo un módulo binario más en el espacio de direcciones del proceso en ejecución. Si su DLL no se vincula a la misma instancia de Qt que el EXE, estará bien. Por lo general, su DLL será una DLL de C, y ni siquiera se garantiza que se vincule con el mismo tiempo de ejecución de C++. Diablos, ni siquiera puedes garantizar el EXE y la DLL usando compiladores C++ compatibles con ABI. –

Cuestiones relacionadas