C++ 从dll启动Qt GUI(在DLLStart函数中)

C++ 从dll启动Qt GUI(在DLLStart函数中),c++,qt,dll,C++,Qt,Dll,我必须从公开DLLStart和DLLStop的dll启动Qt GUI。main中的正常(.exe)方法如下所示: int main(int argc, char *argv[]) { QApplication a(argc, argv); Dialog w; w.show(); return a.exec(); } static struct Data { int argc = 1; char *argv[2] = {strdup("dummy"), {}};

我必须从公开
DLLStart
DLLStop
的dll启动Qt GUI。main中的正常(.exe)方法如下所示:

int main(int argc, char *argv[]) {
    QApplication a(argc, argv); Dialog w;
    w.show();
    return a.exec();
}
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;
}
问题在于阻塞了
a.exec()
调用,因为在dll
DLLStart
中,需要立即返回(见下文)。有解决办法吗?备注:问题与“”有一些共同点,但并非完全相同

/** 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上工作的一种方法是在单独的
QThread
中启动
QApplication
。它不可移植——在OSX上不起作用(我正在研究修复方案)

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

您需要调用
QCoreApplication::processEvents
一次。它将当前应用程序实例集成到windows事件循环中,就是这样

因此,您的启动代码可以如下所示:

int main(int argc, char *argv[]) {
    QApplication a(argc, argv); Dialog w;
    w.show();
    return a.exec();
}
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()
(在进程连接和分离时)


旧答案如下。这已经不是最新的了

下面是一个简短的示例,有关完整的自包含示例,请参见我的

它是不可移植的,这就是为什么Qt文档建议不要使用它。它在Windows上工作得很好。主线程不是魔法——在Windows上不是。OSX上的Cocoa在某种程度上是笨拙的,并且使它不可能实现,显然:(

注意,如果加载DLL的应用程序已经使用QT,那么就没有什么可以做的了。确保用相同的C++编译器编译DLL,链接到同一个C++运行时,使用与应用程序使用的二进制代码兼容的QT版本。de>。要完成一些有用的工作,请显示小部件或使用计时器实例化一些

QoObject
,这些计时器将使它们忙碌。您还可以使用
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();
}

不知道。我只能建议你喜欢opencv.org代码中的window_qt.cpp。它使用qt来显示一个窗口,其中有自己的事件循环,作为非qt库的一部分。是从
DllStart
调用的还是从调用过程调用的?@MB rep()此文件已定位。搜索未找到它,将有一个赃物。@Synxis,不是从DllMain调用的,没有DllMain,所以从调用进程调用。它真的有效吗?说你不能在非主线程中有小部件,尽管我不知道如果你的主应用程序没有定义
QApplication
,它会如何运行。如果主应用程序或某些其他库已经使用qt?只要QApplication的多个实例是隔离的,就没有问题,如果您有多个线程,每个二进制模块(DLL或EXE)一个线程,每个线程实际上都有自己的qt副本,“主应用程序”在任何一种方式下,它都不特殊,它只是运行过程的地址空间中的一个二进制模块。如果你的DLL没有像exe那样链接到Qt的相同实例,它就可以了。通常你的DLL将是一个C DLL,甚至你不能保证链接到同一个C++运行时。C++编译器:我想你应该看看这个端口:亲爱的奥伯,我已经尝试过你的建议,但我没能使它有效:((你能帮我一个忙吗?这是我的页面链接:@ RealStimeMeNICA,你找到解决OSX的方案了吗?