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

时间:2010-01-27 21:46:18

标签: qt dll 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;

然后它将设置一个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);
}

回调只是使用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();
}

然后我将QCoreApplication实例销毁为析构函数中的最后一件事。

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

   QCoreApplication* app = d->_app;
   d->_app = NULL;
   delete d;
   if (app != NULL)
       delete app;
}

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

对此有何想法?将该应用程序移植到Qt不是一种选择。这不是我们的。

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

我不希望以后在我面前爆炸。想法?

2 个答案:

答案 0 :(得分: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;
};

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

这是 OnExec 插槽:

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

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

答案 1 :(得分:1)

4.5.2的Qt文档说QCoreApplication的参数需要有生命周期,只要应用程序对象 - 所以你不应该真正使用局部变量。

除了那件小事:

我正在努力解决同样的问题,而且一切似乎对我也有用。我建议在卸载/退出时非常小心,因为如果你正在使用来自另一个应用程序的事件循环并且在卸载库之前停止了事件循环,那么当你试图关闭时会发生各种各样的肮脏的肮脏()套接字并删除QObjects。