Добрый день!
Для меня он вышел не очень добрым, 10 часов из жизни потрачено в поисках решения на простой вопрос, но в конечном счете я его нашел, и сейчас поделюсь с вами.
Итак, краткая предыстория.
Один мой заказчик попросил разработать kiosk-mode приложение на Qt. И для начала, сделать версию для POS-терминала с ОС Windows XP.
Ok, за неделю я что-то сверстал по приложенным макетам и попробовал отдать версию заказчику. Приложив Qt5Core.dll, Qt5Gui.dll, ну и прочие .dll используемых модулей Qt.
«Failed to load platform plugin „windows“» сказалаяпонскаяфинская бензопила.
Ага, идем в гугл.
Во-первых, официальная документация:
qt-project.org/doc/qt-5.0/qtdoc/deployment-windows.html
Она не очень помогла, пошел читать форумы на qt-project.org. Вот предлагаемые решения:
1) скопировать /qtbase/plugins/platforms/qwindows.dll в папку приложения в каталог platforms или platform
попробовал, не работает
2) скопировать /qtbase/plugins/platforms/qwindows.dll в папку приложения в каталог plugins/platforms, plugins/platform
не работает
3) выставить переменную окружения QT_QPA_PLATFORM_PLUGIN_PATH, указать в ней путь до папки с qwindows.dll
заработало. Но: я не хочу модифицировать переменные среды при установке на компьютер пользователя. Во-первых, пользователь может удалить ее — а так как приложение падает при загрузке, проверить ее наличие я даже и не смогу без костылей. Во-вторых, пользователь может установить приложение с другой версией Qt — и привет, глюки и несовместимости.
4) решение из официальной документации. При инициализации приложения в функции main() добавить строчку вида:
qApp это наш QApplication. Не заработало.
5) использовать аргумент командной строки "-platformpluginpath \«путь_к_папке_с_qwindows.dll\»"
проверил. работает. Вуаля! Вот решение! (что оказалось неправдой)
Правим скрипт innosetup, вот так:
отдаем заказчику, радуемся.
Рано радуемся, не работает sqlite. подкладывание в plugins\sqldrivers, просто sqldrivers не помогло — не видит и не загружает, вот такой код:
выпадал с ошибкой. Ни переменной среды, ни аргумента командной строки для sql плагинов я не нашел.
Вернулся к официальной документации и подумал. А собственно почему статический метод мы вызываем из экземпляра?
А раз он статический, может его можно вызвать до создания экземпляра?
Вот такой код наконец работает:
Кстати, встречал еще вот такой способ задания пути:
но он работает некорректно, так как QCoreApplication::applicationDirPath() выдает warning, если экземпляр QApplication еще не создан.
И собственно секция «Files» в InnoSetup выглядит так:
Статья не претендует на всеобъемлющее исследование, но корректного работающего решения я не нашел и поэтому решил опубликовать свое.
Спасибо за внимание!
Для меня он вышел не очень добрым, 10 часов из жизни потрачено в поисках решения на простой вопрос, но в конечном счете я его нашел, и сейчас поделюсь с вами.
Итак, краткая предыстория.
Один мой заказчик попросил разработать kiosk-mode приложение на Qt. И для начала, сделать версию для POS-терминала с ОС Windows XP.
Ok, за неделю я что-то сверстал по приложенным макетам и попробовал отдать версию заказчику. Приложив Qt5Core.dll, Qt5Gui.dll, ну и прочие .dll используемых модулей Qt.
«Failed to load platform plugin „windows“» сказала
Ага, идем в гугл.
Во-первых, официальная документация:
qt-project.org/doc/qt-5.0/qtdoc/deployment-windows.html
Она не очень помогла, пошел читать форумы на qt-project.org. Вот предлагаемые решения:
1) скопировать /qtbase/plugins/platforms/qwindows.dll в папку приложения в каталог platforms или platform
попробовал, не работает
2) скопировать /qtbase/plugins/platforms/qwindows.dll в папку приложения в каталог plugins/platforms, plugins/platform
не работает
3) выставить переменную окружения QT_QPA_PLATFORM_PLUGIN_PATH, указать в ней путь до папки с qwindows.dll
заработало. Но: я не хочу модифицировать переменные среды при установке на компьютер пользователя. Во-первых, пользователь может удалить ее — а так как приложение падает при загрузке, проверить ее наличие я даже и не смогу без костылей. Во-вторых, пользователь может установить приложение с другой версией Qt — и привет, глюки и несовместимости.
4) решение из официальной документации. При инициализации приложения в функции main() добавить строчку вида:
qApp->addLibraryPath("C:/customPath/plugins");
qApp это наш QApplication. Не заработало.
5) использовать аргумент командной строки "-platformpluginpath \«путь_к_папке_с_qwindows.dll\»"
проверил. работает. Вуаля! Вот решение! (что оказалось неправдой)
Правим скрипт innosetup, вот так:
[Files]
...
Source: "..\build\deploy\platforms\qwindows.dll"; DestDir: "{app}\platforms"; Flags: ignoreversion
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\TryumPosWin.exe"; Parameters:"-platformpluginpath \"{app}\platforms\"" ; WorkingDir: "{app}";
отдаем заказчику, радуемся.
Рано радуемся, не работает sqlite. подкладывание в plugins\sqldrivers, просто sqldrivers не помогло — не видит и не загружает, вот такой код:
if (QSqlDatabase::isDriverAvailable("QSQLITE")){
qDebug("QSqlite driver found.");
} else {
qFatal("QSqlite driver NOT found!");
}
выпадал с ошибкой. Ни переменной среды, ни аргумента командной строки для sql плагинов я не нашел.
Вернулся к официальной документации и подумал. А собственно почему статический метод мы вызываем из экземпляра?
А раз он статический, может его можно вызвать до создания экземпляра?
Вот такой код наконец работает:
int main(int argc, char *argv[])
{
Q_INIT_RESOURCE(resources);
QStringList paths = QCoreApplication::libraryPaths();
paths.append(".");
paths.append("imageformats");
paths.append("platforms");
paths.append("sqldrivers");
QCoreApplication::setLibraryPaths(paths);
QApplication a(argc, argv);
a.setQuitOnLastWindowClosed(false);
QDbc::init();
MainWindow w;
w.showFullScreen();
a.exec();
QDbc::finalize();
}
Кстати, встречал еще вот такой способ задания пути:
paths.append(QCoreApplication::applicationDirPath() + "/plugins");
но он работает некорректно, так как QCoreApplication::applicationDirPath() выдает warning, если экземпляр QApplication еще не создан.
И собственно секция «Files» в InnoSetup выглядит так:
[Files]
Source: "..\build\deploy\icudt51.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\deploy\icuin51.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\deploy\icuuc51.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\deploy\libEGL.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\deploy\libGLESv2.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\deploy\msvcp100.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\deploy\msvcr100.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\deploy\Qt5Core.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\deploy\Qt5Gui.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\deploy\Qt5Network.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\deploy\Qt5Sql.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\deploy\Qt5Widgets.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\build\deploy\imageformats\qico.dll"; DestDir: "{app}\imageformats"; Flags: ignoreversion
Source: "..\build\deploy\platforms\qwindows.dll"; DestDir: "{app}\platforms"; Flags: ignoreversion
Source: "..\build\deploy\sqldrivers\qsqlite.dll"; DestDir: "{app}\sqldrivers"; Flags: ignoreversion
Статья не претендует на всеобъемлющее исследование, но корректного работающего решения я не нашел и поэтому решил опубликовать свое.
Спасибо за внимание!