PDA

View Full Version : Call GUI Dll from non-Qt application



barak
11th July 2010, 09:37
We have started to develop with the open SDK and came across a very crucial problem. If Qt SDK will be able to solve this issue will, probably, make the purchase.

One of our components is Qt DLL which expose GUI dialogs. If we call it from other Qt applications, or even none Qt console application everything is fine and the DLL is able to show its dialogs. But, when we try to load dialogs from another none-Qt GUI application, Java application for instance, the application is not able to continue, no dialog is showed and we get the following error at the command line window we have run the application from: “QPixmap: It is not safe to use pixmaps outside the GUI thread”.

We are testing it on Linux Ubuntu. All we need is to be able to show dialogs from Qt DLL being loaded by none-Qt GUI application.

wysota
11th July 2010, 10:22
You need to integrate Qt event loop with the other app's event loop, i.e. by periodically calling QCoreApplication::processEvents() instead of using threads.

barak
11th July 2010, 10:27
The other application is not mine. It is using my DLL but I can not change its code. It is loading my DLL.

wysota
11th July 2010, 10:35
And how does it call your guis?

barak
11th July 2010, 10:46
The non-Qt GUI application is loading a DLL which uses my Qt-GUI dll. It needs to show some verify PIN dialog, which is implemented in my GUI Qt dll.

wysota
11th July 2010, 10:58
This doesn't answer my question. How does it call your code, in what conditions? And how does your code look like?

barak
11th July 2010, 11:08
My code is a static lib MyDll.a we have another shared library OurDll.so which links statically to MyDll.a(MyDll is the one with the GUI). There is another Java GUI application which links dynamically to the OurDll.so and loads it. When the GUI application performs verify PIN action it calls OurDll.so which in its turn use MyDll.a verify PIN function that have to show GUI dialog.

My Code:

This is called when OurDll.so is loaded.

QApplication * a = 0;
void initPkcsPinDialog(){
if (!qApp)
{
a = 0;
int argc = 1;
char *argv[] = { "asePinDialog", NULL };
a = new QApplication(argc, argv);
}
}

//This is calling the GUI dialog (VerifyPin3Des and VerifyPinSig are dialogs)
bool aseLogin(aseVerifyData& aseData)
{
m_iLastSlotId = aseData.slotID;

if(aseData.pinType == KEY_TYPE_CHAL_RESP)
{
VerifyPin3Des *pinDlg = new VerifyPin3Des(aseData);
m_pOpenDialog = pinDlg;
pinDlg->exec();
delete pinDlg;
m_pOpenDialog = NULL;
}
else
{
VerifyPinSig *pinDlg = new VerifyPinSig(aseData);
m_pOpenDialog = pinDlg;
pinDlg->exec();
delete pinDlg;
m_pOpenDialog = NULL;
}

m_iLastSlotId = 0;
return true;
}

wysota
11th July 2010, 11:33
You still didn't answer my original question.

barak
11th July 2010, 11:35
This one"how does it call your guis?"

It is Java application we use in Linux. It loads the shared library OurDll.so which is statically linked with MyDll.a. OurDll.so expose a known interface and this is the interface the Java GUI application is using. I imagine that the GUI application is using some sort of get proc address to known function pointers and then use them.

wysota
11th July 2010, 11:52
What I'm mainly after is whether both calls to your library are from the same thread (and which thread is it). Knowing JAVA world it is likely they are called from different threads and that is causing you trouble. GUI in Qt can only be accessed from the main thread (as noted several times in the docs, which you have surely read).

barak
11th July 2010, 12:02
The main GUI thread is the Java application which has some other GUI and is implemented as GUI application which loads shared dlls. If I want to use GUI in my DLL I must have QApplication in order to have event loop for Qt, this is a must if I want to show GUI. But then the thread in my GUI dll is different thread here is a snapshot from the Linux:

amiad@ubuntu:~$
amiad@ubuntu:~$
amiad@ubuntu:~$
amiad@ubuntu:~$
amiad@ubuntu:~$ "/home/amiad/Desktop/File Protector 5/FileProtector.sh"
/home/amiad/Desktop/File Protector 5
Starting Actalis File Protector v5 ...
amiad@ubuntu:~$ Checking JVM version...
[FPConfigFile]Pathname: /home/amiad/fp.users/
QApplication: Invalid Display* argument

