PDA

View Full Version : How to use Qt inner process communication to return value to native win32 application



umen
5th May 2011, 14:38
I have native win32 application that starts Qt exe application with (probably ) CreateProcess function
The Qt application doing some work , now when the Qt application done its job I need it somehow to signal back with returned parameter
String type . what is the best way to implement such thing ?

mcosta
5th May 2011, 15:32
it depends to how the "launcher" expects to receive results.

umen
5th May 2011, 18:57
im flexible because i have no idea what choices do i have?
i know i can't open port for tcp connection , and that i have native win32 application that need to start Qt application and receive response

squidge
5th May 2011, 19:44
If you want to return string, why not just output it to standard output and let the parent app read that result?

umen
5th May 2011, 20:29
any pointers on how to do this?
you mean to open cmd window from Qt application and output to stdout astring ?
then read this string from the cmd window? with the win32 application ?

squidge
5th May 2011, 20:54
Yes, exactly. Since you are going to use CreateProcess API you can create a pipe (WinAPI CreatePipe()), provide that pipes handle to the STARTUPINFO structure of CreateProcess and then just read the pipe with standard WinAPI I/O functions like ReadFile().

umen
5th May 2011, 21:05
do i have to create cmd window when the Qt application executes ?
this is something i like to avoid .

rsilva
6th May 2011, 12:46
To use input and output functions you don't need a console. You just need to use the pipe like squidge said.

But, there's another way too. You can use shared memory. To do this you can use QSharedMemory in the Qt application and in the second process you can use the combination of CreateFileMapping, OpenFileMapping, MapViewOfFile.

You can find an example here:
http://msdn.microsoft.com/en-us/library/aa366551(v=vs.85).aspx

But read the comments, try to change the name to a name that doesn't use the Global namespace.
Use Local\ or simple don't type use a name that doesn't have the Global\ or Local\ like "myappsharedmem"

*edit:
And you have the alternative to create a dll with a shared section. So you load the .dll in the two processes and use a function in the dll that returns a pointer to a shared section variable.

To have a shared section you just need to do this.



#pragma data_seg(".shared")

char sharedMemBuf[1024] = ""; //This buffer will be the shared memory used for read/write.

#pragma data_seg()

char* pointerToSharedMem() // Just get a pointer to the buffer.
{
return sharedMemBuf;
}


To see the changes in the buffer just add a timer or check if in some event.
To write just use change it by the normal way.

You can use a function in the dll that copies memory for write and send a message to registered windows, so you can simple find when the buffer is changed.

Example:



/*Dll code*/

#define MYAPP_SHARED_EVENT WM_USER + 36
// Just typed a WM_USER (custom message) and a random number lol

vector<HWND> wndList;

void registerShareEventForWindow(HWND wndList)
{
wndList.push(wndList);
}

void copyMemoryToBuffer(char* data, int size)
{
memcpy(sharedMemBuf, data, size);

vector<HWND>::iterator wnds = wndList.begin();
for (; wnds != wndList.end(); wnds++) SendMessage(*wnds, MYAPP_SHARED_EVENT, (WPARAM)sharedMemBuf, 0);

// Here i'm using wparam to store the pointer for the buffer.
}




/* qt and non-qt application code */

switch(msg->message) // use this inside winEvent or wndProc function
{
case MYAPP_SHARED_EVENT:
onSharedBufferChanged((char*)msg->wParam);
break;
}


NOTE: This isn't thread-safe function so you can use a "wait" system or just only respond to the events without changing the buffer in the same time.

It's just a normal array pointing to a heap section that's shared between all processes that load that dll.

To prevent other processes from loading the dll you can just use a signature system to check if it's your process.

umen
6th May 2011, 13:28
Thanks very much for your answer the first solution seams to be easer to implement
i will try to do that .
update;
to try to implement the sharedmemory thing , i was reading the Qsharedmemory tutorial in :
http://doc.trolltech.com/main-snapshot/ipc-sharedmemory.html
and as you suggested in :
http://msdn.microsoft.com/en-us/library/aa366551(v=vs.85).aspx
now one thing for start i dont understand in the Qt side with QSharedmemory where i set the name of the memory so that my win32 will access it by name?
also in the win32 application is there any way to signal when the memory is with value without doing while loop with timer ?

rsilva
6th May 2011, 23:36
You can also use the name pipe like squidge said, it's a easy solution too and I recommend using it, but I don't know how, I never used it ^^.

-

About the name of the memory, it's in the tutorial, in the constructor:


Dialog::Dialog(QWidget *parent)
: QDialog(parent), sharedMemory("QSharedMemoryExample")

And from the tutorial:

"Note that "QSharedMemoryExample" is passed to the QSharedMemory() constructor to be used as the key. This will be used by the system as the identifier of the underlying shared memory segment."

The "QSharedMemoryExample" is the name that they are using as the name.
Use the same name that you're using in your win32 app.

And you question about the signal the changes you can use the CreateEvent function.
http://msdn.microsoft.com/en-us/library/ms686915(v=VS.85).aspx

edit:
How to do:

- CreateEvent in the launcher; CreateEvent Function (http://msdn.microsoft.com/en-us/library/ms682396(v=VS.85).aspx)

- Create a thread to wait the event using WaitForSingleObject; WaitForSingleObject Function (http://msdn.microsoft.com/en-us/library/ms687032(v=VS.85).aspx)

- In the Qt Process use OpenEvent to get the handle of the event; OpenEvent Function (http://msdn.microsoft.com/en-us/library/ms684305(v=VS.85).aspx)

- Write data to the SharedMemory.

- Use SetEvent in the handle, so the WaitForSingleObject will return now; SetEvent Function (http://msdn.microsoft.com/en-us/library/ms686211(v=VS.85).aspx)

* If you're using a "single-shot" read, in the launcher call CloseHandle in the event.

* If you want a two-way communication you can set two events and use Wait to monitor the changes, and using Set and Reset Event (ResetEvent Function) (http://msdn.microsoft.com/en-us/library/ms685081(v=VS.85).aspx) to notify that some work was done or need to wait before reading/writing.