qt initialized in the dll
https://forum.qt.io/topic/75214/new-qcoreapplication-crash-in-non-qt-environment
New QCoreApplication crash in non Qt environment
New QCoreApplication crash in non Qt environment
Hi,
I'm using a library written with Qt framework within Matlab. Simple task, I have created a mex file, actual DLL with a single entry point, from which I load my library and issue the calls.
I need a QCoreApplication instance in order to have an event loop. So in my code I test QCoreApplication::instance() and if null I create one. When the last library object has been deleted, I delete the QCoreApplication application I have created.
Without unloading the DLL in between, a new library object can be created after QCoreApplication has been deleted. So I test QCoreApplication::instance() and if null I create one. At this point the program crashes.
I traced down the origin of the crash being in C:\Qt\Qt5.6.0-x64\5.6\Src\qtbase\src\corelib\kernel\qcoreapplication.cpp line 2126.
if (d->argc) {
static const char *procName = d->argv[0];
if (qstrcmp(procName, d->argv[0]) != 0) {
// clear the cache if the procname changes, so we reprocess it.
QCoreApplicationPrivate::clearApplicationFilePath();
procName = d->argv[0];
}
The location of the crash is:
static const char *procName = d->argv[0];
Here is a snippet of my code
QCoreApplication* pQApplication = nullptr;
static int argc = 1;
static char * argv[] = { "sharedlib.app", 0 };
SI_IMPEXP int SI_Load()
if (!QCoreApplication::instance())
QCoreApplication::addLibraryPath("C:/Windows/System32/Specim");
pQApplication = new QCoreApplication(argc, argv);
SI_IMPEXP int SI_Unload()
if (pQApplication)
delete pQApplication;
pQApplication = nullptr;
SI_IMPEXP int SI_Test()
qDebug() << "Test";
}
From reading QCoreApplication source code, I now understand argv cannot change during the process lifetime. So I declared it as a global static member.
I do the following sequence and check the memory location of argv. Here is an example of memory location
SI_Load: argv = 0x000007fee
3fd
7008 {0x000007fee3
fa
2c00 "sharedlib.app", 0x0000000000000000 <NULL>}
SI_Test: argv = 0x000007fee
3fd
7008 {0x000007fee3
fa
2c00 "sharedlib.app", 0x0000000000000000 <NULL>}
SI_Unload argv = 0x000007fee
3fd
7008 {0x000007fee3
fa
2c00 "sharedlib.app", 0x0000000000000000 <NULL>}
SI_Load argv = 0x000007fee
396
7008 {0x000007fee3
93
2c00 "sharedlib.app", 0x0000000000000000 <NULL>} <--
new argv
allocation – QcoreApplication constructor will crash since the already initialized *
static const char procName
points to old memory.
Each of these call are run from the same thread and same process ID. argv is reallocated only after SI_Unload has returned.
I'm puzzled. How could deleting QCoreAppliction instance change a global static variable allocation? I'm I missing something fundamental?
I hope someone can enlighten me.
Thanks.
I am pretty new to Qt. I am using Qt and the Qt plugin for Visual Studio 2010. I am creating a multi-library project that involves plugins and interfaces. While solving an earlier problem I temporarily set one of the dll projects (BuilderCore) to build a static library. I got it to build fine but I noticed I was missing one of the dlls in the Win32 Debug folder. I realized that I was still doing a static library build for that particular project. So I changed it back to the dll version.
As soon as I changed it back I got 7 linking errors. I have tried all the "removing Q_OBJECT" as many LNK2019 and LNK2001 articles have suggested and then adding back. I have tried compiling with and without the Q_OBJECT in the derived class without success.
Some possibly important information. The IBuilderRole "interface" class is located in the BuilderCore dll (that was originally statically linked when it worked). It is derived from QObject and a basic ground level BuilderObject class that defines all classes that need specific object information stored for use in scripting and events that will occur within the application. The BuilderClient class is derived from the IBuilderRole interface and is in its own separate dll. All functions listed have been implemented in a cpp file.
Here is the IBuilderRole header: namespace BuilderCore {
class IBuilderRole : public QObject, BuilderObject Q_OBJECT
public: IBuilderRole(const char* derivedRoleName, int roleID); virtual ~IBuilderRole(); QList<IBuilderMode*>& GetModes() const; QList<QAction*>& GetActions() const; BuilderRoles GetRole() const;
signals: void RoleAdded(); // triggered when Role has been initialized void RoleReady(); // triggered when Role is ready to begin void RoleStarted(); // triggered when Role has first started void RoleBeginRemove(); // triggered when Role needs to end void RoleEndRemove(); // triggered when Role has ended void RoleCleared(); // triggered just before dynamic library is unloaded
public: virtual void AddRole() = 0; virtual void SetupRole() = 0; virtual void Start() = 0; virtual void Stop() = 0; virtual void ShutdownRole() = 0; virtual void RemoveRole() = 0;
protected: QList<IBuilderMode*>& mModes; QList<QAction*>& mActions; BuilderRoles mRole; };
}
Q_DECLARE_INTERFACE(BuilderCore::IBuilderRole, "BuilderRoleInterface/1.0") @
Here is the BuilderClient class header. Note that I have experimented with the Q_OBJECT line with and without the comment marks. Without the comment line it it says "undefined interface" in reference to the Q_INTERFACES line. Adding the BuilderCore:: namespace in front of IBuilderRole in this line gets rid of that error but goes back to the problem with linking. namespace BuilderCore {
class BUILDERCLIENT_EXPORT BuilderClient : public IBuilderRole //Q_OBJECT Q_INTERFACES(IBuilderRole)
public: BuilderClient(); ~BuilderClient();
public: virtual void AddRole(); virtual void SetupRole(); virtual void Start(); virtual void Stop(); virtual void ShutdownRole(); virtual void RemoveRole();
private: // Nothing yet... @
Here are the link errors I am getting: 3> Creating library D:\Developing\Projects\IMT\Rosweld\trunk\Source\Builder\Win32\Debug\BuilderClient.lib and object D:\Developing\Projects\IMT\Rosweld\trunk\Source\Builder\Win32\Debug\BuilderClient.exp 3>builderclient.obj : error LNK2019: unresolved external symbol "public: __thiscall BuilderCore::IBuilderRole::IBuilderRole(char const *,int)" (??0IBuilderRole@BuilderCore@@QAE@PBDH@Z) referenced in function "public: __thiscall BuilderCore::BuilderClient::BuilderClient(void)" (??0BuilderClient@BuilderCore@@QAE@XZ) 3>builderclient.obj : error LNK2001: unresolved external symbol "public: virtual struct QMetaObject const * __thiscall BuilderCore::IBuilderRole::metaObject(void)const " (?metaObject@IBuilderRole@BuilderCore@@UBEPBUQMetaObject@@XZ) 3>builderclient.obj : error LNK2001: unresolved external symbol "public: virtual void * __thiscall BuilderCore::IBuilderRole::qt_metacast(char const *)" (?qt_metacast@IBuilderRole@BuilderCore@@UAEPAXPBD@Z) 3>builderclient.obj : error LNK2001: unresolved external symbol "public: virtual int __thiscall BuilderCore::IBuilderRole::qt_metacall(enum QMetaObject::Call,int,void * *)" (?qt_metacall@IBuilderRole@BuilderCore@@UAEHW4Call@QMetaObject@@HPAPAX@Z) 3>builderclient.obj : error LNK2019: unresolved external symbol "public: virtual __thiscall BuilderCore::IBuilderRole::~IBuilderRole(void)" (??1IBuilderRole@BuilderCore@@UAE@XZ) referenced in function "public: virtual __thiscall BuilderCore::BuilderClient::~BuilderClient(void)" (??1BuilderClient@BuilderCore@@UAE@XZ) 3>builderclient.obj : error LNK2019: unresolved external symbol "public: void __thiscall BuilderCore::IBuilderRole::RoleAdded(void)" (?RoleAdded@IBuilderRole@BuilderCore@@QAEXXZ) referenced in function "public: virtual void __thiscall BuilderCore::BuilderClient::AddRole(void)" (?AddRole@BuilderClient@BuilderCore@@UAEXXZ) 3>D:\Developing\Projects\IMT\Rosweld\trunk\Source\Builder\Win32\Debug\BuilderClient.dll : fatal error LNK1120: 6 unresolved externals @
The only thing I can think of (but I don't know how to do) is that perhaps the moc files for the BuilderCore class would be needed for the derived builderclient class as well?
UMMM... DUH... I cannot believe I overlooked the missing Export tag... I only noticed it after posting this and looking at the two together. Anyway... this is the only post I have found on the internet that talks about this kind of problem occuring only after switching from static to dynamic so I guess I will just leave it up. Maybe someone else will benefit from this ridiculous error on my part.
So here is the solution: I forgot to declare the class an export by using the QT define generated when the project first gets made. The class line of the first file (Interface) should read:
class BUILDERCORE_EXPORT IBuilderMode : QObject, BuilderObject
Qt 5.1: QWinMigrate does not process events correctly in Dll project
RolandWinklmeier 2013年7月16日 下午4:46
Good morning everyone,
I'm using Qt since years now and it was always straight forward. I really love this library :)
But currently I have a problem with a project being migrated to Qt5.1 from Qt4. One part of this project is a plugin for an existing MFC application. To be able to launch dialogues in within this plugin I had used the QWinMigrate library and it worked very well with Qt4.
Now I have migrated to Qt5.1 and it seems QWinMigrate does not process queued events anymore. It is reproducible with the examples in QWinmigrate. I did the following:
- Build the project in 'qt-solutions\qtwinmigrate\examples\mfc\step1'
- Ammend example qtdll to create and show a dialog instead of the MessageBox and build it:
@ [...]
QWinWidget * g_win;
// Dialog with an OK and a Cancel Button. Class definition is skipped here. CDialog *g_dialog;
BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID / lpvReserved / ) static bool ownApplication = FALSE;
if ( dwReason == DLL_PROCESS_ATTACH )
ownApplication = QMfcApp::pluginInstance( hInstance ); if ( dwReason == DLL_PROCESS_DETACH && ownApplication ) delete g_dialog; delete g_win; delete qApp;
}
return TRUE;
}
extern "C" __declspec(dllexport) bool showDialog( HWND parent ) g_win = new QWinWidget( parent ); g_win->showCentered();
g_dialog = new CDialog(win);
g_dialog->show();
} @
If you run now the MFC executable build in step 1 and press on "about" it should load the library "qtdialog.dll" which itself open the child CDialog. But then, CDialog is completely unresponsive. You can click on the buttons, etc but nothing happens, not even close. Not any of the events are processed.
Only if I move or resize the parent MFC window or something similar, events of the child are processed.
I rechecked with Qt 4.8.4 and with this one everything is fine, but Qt 5.1 has this weird behavior.
I looked into the code of class QMFCApp. Qt's event loop is triggered by installing a hook procedure monitoring WH_GETMESSAGE: QT_WA({ hhook = SetWindowsHookExW(WH_GETMESSAGE, QtFilterProc, 0, GetCurrentThreadId()); hhook = SetWindowsHookExA(WH_GETMESSAGE, QtFilterProc, 0, GetCurrentThreadId()); @
which fires the following callback and triggers the event processing:
@ LRESULT CALLBACK QtFilterProc(int nCode, WPARAM wParam, LPARAM lParam) if (qApp) { // don't process deferred-deletes while in a modal loop