从dll启动Qt GUI(在DLLStart函数中) [英] Starting Qt GUI from dll (in DLLStart function)
问题描述
我必须从一个暴露于$ code> DLLStart 和 DLLStop
的dll启动Qt GUI。主要的(.exe)方法如下:
int main(int argc,char * argv []){
QApplication a(argc,argv);对话框w
w.show();
return a.exec();
}
问题是阻止 a.exec()
调用,因为在dll DLLStart
需要立即返回(见下文)。任何解决方法?备注:问题是与添加Qt GUI共享一些共同点一个动态库,但它不是完全重复的。
/ **启动模块* /
int __stdcall DLLStart(void){
..
QApplication qaDll(ac,av);对话框w
w.show();
qaDll.exec();
return 0; //从未达到
}
/ **停止模块* /
void __stdcall DLLStop(void){}
在Windows上运行的一种方法是在单独的 QApplication
的QThread
。它不是可移植的 - 它不适用于OS X(我在研究一个修复)。
但是,您不需要单独的线程。如果您将代码注入正在运行的应用程序,它已经有一个事件循环。您只需要创建一个全局的 QApplication
对象即可完成。事件循环已经在运行,因此您不需要调用 exec()
。 Qt的Windows与本机事件循环集成,一切都很好。
您需要调用 QCoreApplication :: processEvents
一次。它将当前的应用实例集成到Windows事件循环中,就是这样。
因此,您的启动代码可能如下所示:
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()
{
删除win;
删除应用程序;
free argv [0];
delete [] argv;
delete argc;
}
startup()
和 shutdown()
应该在适当的时间调用(进程附加和分离)。
旧答案如下。这不是完全是最新的。
下面是一个简短的例子,对于一个完整的自包含例子,请参阅我的其他答案。
它不可移植,这就是为什么Qt文档建议反对它。它在Windows上工作正常。主线程不是魔术 - 不在Windows上。可可在OS X上是笨拙的,显然是不可能的:(。
请注意,如果加载DLL的应用程序已经使用了Qt,那么没有什么可进一步的确保您使用相同的C ++编译器编译您的DLL,并链接到相同的C ++运行时,并使用与应用程序使用的二进制兼容的Qt版本,然后您不需要自己的 QApplication
。要获得一些有用的工作,请显示一个Widget或实例化一些 QObjects
,其定时器将使他们变得忙碌也可以使用 QMetaObject :: invokeMethod(obj,mySlot,Qt :: QueuedConnection)
而不是使用定时器:当控件返回到事件循环时,将进行调用。
如果这是不可能的,那么以下是您唯一的选择,只要我能告诉我,工作正常。
$ b $请注意,我在这里有点讽刺:前段的条件将会可靠地得到满足是使用该DLL的应用程序的作者。否则 - 忘记它。
class AppThread:public QThread {
int& ARGC;
char ** argv;
int result;
void run(){
QApplication a(argc,argv);
对话框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();
}
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) { }
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:
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;
}
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_) {}
}
int __stdcall DLLStart(void) {
AppThread * thread = new AppThread(argc, argv);
thread->start();
return 0;
}
void __stdcall DLLStop(void) {
qApp->thread()->quit();
qApp->thread()->wait();
}
这篇关于从dll启动Qt GUI(在DLLStart函数中)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!