PDA

View Full Version : QWidget: Must construct a QApplication before a QPaintDevice crash error



eric_vi
10th July 2012, 02:44
i am having 2 different plug-ins that work inside a non QT application... as long as i stay in debug mode all fine... when i go to release and deploy them... as long as i use the same plug in all fine...
when i start switching from one of the plug-in to the other i start to get this QWidget: Must construct a QApplication before QPaintDevice ... i am sure my QApplication has been created before i checked it out

it sounds more like the frameworks which are exactly the same (but dynamic, deployed and independent for each plug-in) are not unloaded and create a conflict

I taht possible? how can you make sure when you quit one plug-in that use QT frameworks without quitting the application that has launched the plug-in that there cannot be conflict of frameworks with a subsequent plug-in that is launched in the same session

ChrisW67
10th July 2012, 04:41
I have no idea what, "I taht possible?" is referring to or, indeed, much of what your post is trying to say.

What do you mean by "plug-ins that work inside a non QT application"? Are you talking about ActiveX controls on Windows or something else?
What do you mean by , "switching from one of the plug-in to the other"? Do you mean moving focus between widgets presented by the "plug-ins", loading and unloading the "plug-ins", or something else?

Where and how is the (singular) QApplication instance created? Where and how is that QApplication instance destroyed?

high_flyer
10th July 2012, 09:38
I think what he is trying to say is, that he has a non Qt application, which uses plugins which link to Qt.
This will also account to the sort of the problem he (probably) refers to regarding the construction of a QApplication.

@OP
Do you need to use Qt GUI facilities or services that need an event loop?
Consider very good what you relay need in your Qt plugins, it might be that you can get rid of all the event loop dependent code, which will free you from the need to have an instantiated QApplication/QCoreApplication in your plugins.

eric_vi
10th July 2012, 13:48
Hello again, thank you,

