在非Qt应用程序中使用基于Qt的DLL

dar*_*ron 24 dll qt mfc

我做得对吗?

我的一个客户有一个小组,我正在开发基于Qt的客户端 - 服务器的东西,有很多有趣的小部件和套接字.

公司内的另一个团队希望使用基于QTcpSocket的客户端数据提供程序类的封装版本.(基本上它听起来像,提供从服务器到客户端显示器的数据)

但是,该组有一个巨大的应用程序,主要是使用MFC构建的,这根本不会很快改变.基于Qt的DLL也是延迟加载的,因此在某些配置中可以在没有此功能的情况下部署它.

我有它的工作,但它有点hacky.这是我目前的解决方案:

DLL包装器类构造函数调用QCoreApplication :: instance()以查看它是否为NULL.如果它为NULL,则假定它在非Qt应用程序中,并创建它自己的QCoreApplication实例:

if (QCoreApplication::instance() == NULL)
{
    int argc = 1;
    char* argv[] = { "dummy.exe", NULL };
    d->_app = new QCoreApplication(argc, argv);  // safe?
}
else
    d->_app = NULL;
Run Code Online (Sandbox Code Playgroud)

然后它将设置一个Windows计时器,偶尔调用processEvents():

if (eventTimerInterval > 0)
{
    // STATE: start a timer to occasionally process the Qt events in the event queue
    SetTimer(NULL, (UINT_PTR)this, eventTimerInterval, CDatabaseLayer_TimerCallback);
}
Run Code Online (Sandbox Code Playgroud)

回调只是使用timerID作为指向类实例的指针来调用processEvents()函数.SetTimer()文档说当HWND为NULL时它会忽略timerID,所以这看起来完全有效.

VOID CALLBACK BLAHBLAH_TimerCallback(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
    ((BLAHBLAH*)idEvent)->processEvents(); // basically just calls d->_app->processEvents();
}
Run Code Online (Sandbox Code Playgroud)

然后我将QCoreApplication实例销毁为析构函数中的最后一个东西.

BLAHBLAH::~BLAHBLAH()
{
    .. other stuff

   QCoreApplication* app = d->_app;
   d->_app = NULL;
   delete d;
   if (app != NULL)
       delete app;
}
Run Code Online (Sandbox Code Playgroud)

如果托管应用程序希望对processEvents()本身的调用计时,它可以为eventTimerInterval传递0并调用BLAHBLAH :: processEvents()本身.

有什么想法吗?将该应用程序移植到Qt不是一种选择.这不是我们的.

它似乎有效,但这里可能有几个假设被打破.我可以用这样的伪参数构建一个QCoreApplication吗?事件队列是否可以安全地以这种方式运行?

我不希望以后在我面前爆炸.思考?

das*_*esy 9

研究Qt代码似乎需要QCoreApplication来调度系统范围的消息,例如定时器事件.信号/插槽甚至QThreads之类的东西都不依赖于它,除非它们与那些系统范围的消息有关.以下是我在共享库中的方式(使用Qt本身的跨平台方式),我实际上是调用exec,因为processEvents()本身并不处理所有内容.

我有一个全局命名空间:

// Private Qt application
namespace QAppPriv
{
    static int argc = 1;
    static char * argv[] = {"sharedlib.app", NULL};
    static QCoreApplication * pApp = NULL;
    static QThread * pThread = NULL;
};
Run Code Online (Sandbox Code Playgroud)

我在QObject(即moc'ed)中有一个OpenApp方法,如下所示:

// Initialize the app
if (QAppPriv::pThread == NULL)
{
    // Separate thread for application thread
    QAppPriv::pThread = new QThread();
    // Direct connection is mandatory
    connect(QAppPriv::pThread, SIGNAL(started()), this, SLOT(OnExec()), Qt::DirectConnection);
    QAppPriv::pThread->start();
}
Run Code Online (Sandbox Code Playgroud)

这是OnExec插槽:

if (QCoreApplication::instance() == NULL)
{
    QAppPriv::pApp = new QCoreApplication(QAppPriv::argc, QAppPriv::argv);
    QAppPriv::pApp->exec();
    if (QAppPriv::pApp)
        delete QAppPriv::pApp;
}
Run Code Online (Sandbox Code Playgroud)

到目前为止似乎工作正常,我不确定我是否需要在最后删除应用程序,如果我找到了什么,我会更新我的答案.


Jam*_*mes 1

4.5.2 的 Qt 文档表示 QCoreApplication 的参数需要具有与应用程序对象一样长的生命周期 - 因此您不应该真正使用局部变量。

除了那件小事:

我正在努力解决同样的问题,一切似乎也对我有用。但是,我建议在卸载/退出时非常小心,因为如果您正在使用另一个应用程序的事件循环,并且该事件循环在您的库卸载之前停止,那么当您尝试关闭时,可能会发生各种崩溃的情况。 () 套接字并删除 QObject。