Использование библиотеки на основе Qt в не-Qt-приложении - PullRequest
24 голосов
/ 28 января 2010

Я правильно делаю?

У моего клиента есть группа, в которой я разрабатываю клиент-серверные материалы на основе Qt с множеством забавных виджетов и сокетов.

Другая группа внутри компании хочет использовать упакованную версию клиентских классов провайдеров данных на основе QTcpSocket. (Что делает в основном то, на что это похоже, предоставляет данные с сервера на клиентские дисплеи)

Однако у этой группы есть огромное приложение, построенное в основном из MFC, и это просто не изменится в ближайшее время. DLL-библиотека на основе Qt также загружается с задержкой, поэтому ее можно развернуть без этой функции в определенных конфигурациях.

У меня это работает, но это немного глупо. Вот мое решение на данный момент:

Конструктор класса 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);
}

Обратный вызов просто вызывает функцию processEvents (), используя timerID в качестве указателя на экземпляр класса. Документы 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 (), оно может передать 0 для eventTimerInterval и вызвать BLAHBLAH :: processEvents ().

Есть мысли по этому поводу? Портирование этого приложения на Qt не вариант. Это не наше.

Кажется, это работает, но, возможно, здесь нарушено несколько предположений. Могу ли я просто создать QCoreApplication с фиктивными аргументами, подобными этому? Безопасно ли работать таким образом в очереди событий?

Я не хочу, чтобы это взорвалось мне в лицо позже. Мысли?

Ответы [ 2 ]

9 голосов
/ 03 мая 2012

Изучая код 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;
};

У меня есть OpenApp метод в QObject (это moc'ed), подобный этому:

// 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 голос
/ 12 августа 2010

Документация Qt для 4.5.2 гласит, что аргументы QCoreApplication должны иметь время жизни, равное периоду объекта приложения, поэтому вам не следует использовать локальные переменные.

Помимо этой мелочи:

Я борюсь с той же проблемой, и, похоже, у меня все работает. Однако я бы порекомендовал быть очень осторожным во время выгрузки / выхода, поскольку, если вы используете цикл обработки событий из другого приложения и этот цикл обработки событий останавливается до выгрузки вашей библиотеки, то при попытке закрытия могут возникнуть всевозможные ошибки () сокеты и удалить объекты QObject.

...