yes i have non Qt application (not made by me so i have no control over it. This application can call plugins following a user interaction. So a user can decide to launch a plug-in... Those plug-in use QT and do have a user interface and multiple QT frameworks are needed ( i do not use static QT frameworks)

i have sub classed QApplication



class myQApplication : public QApplication
{
public:
myQApplication(int &argc, char **argv);

protected:
bool event(QEvent *);

};


and as soon as the plug-in starts before any event loop i call
my_qapp = new myQApplication(argc, argv);


then my event loop

when i quit the plug-in i do
delete my_qapp;


All this works perfectly well in debug mode..

when i go to release i need to deploy it so each plug-in has its own copy of the frameworks.

In release mode, as long as i use one plug-in, ii can do multiple launch and quit, all works fine. The problem occurs when i quit one of the plug-in and launch the second one... i got this error message
and in console i can see some message that says that the framework of plug-in number 1 or the framework or plug-in number 2 might be used and that is where i am getting really confused.

high_flyer
10th July 2012, 14:23
There are some things you are not saying - for example, where/when (if at all?) you start the the QApplication event loop? (exec())


Try calling quit() on your QApplication before you delete it in your DLL, see if this helps.

eric_vi
10th July 2012, 15:01
the application uses only one plug-in at a time..


there are not many steps.. the crash occurs during the initialisation of my QMainWindow
as i am giving a minimum and a maximum size (setMinimumSize...)

so i have not reached the even loop yet



{
MainWindow *w;

my_qapp = new myQApplication(argc, argv);

// MainWindow is a sub class of QMainWindow
w = new MainWindow();

my_qapp->exec();


}



i do have any quit() when i delete my QApplication at exit time i will try that

amleto
10th July 2012, 17:19
{
MainWindow *w;

my_qapp = new myQApplication(argc, argv);

// MainWindow is a sub class of QMainWindow
w = new MainWindow();

my_qapp->exec();
}


what is this I dont even...

correct:


int main(int argc, char** argv) // please include method name etc so we have some context!!
{
myQApplication my_qapp(argc, argv);

// MainWindow is a sub class of QMainWindow
MainWindow w;
w.show()

my_qapp.exec();
}

This is not java, dear.

eric_vi
10th July 2012, 21:14
i don't know about java... i had it this way before but because of this bug i was not exactly sure where the objects would be created so i tried with a 'new' allocator to see if it was making any difference

eric_vi
11th July 2012, 04:22
i tried to put a quit() when deleting the QApplication... this does not make any change...

when within the same session i quit one plug-in to launch another (each of those plug-in are deployed and have their own set of frameworks) I get this QWidget: Must construct a QApplication before a QPaintDevice crash error... i am running on Mac OS and if i examine the console log i can see that during the launch of plugin 2 i get multiple warnings such as

objc[722]: Class QNSStatusItem is implemented in both /Library/Application Support/plugin1/Frameworks/QtGui.framework/Versions/4/QtGui and /Library/Application Support/plugin2/Frameworks/QtGui.framework/Versions/4/QtGui. One of the two will be used. Which one is undefined.


i really have no clue why the frameworks from the previous plug-in launch can still be used!

high_flyer
11th July 2012, 10:32
Without seeing the real code its hard to tell.

eric_vi
11th July 2012, 21:37
i have described what the code is doing there is not much more to it

but let me describe again my issue, hopefully someone can give me some hints, because i am totally stuck...


i am in a deployed configuration (in debug mode i have no problem at all, since i am always using a unique framework).

i have an application (non QT), that launch thru user interaction PlugIn1 (QTmade that has been deployed and point to his own set of QT frameworks), all is fine so far...
the user quits PlugIn1 ( doing so the QApplication from PlugIn1 is deleted and i added a quit()), the Plugin1 process is gone and the user returns to the main application then launch plugIn2 (which is similar to PlugIn 1, deployed with its own set of QT frameworks)...
When launching PlugIn2... i can see in console mode a warning that QT might still use the frameworks of PlugIn1 (!!!!), and of course if it does so i got the QApplication before a QPaintDevice error, since PlugIn1 is no longer there and has been quitted before.

so my question... how can i make sure the qt framework binaries are not going to be used anymore when i quit a plug-in working on QT frameworks that is used within an application, because so far it does not seem to happen for me.

wysota
11th July 2012, 22:18
how can i make sure the qt framework binaries are not going to be used anymore when i quit a plug-in working on QT frameworks that is used within an application
The only way I know is to statically link Qt to your plugin. Otherwise always the first loaded instance of the framework will be used because libraries (as far as I know) once loaded into the process, stay there until the process quits. Therefore when plugin2 needs to resolve its Qt symbols, it does so against the set of libraries loaded for plugin1.

However I doubt this would give you the warning you receive. I'd say you were not freeing all the resources from plugin1 properly. I would also not delete the application object instance, I don't see the point of doing so -- you can reuse the same instance that the previous plugin used.

eric_vi
12th July 2012, 00:17
i might not been freeing them correctly i agree that is highly possible...

how can i for example free the whole QTCore, QTGui etc..

wysota
12th July 2012, 09:11
how can i for example free the whole QTCore, QTGui etc..
I'm not talking about libraries but rather objects. Without seeing what you really do it is hard to suggest anything. For instance you need to make sure you delete all the widgets you use. This is bookkeeping that you have to do on your own. Other than that I think the whole "plugin" concept you have is incorrect but again without knowing the big picture, I'm not able to say more.

high_flyer
12th July 2012, 09:34
Otherwise always the first loaded instance of the framework will be used because libraries (as far as I know) once loaded into the process, stay there until the process quits.
Unless you unload them.


Therefore when plugin2 needs to resolve its Qt symbols, it does so against the set of libraries loaded for plugin1.
Are you sure about that witek?
To my knowledge, each DLL is a process of its own - as I wrote in my previous post - each DLL is equivalent to an exe, AFAIK.

wysota
12th July 2012, 09:56
Unless you unload them.
I don't know any way of unloading a library that was loaded by the linker. You don't even have any "handle" to the library so I don't know how you'd like to unload "library X".


Are you sure about that witek?
To my knowledge, each DLL is a process of its own - as I wrote in my previous post - each DLL is equivalent to an exe, AFAIK.
When a DLL is loaded, it occupies some memory. Then this memory is being attached to every process that requests this library to be present. Therefore each DLL is loaded into memory only once and can be attached to multiple processes. There is no flow in the DLL itself, it is just a blob of code so it is not like a process -- it doesn't have its own stack, nor heap nor set of registers (and thus no instruction pointer). If you try to load the same library again, it is not loaded because it is already there. If one loads a library called "QtCore" then if someone (e.g. another library) requests a library called "QtCore" to be loaded again, the one that's already there will be used.

Now another thing is whether requesting library X loads it into memory or uses one that looks like X that is already present in the memory. This decision has to be made when the required symbol is not already loaded into the process. If we assume that libraries are not automatically unloaded when nobody wants to use it anymore (and I think that's the case) then if you request a symbol that is in the library (like "QApplication") then it is being resolved from the library that is already loaded.

So the bottom line is that unless MacOSX does something really weird with regard to frameworks then symbols from plugin2 are being resolved against Qt libs loaded by plugin1. I don't know what happens when the application explicitly unloads plugin1 (we don't know if that happens in this particular case), maybe it would unload Qt libs as well as I'd expect that the system holds a reference counter for each attached library on behalf of each process which at least seems to be happening on Linux -- as far as dlopen() manual is concerned. But I'm assuming plugin1 is simply not unloaded at all. In other words we don't know if an equivalent of dlclose() is called on the handle of the plugin1 library and whether it works.

high_flyer
12th July 2012, 10:24
I don't know any way of unloading a library that was loaded by the linker. You don't even have any "handle" to the library so I don't know how you'd like to unload "library X".
Under windows at least you do get a handle to your DLL.
A reference count is done for the used instances, and when you call FreeLibrary() if the reference is 0, the DLL is removed from your apps memory.
In such a scenario, a reference to a QApplication object would be lost in the calling application as well. (I'd expect).

wysota
12th July 2012, 10:39
Under windows at least you do get a handle to your DLL.
Only if you load it explicitly. Not if it's loaded implicitly by the linker. Try writing a simple application that links with QtCore and unload that library while running the program. In other words, modify this code:


#include <stdio.h>

int main(int argc, char **argv) {
getchar();
return 0;
}

SOURCES += main.cpp
QT = core

... and make it unload QtCore before the call to getchar().

high_flyer
12th July 2012, 10:45
That is correct - but plugins are explicitly loaded, at least when I implement them, that is the whole point with plugins. :)

wysota
12th July 2012, 11:08
That's why I said that all depends on whether the plugin is explicitly unloaded or not. If not then you can't unload Qt that is implicitly loaded by the plugin.

high_flyer
12th July 2012, 11:10
That's why I said that all depends on whether the plugin is explicitly unloaded or not.
Agreed.
I thought calling quit() on the application might force the freeing of any resources QApplication might have - but I didn't really checked in depth.

wysota
12th July 2012, 11:21
quit() only leaves the event loop. You can still access all its data or re-enter the loop. However even destroying the application object will not unload the plugin as one has nothing to do with the other.

high_flyer
12th July 2012, 11:25
However even destroying the application object will not unload the plugin as one has nothing to do with the other.
True.
It was not means as unloading the plugin but forcing resource releasing by QApplication - which as you just claimed is not happening.
The OP has to make sure manually that all resources are freed before unloading the plugin.

wysota
12th July 2012, 11:34
My bet is he has no influence on if his plugin is unloaded or not as it is done (or not) by that other application. Based on what happens I would guess it is not unloaded at all.

high_flyer
12th July 2012, 12:42
@OP
One solution might be to check for a valid QApplication instance in your plugin (qApp is global ) and only initialize QApplication if it is not yet initialized.
If we follow on the logic of what wysota said, the qApp context should be in the context of the calling application, thus still valid when you unload one plugin and load another.

eric_vi
12th July 2012, 18:22
well i am not in control of the application that is loading my plug-ins... i am nearly 100% sure this application is unloading the plug-in that has just been used and closed... but i am going to ask the maker of this app the question.

I am quite sure all my widgets are closed but i will remove some code and will try just to keep a loading/int then exiting phease without user interaction and see if it makes a difference.
I tried to place a quit() as i am deleting the QApplication but there is no change, i cannot keep static the address of the first allocation of QApplication the second plug-in as nothing to do with the first.

Now again when i load my second plug-in i can see in the console mode that the frameworks of the first one might still be used...

I could have a common framework for all my plug-ins and that will work for me but what if someone else build a plug-in for this app using QT, i will have my framework to be confused with his ... so i guess for plug-ins having the frameworks static might be the only way.

wysota
12th July 2012, 18:33
i am nearly 100% sure this application is unloading the plug-in that has just been used and closed...
I am nearly 100% sure it doesn't.


I am quite sure all my widgets are closed
If you close a widget, it doesn't get deleted. You need to make sure every bit of QPaintDevice is deleted.

eric_vi
12th July 2012, 21:48
hi thanks

yes you right they told me they don't unload plug-ins that were used



i meant by close deleted... i am going to check if i miss some ... i thought deleting the QApplication would do a global cleaning but you are saying not so i have to check more carefully

high_flyer
12th July 2012, 23:28
I tried to place a quit() as i am deleting the QApplication but there is no change, i cannot keep static the address of the first allocation of QApplication the second plug-in as nothing to do with the first.
You don't have to, Qt does it for you.
There is a qApp global pointer which hold the address of the instantiated QApplication.
You can check against that qApp pointer.
So you don't need to delete your QApplication, just allocate it once if qApp == NULL.

wysota
12th July 2012, 23:39
... just make it QApplication and not MyApplication. Keep your environment clean.

eric_vi
20th July 2012, 23:10
by testing qApp i have been making sure that i have QApplication created only once, when the plug-in 1 is loaded at the beginning , i do not delete qApplication leaving the first plug-in...

unfortunately this does not solve my issue..

I can still see in console mode when my plug-in 2 loads that the different classes might use the qt frameworks (core/gui etc..) of the plug-in 1 or plug-in 2 (it is undefined)... a segmentation fault quickly follows...

any other ideas?

wysota
20th July 2012, 23:36
Maybe we should have asked it earlier... Does it work if you compile plugin2 against the same set of Qt libraries plugin1 is built against?

eric_vi
21st July 2012, 15:07
Thnks again for your continuous help...

yes in debug mode all works fine since everything goes toward the same qt frameworks... then i deploy (using otools etc..., i am very familiar with this process)... If i deploy each plug-in toward the same set of frameworks, all is good... no warning no crash. Unfortunately for other installation reasons even if the frameworks are exactly the same, i need to duplicate and have one set of framework assigned per plug-in... So in this configuration if i use plug-in 1 only or plug-in 2 only, i can launch/close them over and over without issue... (no warning on console, all good)
it is only when i launch plug-in 1 then quit the plug-in 1, then launch plug-in 2... (or vice versa, launch first plug-in 2, then plug-in 1) that i got the console message and then the crash... and again now i do not delete the qApp when quitting the plug-in and i test if qApp is not NULL at the launch of each plug-in so i do not create 2 qApplication and i use the qApplication that has been created by the first plug-in launched, (that part works well, but does not seem to prevent the confusion between the frameworks of plug-in 1 and plug-in 2)

eric_vi
24th July 2012, 19:06
update... i rebuilt my plug-ins with static libraries instead of external frameworks thinking it would solve my issue.... (also those 2 plug-ins are exactly identical only difference is their name)

unfortunatly not working..

launching one of the plug-in after the other i get in console.. many similar messages with various classes
Class QCocoaColorPanelDelegate is implemented in both /Applications/xxxapp/Plug-ins/plugin1 and /Applications/xxxapp/Plug-ins/plugin2. One of the two will be used. Which one is undefined.

then i crash badly soon after...

i obviously do something wrong but i have no clue what!

wysota
25th July 2012, 07:59
The only problem is the first plugin not being unloaded before the second one loads.

eric_vi
25th July 2012, 14:35
it looks like it... but i am not in control of the application... is there any way for me to unload the previous qt libraries/frameworks so i can reload them?

wysota
25th July 2012, 15:07
Not without changing the original framework. Welcome to DLL Hell :)

eric_vi
25th July 2012, 16:09
grrr i can see the nightmare :eek: this is not my territory at all...

alternatively is it possible for a dll to unload a previous dll... if so what do i need to collect?

wysota
25th July 2012, 16:10
No, sorry. The original program is flawed and there is nothing you can do about it.

eric_vi
25th July 2012, 18:01
well after further research you right i am doomed.. it is not even this app that is flawed... it is the Apple Objective-C runtime that does not let do that

Thank you Apple

wysota
25th July 2012, 18:30
I don't see what Objective-C runtime has to do with your problem. Your problem is related to a) dynamic linker, b) application that doesn't unload a plugin once it doesn't need it anymore.

eric_vi
25th July 2012, 21:35
obj-c keeps various references to dll trying to unload within app causes the app to crash... so it has to remain loaded...it has been reported to apple

wysota
25th July 2012, 21:39
Are you using Objective C?