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

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

问题描述

我必须从暴露 DLLStart DLLStop 的dll启动Qt GUI。主要的正常(.exe)方法如下:

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

问题是阻塞 a.exec 调用,因为在dll DLLStart 需要立即返回(见下文)。任何解决方法?备注:问题是与添加QT GUI共享一些共同点动态库,但它并不完全重复。

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) { }


推荐答案

Windows上的一种方法是在单独的项目中启动 QApplication QThread 。它不可移植 - 它不适用于OS X(我正在研究一个修复)。

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).

但是,你不需要一个单独的线程。如果你把你的代码注入一个正在运行的应用程序,它已经有一个事件循环。你只需要创建一个全局的 QApplication 对象,你就完成了。事件循环已经在运行,因此您不需要调用 exec()。 Qt的窗口与原生事件循环集成,一切都很好。

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.

需要调用 QCoreApplication :: processEvents 一次。它会将当前应用程序实例集成到Windows事件循环中。

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

startup()

The startup() and shutdown() should be called at appropriate times (on process attach and detach).

旧的答案如下。

下面是一个简短的例子,一个完整的自包含示例,请参阅我的其他回答

A short example is below, for a complete self-contained example see my other answer.

它不可移植,这就是为什么Qt文档建议。它的工作原理在Windows上很好。主线程不是魔术 - 不是在Windows上。 OS X上的Cocoa在某种程度上是笨拙的,显然是不可能的:(。

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 :(.

请注意,如果加载DLL的应用程序已经使用了Qt,确保你使用相同的C ++编译器编译你的DLL,链接到同一个C ++运行时,并使用与应用程序使用的二进制兼容的Qt版本,然后你不需要你自己的实例 QApplication 。要做一些有用的工作,显示一个Widget或实例化一些 QObjects 也可以使用 QMetaObject :: invokeMethod(obj,mySlot,Qt :: QueuedConnection)而不是使用定时器:当控制返回到事件循环时将进行调用。

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.

注意,我在这里有点讽刺:如果你是使用DLL的应用程序的作者,上一段中的条件将可靠地被满足。否则 - 忘记它。

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天全站免登陆