Подтвердить что ты не робот

Использование DLL на основе Qt в приложении, отличном от Qt

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

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

Другая группа в компании хочет использовать завернутую версию классов поставщика данных клиентских данных на основе 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;

Затем он будет устанавливать таймер окна, чтобы иногда вызвать 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, он игнорирует таймерID, поэтому это выглядит абсолютно корректным.

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 с такими фиктивными аргументами? Безопасна ли очередь событий для работы таким образом?

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

4b9b3361

Ответ 1

Изучение 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;
}

Пока это работает нормально, я не уверен, что мне нужно удалить приложение в конце, я обновлю свой ответ, если найду что-то.

Ответ 3

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

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

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