从dll启动Qt GUI(在DLLStart函数中) [英] Starting Qt GUI from dll (in DLLStart function)

查看:142
本文介绍了从dll启动Qt GUI(在DLLStart函数中)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须从一个暴露于$ 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