Using a Qt-based DLL in a non-Qt application

dll, mfc, qt

Solution

Studying the Qt code it seems QCoreApplication is needed to dispatch system-wide messages such as timer events. Things like signal/slots and even QThreads do not depend on it unless they are related to those system-wide messages. Here is how I do this in a shared library (in a cross platform way using Qt itself) and I actually do call exec, because processEvents() alone does not process everything.

I have a global namespace:

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

I have an OpenApp method in a QObject (that is moc'ed) like this:

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

And here is OnExec slot:

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

So far it seems to be working fine, I am not sure if I need to delete the app at the end, I will update my answer if I find something.

Problem

Am I doing it right? A client of mine has a group where I'm developing Qt-based client-server stuff with a lot of fun widget stuff and sockets. Another group within the company wants to use a wrapped version of the QTcpSocket-based client data provider classes. (Which does basically what it sounds like, provides data from the server to the client displays) However, that group has a huge application built mostly with MFC, and that is simply not going to change any time soon. The Qt-based DLL is also delay-loading so that it can be deployed without this feature in certain configurations. I've got it working, but it's a little hacky. Here's my solution at the moment: The DLL wrapper class constructor calls QCoreApplication::instance() to see if it's NULL or not. If it's NULL, it assumes it's in a non-Qt app, and creates a QCoreApplication instance of it's own: ``` if (QCoreApplication::instance() == NULL) { int argc = 1; char* argv[] = { "dummy.exe", NULL }; d->_app = new QCoreApplication(argc, argv); // safe? } else d->_app = NULL; ``` It then will set up a windows timer to occasionally call 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); } ``` The callback simply calls the processEvents() function using the timerID as a pointer to the class instance. The SetTimer() docs say when HWND is NULL it ignores the timerID, so this appears to be perfectly valid. ``` VOID CALLBACK BLAHBLAH_TimerCallback(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { ((BLAHBLAH*)idEvent)->processEvents(); // basically just calls d->_app->processEvents(); } ``` I then destroy the QCoreApplication instance as the very last thing in the destructor. ``` BLAHBLAH::~BLAHBLAH() { .. other stuff QCoreApplication* app = d->_app; d->_app = NULL; delete d; if (app != NULL) delete app; } ``` If the hosting application wishes to time the calls to processEvents() itself, it can pass 0 in for eventTimerInterval and call BLAHBLAH::processEvents() itself. Any thoughts on this? Porting that app to Qt is not an option. It's not ours. It appears to work, but there are probably several assumptions being broken here. Can I just construct a QCoreApplication with dummy arguments like that? Is the event queue safe to operate in this manner? I don't want this blowing up in my face later. Thoughts?

Original source