amiad@ubuntu:~$
amiad@ubuntu:~$ QPixmap: It is not safe to use pixmaps outside the GUI thread
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QApplication(0x88da510), parent's thread is QThread(0x88d57c8), current thread is QThread(0x8bee0a0)
QPixmap: It is not safe to use pixmaps outside the GUI thread
QPixmap: It is not safe to use pixmaps outside the GUI thread

One more thing only the Java GUI application is calling my DLL at a time. One call at a time.

wysota
11th July 2010, 12:26
You still fail to understand me or you don't understand what threads are. I'm not asking whether your code is called by multiple threads at the same time, I'm asking whether both functions are called from the same thread (sequentially, not concurrently). The fact that the main thread of the process is executed by the java runtime says exactly nothing about which thread is calling your function. You can't answer my question without either debugging the java app, asking its author or inspecting its (app's, not author's) source code. So far we can only see Qt says your data is referenced by two threads. The only question is whether you start the thread in one of your dialogs or the java part does and what can you do to prevent it.

barak
11th July 2010, 12:34
I understand, you ask if the Java application might be opening another thread and call my code from that thread, or is it calling it from its main thread, the GUI thread. You are correct I have no way of knowing it but is there a solution to each option? Is it possible to show GUI from shared library called by GUI application?

Can I try some solution to any of the cases?

wysota
11th July 2010, 12:44
You can only access the GUI from the main (the one with QApplication object) thread so if you are currently working in context of a different thread, you need to order the main thread to operate the GUI for you and then return results back to the calling thread (you can use signals and slots or QCoreApplication::sendEvent()). Whether this will work or not depends on how the java application works. Also remember you need to have an event loop running to be able to receive signals across threads or use events. So either way you will have to integrate Qt event loop with the main app's event loop.

barak
11th July 2010, 12:48
Can you show me in a few lines of code how do I integrate the Qt event loop with the main application's event loop?

wysota
11th July 2010, 12:52
No, sorry. I don't know how the java app works. I can only tell you that you need to force the application to periodically call QApplication::processEvents().

barak
11th July 2010, 12:55
OK one last question: if the Java application will not periodically call QApplication::processEvents() it will not work? I can not call QApplication::processEvents() from my code correct?

wysota
11th July 2010, 13:09
OK one last question: if the Java application will not periodically call QApplication::processEvents() it will not work?
It depends how you wish to implement it. You need to call your dialog in the context of the same thread the QApplication object was created in. The first thing I'd try would be to create the application object in the same function you are creating the dialog itself.


I can not call QApplication::processEvents() from my code correct?
Unless your code is called several times each second then no. But you should be able to inject some code into the java app (i.e. setup some timer or something like that). An alternative is to have a helper application in pure C++/Qt and only communicate with it from your two functions using some IPC mechanisms. Your init function would start the application and the other function would communicate with it through shared memory, pipes, sockets or similar mechanisms.

barak
11th July 2010, 13:13
Some thing like this?



bool aseLogin(aseVerifyData& aseData)
{
m_iLastSlotId = aseData.slotID;
QApplication * a = 0;
int argc = 1;
char *argv[] = { "asePinDialog", NULL };
a = new QApplication(argc, argv);

if(aseData.pinType == KEY_TYPE_CHAL_RESP)
{
VerifyPin3Des *pinDlg = new VerifyPin3Des(aseData);
m_pOpenDialog = pinDlg;
pinDlg->exec();
delete pinDlg;
m_pOpenDialog = NULL;
}
else
{
VerifyPinSig *pinDlg = new VerifyPinSig(aseData);
m_pOpenDialog = pinDlg;
pinDlg->exec();
delete pinDlg;
m_pOpenDialog = NULL;
}

m_iLastSlotId = 0;
return true;
}

wysota
11th July 2010, 13:19
Apart from memory leaks (why use pointers here if all objects are only used in local context?), yes.

barak
11th July 2010, 13:22
You are correct !!

Thank you very much it is WORKING !!! I have managed to show the dialog and work with it.

Again, many thanks :o

Keep on with the great job your doing.