C++ 如何在不同的线程中运行不同的QApplication实例

C++ 如何在不同的线程中运行不同的QApplication实例,c++,qt,plugins,qapplication,C++,Qt,Plugins,Qapplication,我有一个Qt应用程序,它必须能够加载插件。加载插件时(我使用boost::dll),我调用插件工厂方法来检索具有以下(简化)接口的类: #ifdef _WIN32 using WindowHandle = HWND; #else using WindowHandle = void*; #endif class PluginInterface { public: /** * @brief Retrieve the window handle of the plugin. *

我有一个Qt应用程序,它必须能够加载插件。加载插件时(我使用boost::dll),我调用插件工厂方法来检索具有以下(简化)接口的类:

#ifdef _WIN32
using WindowHandle = HWND;
#else
using WindowHandle = void*;
#endif

class PluginInterface {
public:

  /**
   * @brief Retrieve the window handle of the plugin.
   *
   * The plugin should have a single main window, that's the main window of the
   * plugin itself. The method retrieve this window handler and pass it to the
   * caller, in order to allow it to attach this window to its main gui
   * interface. The pointer ownership is on the plugin, so the caller mustn't
   * delete it for any reason.
   *
   * @return Window handle.
   */
  virtual WindowHandle getWindowHandle() const = 0;
};

该接口允许检索指向窗口的HWND指针,然后我将其附加到应用程序上。基本思想是使用我的应用程序创建一个容器,在其中可以加载和运行其他库

在一个插件中,我通过创建另一个QApplication来实现这个接口。我创建了一个转发声明,因此当我加载插件时,应用程序不知道插件正在使用Qt,从而创建了一个不透明指针:

class Application;

class MyPluginInterface final : public PluginInterface {
public:

  MyPluginInterface();
  virtual ~MyPluginInterface();

public:
  WindowHandle getWindowHandle() const override;

private:

  Application* m_application;
};


////// CPP file

#include "Application.hpp"

MyPluginInterface::MyPluginInterface() :
  PluginInterface() {
  m_application = new Application();
}

MyPluginInterface ::~MyPluginInterface () {

}

WindowHandle MyPluginInterface ::getWindowHandle() const {
  return m_application->getWindowHandle();
}
Application
创建一个
QApplication
和一个
QMainWindow
,然后在另一个线程中运行
QApplication::exec()。然后,我创建一个方法来检索
QMainWindow
HWND
句柄,该句柄应该通过插件接口传递给容器应用程序,然后容器应用程序将显示它

#ifndef APPLICATION_HPP_
#define APPLICATION_HPP_

#include "WindowHandle.hpp"
#include <QApplication>
#include <QMainWindow>
#include <memory>
#include <thread>

class Application final {
public:

  Application();
  ~Application();
  WindowHandle getWindowHandle() const;

private:

  void createMainWindow();

private:

  std::unique_ptr<QApplication> m_application;
  std::thread m_applicationThread;
  QMainWindow* m_mainWindow;
};

#endif // !APPLICATION_HPP_

/////////////// CPP FILE

#include "Application.hpp"
#include <qpa/qplatformnativeinterface.h>
#include <QLabel>


///////////////////////////////////////////////////////////////////////////////
// USING SECTION                                                             //
///////////////////////////////////////////////////////////////////////////////

using WindowHandle;
using std::thread;

///////////////////////////////////////////////////////////////////////////////
// PUBLIC SECTION                                                            //
///////////////////////////////////////////////////////////////////////////////

Application::Application() {
  int argc = 1;
  char* argv[] = { "plugin" };
  QCoreApplication::addLibraryPath("./");
  m_application = std::make_unique<QApplication>(argc, argv);
  m_applicationThread = thread([this]() {
    createMainWindow();
    m_application->exec();
  });
}

Application::~Application() {
  if (m_applicationThread.joinable()) {
    m_applicationThread.join();
  }
}

WindowHandle Application::getWindowHandle() const {
  WindowHandle handle{ nullptr };
  if (QWindow* w = m_mainWindow->windowHandle()) {
    auto nativeInterface = QGuiApplication::platformNativeInterface();
    handle = static_cast<HWND>(nativeInterface->nativeResourceForWindow(QByteArrayLiteral("handle"), w));
  }
  return handle;
}

///////////////////////////////////////////////////////////////////////////////
// PRIVATE SECTION                                                           //
///////////////////////////////////////////////////////////////////////////////

void Application::createMainWindow() {
  m_mainWindow = new QMainWindow();
  QLabel* label = new QLabel(m_mainWindow);
  label->setText("Questo e' un plugin");
  m_mainWindow->setCentralWidget(label);
  m_mainWindow->show();
}
断言说

ASSERT failure in QCoreApplication: "there should be only one application object", file H:\...\corelib\kernel\qcoreapplication.cpp, line 792
由于容器应用程序现在不知道插件的任何内容(接口不公开Qt类和逻辑),我希望能够同时运行
QApplication


问题的原因是什么?我如何解决它?

各种
Q*应用程序
类都是典型的单例实例——严格来说每个进程一个。从:
“对于任何使用Qt的GUI应用程序,无论应用程序在任何给定时间是否有0、1、2或更多窗口,都有一个QApplication对象”
。您只需使用public method
bool isQt()在您的界面中)。但无论如何,您似乎不得不在主应用程序和基于Qt的插件中使用
QApplication
。另请参阅,可能在插件中使用静态实例指针是可能的。还要注意,在非主线程中不可能创建小部件。您还可以像
类应用程序一样向前声明
类QWidget
你也可以通过将插件接口与基于Qt的应用程序本身分离。我不知道是否可以,因为同样的插件也必须由C#容器应用程序加载。你想将完整的应用程序用作插件。但Qt插件系统并不是为此而设计的。因此,在基于Qt的容器应用程序和基于Qt的插件之间需要一些中间接口。这个中间接口将隐藏在基于Qt的容器中。Qt远程对象可以提供这个中间接口。
ASSERT failure in QCoreApplication: "there should be only one application object", file H:\...\corelib\kernel\qcoreapplication.cpp, line 792