【问题标题】:Starting Qt GUI from dll (in DLLStart function)从 dll 启动 Qt GUI(在 DLLStart 函数中)
【发布时间】:2012-06-15 15:47:32
【问题描述】:

我必须从暴露DLLStartDLLStop 的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) { }

【问题讨论】:

  • 不知道。我只能建议你喜欢 opencv.org 代码中的 window_qt.cpp。它使用 Qt 来显示一个带有自己的事件循环的窗口,作为非 Qt 库的一部分。
  • DllStart 是从 DllMain 调用的吗?还是从调用进程调用?
  • @MB 任何提示在代表 (code.opencv.org/projects/opencv/repository) 中此文件所在的位置。搜索没有找到它,将有一个战利品。
  • @Synxis,不是从DllMain调用的,没有DllMain,所以是从调用进程调用的

标签: c++ qt dll


【解决方案1】:

在 Windows 上工作的一种方法是在单独的 QThread 中启动 QApplication。它不可移植——它不能在 OS X 上运行(我正在研究修复)。

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

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

【讨论】:

  • 真的有用吗? doc.qt.nokia.com/4.7-snapshot/… 说你不能在非主线程中拥有小部件,尽管我不知道如果你的主应用程序没有定义 QApplication 会如何表现。如果主应用程序或其他一些库已经使用 qt 怎么办?
  • 拥有多个 QApplication 实例只要它们是隔离的就不是问题,如果你有多个线程,每个二进制模块(DLL 或 EXE)一个,每个都有自己的效果,就会发生这种情况Qt的副本。 “主应用程序”在任何方面都没有什么特别之处,它只是运行进程地址空间中的一个二进制模块。如果您的 DLL 没有链接到与 EXE 相同的 Qt 实例,那就没问题了。通常你的 DLL 是一个 C DLL,你甚至不能保证链接到同一个 C++ 运行时。哎呀,你甚至不能保证使用 ABI 兼容的 C++ 编译器的 EXE 和 DLL。
  • 我认为你应该注意这个端口:stackoverflow.com/questions/9777911/…
  • 亲爱的 Ober,我已经尝试了你的建议,但我没有成功,:((,你能帮我吗?这是我的页面链接:stackoverflow.com/questions/54667520/…
  • @ReinstateMonica,你找到 OSX 的解决方案了吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-17
  • 1970-01-01
  • 2012-09-30
  • 1970-01-01
  • 2015-06-17
相关资源
最近更新 更多