Starting Qt GUI from dll (in DLLStart function)
c++, dll, qt
Solution
One way works on Windows is to start `QApplication` in a separate `QThread`. It's not portable -- it doesn't work on OS X (I'm researching a fix).
But, you don't need a separate thread. If you inject your code into a running application, it already has an event loop. You only need to create a global `QApplication` object and you're done. The event loop is already running, so you don't need to call `exec()`. Qt's windows integrate with the native event loop, and everything is good on that front.
You do need to call `QCoreApplication::processEvents` once. It will integrate the current application instance into the windows event loop, and that's it.
Thus, your startup code could look as follows:
static struct Data {
int argc = 1;
char *argv[2] = {strdup("dummy"), {}};
QApplication app{argc, argv};
MainWindow win;
} *d;
static void startup() {
d = new Data;
d->win.show();
d->app.processEvents();
}
static void shutdown() {
delete d;
}
The `startup()` and `shutdown()` should be called at appropriate times (on process attach and detach).
Old answer follows. This is not completely up to date anymore.
A short example is below, for a complete self-contained example see my other answer.
It is not portable and that's why Qt documentation advises against it. It works just fine on Windows. The main thread is not magic -- not on Windows. Cocoa on OS X is clumsy in a way and makes it impossible, apparently :(.
Note that if the application that loads the DLL already uses Qt, then there's nothing further for you to do. Ensure you compile your DLL with the same C++ compiler, link against the same C++ runtime, and use a version of Qt that's binary compatible with the one used by application. You then don't need your own instance of `QApplication`. To get some useful work done, show a Widget or instantiate some `QObjects` with timers that will get them busy. You can also use `QMetaObject::invokeMethod(obj, "mySlot", Qt::QueuedConnection)` instead of using timers: the call will be made when control returns to the event loop.
If that's not possible, then the below is your only option. Works just fine, as far as I can tell.
Note that I'm a bit sarcastic here: The conditions in the previous paragraph will be met reliably maybe if you are the author of the application that uses the DLL. Otherwise -- forget about it.
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) {}
~AppThread() { quit(); wait(); }
}
extern "C" int __stdcall DLLStart(void) {
auto *thread = new AppThread(argc, argv);
thread->start();
return 0;
}
extern "C" void __stdcall DLLStop(void) {
delete qApp->thread();
}
Problem
I have to start a Qt GUI from a dll exposing `DLLStart` and `DLLStop`. The normal (.exe) approach in main is as follows: ``` int main(int argc, char *argv[]) { QApplication a(argc, argv); Dialog w; w.show(); return a.exec(); } ``` The problem is the blocking `a.exec()` call, since in the dll `DLLStart` needs to return immediately (see below). Any workaround for this? Remark: The question is sharing some common ground with " Adding a Qt GUI to a Dynamic Library ", but it is no exact duplicate. ``` /** 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) { } ```