我必须从暴露DLLStart
和DLLStop
的dll启动Qt GUI。 main中的正常(.exe)方法如下:
int main(int argc, char *argv[]) {
QApplication a(argc, argv); Dialog w;
w.show();
return a.exec();
}
问题是阻止a.exec()
调用,因为在dll DLLStart
中需要立即返回(见下文)。有什么解决方法吗?备注:问题是与"分享一些共同点。 Adding a Qt GUI to a Dynamic Library",但它并不完全重复。
/** 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) { }
答案 0 :(得分:15)
在Windows上运行的一种方法是在单独的QApplication
中启动QThread
。它不可移植 - 它不适用于OS X(我正在研究修复)。
但是,您不需要单独的线程。如果将代码注入正在运行的应用程序,它已经有一个事件循环。您只需创建一个全局QApplication
对象就可以了。事件循环已在运行,因此您无需致电exec()
。 Qt的windows与原生事件循环集成,一切都很好。
您do need拨打QCoreApplication::processEvents
一次。它会将当前的应用程序实例集成到windows事件循环中,就是这样。
因此,您的启动代码可能如下所示:
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;
}
应在适当的时间调用startup()
和shutdown()
(在进程附加和分离时)。
旧答案如下。这不再完全是最新的了。
下面是一个简短的示例,有关完整的自包含示例,请参阅我的other answer。
它不可移植,这就是为什么Qt文档建议反对它。它在Windows上运行得很好。主线程不是魔术 - 不是在Windows上。 OS X上的Cocoa在某种程度上是笨拙的,显然是不可能的:(。
请注意,如果加载DLL的应用程序已经使用了Qt,那么您无需进一步操作。确保使用相同的C ++编译器编译DLL,链接到相同的C ++运行时,并使用与应用程序使用的二进制兼容的Qt版本。然后,您不需要自己的QApplication
实例。要完成一些有用的工作,请显示一个小部件或使用定时器实例化一些QObjects
,这将使他们忙碌。您也可以使用QMetaObject::invokeMethod(obj, "mySlot", Qt::QueuedConnection)
而不是使用计时器:当控制返回到事件循环时,将进行调用。
如果那是不可能的,那么以下是您唯一的选择。就我所知,工作得很好。
请注意,我在这里有点讽刺:如果您是使用DLL的应用程序的作者,则可以可靠地满足前一段中的条件。否则 - 忘了它。
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();
}