PDA

View Full Version : Running external process like cmd.exe



atomic
3rd September 2014, 16:54
Hi,
I have problem with support / starting external process.
I have simple console application which adds two entered numbers and display result.

When I run this console application in cmd.exe it works fine - stdin in cmd.exe is directly send
to my application, stdout in my application is directly send to cmd.exe console and when my app exit
stdin return to work with cmd. sample use:

10611

Now question - how i can set QProcess that can work the same way?

what I have:



QProcess process;
process.start( "C:/Users/C50/Desktop/test/consoleQt.exe",
QStringList(), QIODevice::ReadWrite | QIODevice::Text );

QTextStream in( stdin );

while( process.state() == QProcess::Running ) {

process.write( in.readLine().toStdString().c_str() );
}

stampede
3rd September 2014, 19:43
Use signals, from the docs:

(after calling QProcess::start) ... QProcess then enters the Starting state, and when the program has started, QProcess enters the Running state and emits started().
You can also call waitForStarted() after start() if you prefer synchronous api.
Also, there is no need for this conversion:


process.write( in.readLine().toStdString().c_str() );

this will do:


process.write(in.readLine());

atomic
4th September 2014, 11:59
I have some solution which work fine but I am not sure whether this code is ok and whether in some conditions can make problems.

I found in documentation QProcess


void QProcess::setInputChannelMode(InputChannelMode mode)

QProcess::ForwardedInputChannel 1

QProcess forwards the input of the main process onto the running process. The child process reads its standard input from the same source as the main process. Note that the main process must not try to read its standard input while the child process is running


and


QProcess::ForwardedChannels 2

QProcess forwards the output of the running process onto the main process. Anything the child process writes to its standard output and standard error will be written to the standard output and standard error of the main process.


It is my code


process.setInputChannelMode( QProcess::ForwardedInputChannel );
process.setProcessChannelMode( QProcess::ForwardedChannels );

process.start( "D:/Projects/Qt projects/4programQt/build-consoleQt-Desktop_Qt_5_3_MinGW_32bit-Release/release/consoleQt.exe",
QStringList(), QIODevice::ReadWrite | QIODevice::Text );

process.waitForStarted();
while( process.waitForFinished( - 1 ) ) {

if( process.state() == QProcess::Running )
command = in.readLine();
}


Now i don't need use write() function because child process automatically read from stdin main process.
What do you think about this code?

yeye_olive
5th September 2014, 19:52
Forwarding the channels to the main process is a bad idea that will not help you solve your problem.

What you need to do is communicate asynchronously through the input and output channels as you would with a socket. Connect the QProcess' error(), finished(), readyReadStandardError(), and readyReadStandardOutput() signals to slots in your program. You can then accumulate the data as it arrives on the two channels and decode it either incrementally -- this requires keeping a potentially complex state around -- or in one go after the process has finished. If you want to give the illusion of synchrony in your program, use a QEventLoop.

atomic
6th September 2014, 09:24
Why forwarding the channels to the main process is a bad idea?
In tests it works fine. I can block main process until child working it is ok for me.

yeye_olive
8th September 2014, 10:45
Forwarding channels is a bad idea because you pollute your main program's channels with those of the child process. If the main program writes something on its output or error channel, you will end up trying to parse it. This is not just hypothetical: Qt's classes routinely print warning messages (though maybe only on the error channel, but who knows for sure?).

In any case, this does not help you solve your problem: communicate with the child process. Your current solution should work equally well without forwarded channels, but you should realize that you may run into a deadlock. If the child process writes too much on its output/error channel and fills its internal buffer, it will wait for the main process to read the pending data. Since your main process currently starts reading only after the child process has terminated, you had better hope that the buffers are large enough.