PDA

View Full Version : QProcess and none-string arguments



Raistlin
11th March 2008, 18:17
I need to combine some code I have written myself.


The main program is written in LabVIEW and has C-style DLLs calls, where the DLLs contain C++ code with Qt.
The second part is written entirely in Qt.

I tried to integrate the second part in my LabVIEW code, but this is not trivial because of the threads, signals/slots, event handling, ... Therefore, I postponed this to later and would now like to use QProcess as a solution.

I need to pass a lot of parameters from the main program to the second application. These range from strings to ints, floats, doubles, ... I thought I could use the 'arguments' of void QProcess::start( const QString & program, const QStringList & arguments) . I am not sure how to handle this however.


Format all parameters into QStrings and append them to the QStringList.
Construct a QDataStream based on a QByteArray, serialize all date in there, and construct a QString based on this. I suppose however that I can run into troubles because of '0' bytes, and have to use QT_NO_CAST_FROM_ASCII to avoid strange things happening to the data.

Or is there a more elegant way? Any suggestions?

wysota
11th March 2008, 21:52
I suggest you format the data as XML and pass it to stdin of the other application (so not as a parameter but as a stream of data).

Raistlin
12th March 2008, 11:23
Thank you for the suggestion.

I do however still have some issues to get the inter process communication to work. This is how I handle it. The application is launched succesfully, but it does not seem to receive any data. I use a QFile constructed with stdin in my server to capture the input from the startserver program.

The main.cpp of my startserver program:



#include <QCoreApplication>
#include "startserver.h"

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Startserver w;
return a.exec();
}


The startserver class:



#include <QDir>
#include <QFile>
#include <QProcess>
#include <QString>
#include <QStringList>

class Startserver : public QObject
{
Q_OBJECT

public:
Startserver(QObject *parent = 0);
~Startserver();

private slots:
void serverFinished(int, QProcess::ExitStatus);

private:
QProcess* process_;
};

Startserver::Startserver(QObject* parent) : QObject(parent)
{
QString appName = QString("myapplication.exe");

process_ = new QProcess(this);

process_->start(appName);
process_->waitForStarted();

connect(process_, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(serverFinished(int, QProcess::ExitStatus)));

//Start a timer, which sends data to the server each second
QTimer* timer = new QTimer(this);
timer->setInterval(1000);
connect(timer, SIGNAL(timeout()), this, SLOT(sendData()));
timer->start();
}

Startserver::~Startserver()
{

}

void Startserver::serverFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
exit(exitCode);;
}

void Startserver::sendData()
{
//Send some data to server
//This slot is effictively called each second !!
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_3);
out << (quint32)0;
out << QString("Hello server");
out.device()->seek(0);
out << (quint32)(block.size() - sizeof(quint32));

//Data is sent to stream each time, since bytesToWrite returns same amount each time
process_->write(block);

while (process_->bytesToWrite() > 0)
{
if (!process_->waitForBytesWritten())
break;
}
}



And here is what happens in the main class of my server program. The code is a lot bigger, so I only show what I think to be the relevant parts.



#include <QByteArray>
#include <QList>
#include <QtNetwork>
#include <QtCore>
#include <QMessageBox>

#include "ConnectionThread.h"

class OctoServer : public QTcpServer
{
Q_OBJECT

public:
OctoServer(QObject *parent = 0);
~OctoServer();

signals:
//...

public slots:
void readInput();
//...

private:
QString* directory_;
};

OctoServer::OctoServer(QObject* parent) : QTcpServer(parent)
{
QFile* stdinFile = new QFile(this);
directory_ = new QString();

//Open a file pointing to the stdin and connect incoming data signal to custom slot
stdinFile->open(stdin, QIODevice::ReadOnly);
connect(stdinFile, SIGNAL(readyRead()), this, SLOT(readInput()));

//...
}

void OctoServer::readInput()
{
//This slot is never called !!
QMessageBox::information(0, QString("Data incoming"), QString("Data")) ;
}

OctoServer::~OctoServer()
{
delete directory_;
}

wysota
12th March 2008, 11:32
Have you tried verifying each application that they actually read/write the data to respective descriptors?

Raistlin
12th March 2008, 11:39
How exactly would I accomplish this?

Raistlin
12th March 2008, 14:20
Hmm, it seems QFile does not emit readyRead() in general. So this means I will need to poll in the idle loop for this, since QSocketNotifier is also not an option on Windows.

Good to know :).

If I could only wait for the official release of Qt 4.4 and the introduction of QSharedMemory.

wysota
12th March 2008, 14:56
You can always use platform dependent solutions.

Raistlin
12th March 2008, 15:45
Well, I implemented a connection through a QTcpSocket now, and once Qt 4.4 is available (not the beta, since we have to release this code to customers) I will take a look at QLocalServer (http://doc.trolltech.com/4.4beta/qlocalserver.html) and QLocalSocket (http://doc.trolltech.com/4.4beta/qlocalsocket.html).

wysota
12th March 2008, 16:28
If both applications are GUI-based, you can use WinAPI PostMessage() call.