Requirements: Qt widgets show up when Qt shared lib loads, for none-Qt application.
After some web searching, I found:
All Qt widgets must live in "main thread", the "main thread" is the first Qt object created thread. so, create a none-Qt thread (std::thread), then, create QApplication and some other widgets in that thread should work, but not.
Do not create any Qt related object or call any Qt related static methods before QApplication created, in that none-Qt thread.
The thread solution is not portable for Mac OS, my target platform is Windows only, so, it does not matter.
In my case, if app load my Qt lib, and invoke the method for showing widgets, it works. but for some reason, caller can not call my lib method manually.
If host application (one that loads the shared lib) is Qt application, you should call QApplication::processEvents(), not QApplication::exec(). in my case, I should call QApplication::exec() in that thread.
Source code here:
- dllMain version:
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved)
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
auto t = std::thread([]() {
// setCodecForLocale is in the same thread,
// call it before QApplication created should be OK.
QTextCodec::setCodecForLocale(QTextCodec::codecForName("GBK"));
int i = 0;
int argc = 0;
QApplication app(argc, 0);
auto dialogLogin = new DialogLogin(); // custom widget
dialogLogin->setModal(true);
dialogLogin->show();
app.exec(); // app.processEvents() not work, too.
});
t.join(); // wait for thread ends in dllMain should be BAD, test only
}
return true;
}
- Simple C++ static class version
class LibExecutor {
public:
LibExecutor()
{
auto t = std::thread([]() {
QTextCodec::setCodecForLocale(QTextCodec::codecForName("GBK"));
int argc = 0;
QApplication app(argc, 0);
auto dialogLogin = new DialogLogin();
dialogLogin->setModal(true);
dialogLogin->show();
app.exec();
});
t.join();
}
};
static LibExecutor libExecutor;
Both version invoke widgets init stuff successfully, but widgets not show up.
Here is how I test it, using Qt load lib, but, event I load lib using Win32 API, failed too.
#include "mainwindow.h"
#include <QApplication>
#include <QLibrary>
int main(int argc, char* argv[])
{
QLibrary lib("F:/lib_location/lib_name.dll");
if (lib.load()) {
qDebug() << "load ok!";
} else {
qDebug() << "load error!";
}
}
Here is a working example. Tested with Qt 5.12 and MSVC2017 and MinGW.
Note that if you use Qt function before the thread is created, Qt will detect that it is not in the main thread and the process will crash. That is why I do not use
QLibrary.This use case is not supported by Qt. So if you make it work now, you are not guaranteed that it will work in the future.
You cannot load at the same time 2 dll like this.
Depending on what you do in your main application, it could happens that some Qt features are not working as expected. For instance it could happen that Qt expects messages from Windows, but will never get them because they will be handled by the real main thread.
About DllMain
From Windows documentation:
and Dynamic-Link Library Best Practices:
From this I can tell you that you will not be able to create a
QApplicationand run a Qt app fromDllMainfor, at least, the following reasons:qwindows.dll) usingLoadLibrary. If you use any audio or image or sql database, Qt will also try to load the corresponding plugins (e.g.qjpeg.dll).QSettingswith native format.mallocorfree.