Qt QProcess how to write to standard in? - c++

I am starting a QProcess to open cmd.exe.
I want to write to std in to send commands to cmd.exe, and I want to recieve it's output.
QProcess mProcess = new QProcess(this);
mProcess->setReadChannelMode(QProcess::SeparateChannels);
mProcess->start("cmd");
QApplication::processEvents();
QString s(mProcess->readAllStandardOutput());
writeToConsole(s);
This all works just fine. The process starts, I get output. However, I can't now write to the process anymore. I have looked over QProcess documentation and I don't see any way to write to standard in. I've tried mProcess->write(data); but that didn't do anything.
How do I write to standard in to the running process?

You have to use write function only to write in to the standard in.
But the important thing is you have to close the write channel using void QProcess::closeWriteChannel().
Look into below documentation.
http://doc.qt.io/qt-5/qprocess.html#closeWriteChannel

You should wait for operations to finish before moving on to the next action.
QProcess mProcess = new QProcess(this);
mProcess->setReadChannelMode(QProcess::SeparateChannels);
//Start the process
mProcess->start("cmd");
QApplication::processEvents();
mProcess->waitForStarted();
// Read the output
mProcess->waitForReadyRead();
QString output(mProcess->readAllStandardOutput());
mProcess->closeReadChannel();
// Write the data
mProcess->write(output);
mProcess->waitForBytesWritten();
mProcess->closeWriteChannel();
// Wait for finished
mProcess->waitForFinished();
It seems strange to send the output directly back into the program being executed. Alternatively you could connect the void QIODevice::readyRead() signal to a slot where the output can be handled elsewhere.

The mistake I was making here was not putting \n on the end of the multiple commands.
''''
// 1st command
mProcess->write(output1 + "\n");
mProcess->waitForBytesWritten();
// 2nd command
mProcess->write(output1 + "\n");
mProcess->waitForBytesWritten();
// Wait for finished
mProcess->waitForFinished();
mProcess->closeWriteChannel();
''''

Related

Monitor running qprocess and return value when qprocess is finished

I want to run a qprocess (the program adb) and when the process is finished return the results to the calling function. However, there's every possibility that adb could find itself in a loop, printing error messages such as "ADB server didn't ACK" to stdout, not ever finishing. I need to trap these errors.
QProcess run_command;
connect(&run_command,SIGNAL(readyReadStandardOutput()),this,SLOT( dolog() ));
QString result=RunProcess("adb connect 192.168.1.100");
...
QString MainWindow::RunProcess(QString cstring)
{
run_command.start(cstring);
// keep gui active for lengthy processes.
while(run_command.state() != QProcess::NotRunning)
qApp->processEvents();
QString command=run_command.readAll();
return command; // returns nothing if slot is enabled.
}
void MainWindow::dolog()
{
QString logstring = run_command.readAllStandardOutput();
if (logstring.contains("error condition")
logfile("Logfile:"+logstring);
}
If I enable the signal/slot, dolog() prints stdout to a logfile, but RunProcess returns a blank string. If I disable the signal/slot, RunProcess() returns the qprocess output as expected.
First you need to identify which output stream the command in question is using for its errors.
It is very like stderr so you would need to connect to the readyReadStandardError() signal instead.
For the command itself I would recommend to split it into command and arguments and use the QProcess::start() overload that takes the command and a list of arguments.
Just more robust than to rely on a single string being correctly separated again.

How to avoid waitForStarted with QProcess to stop GUI from freezing?

I am running wscript with QProcess to run a VB Script that converts Excel files to tab delimited text files. The script runs fine and everything, but the GUI freezes and the user is unable to interact with it for a significant amount of time. Here is the code:
/* Create txt files and store paths */
for (int i = 0; i < excelFilepaths.size(); ++i) {
wscript->start("wscript.exe", QStringList() << vbs.fileName() << excelFilepaths.at(i) << newDir.absolutePath() + "/" + QString::number(i + 1));
wscript->waitForFinished();
payloadPaths.push_back(newDir.absolutePath() + "/" + QString::number(i + 1));
}
So whats going on is that I have multiple excel file paths and a QProcess allocated on the heap. This QProcess runs the VB Script that converts the excel files into text files and then stores the path of the new text file. This takes a long time (about 20 seconds for 4 excel files). During this time the GUI is frozen. I would like the user to be able to use parts of the GUI that don't interfere with the process.
Now I suspect that the cause of this issue is
QProcess::waitForFinished()
And I've read online about connecting the finished() and error() signals of QProcess to remove this problem. However I've been having difficulty doing so. I'm running this code as a method of a class that inherits from QObject and containst the Q_OBJECT macro, so everything should be set. I just need some help putting the rest of the pieces together. How can I make it so my GUI does not freeze while QProcess is running? Please help.
To quote the documentation at the section called Synchronous Process API:
waitForStarted() blocks until the process has started.
waitForReadyRead() blocks until new data is available for reading on the current read channel.
waitForBytesWritten() blocks until one payload of data has been written to the process.
waitForFinished() blocks until the process has finished.
Calling these functions from the main thread (the thread that calls QApplication::exec()) may cause your user interface to freeze.
Keep that in mind. However you may overcome this issue using something like that:
connect(process, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
[=](int exitCode, QProcess::ExitStatus exitStatus){ /* ... */ });
Note that there are some more signals which may suite any desired purpose.
I had the same problem but with QSerialPort. However, i think the solution is the same. I couldn't find a way to have "serial->waitForReadyRead()" not freezing the GUI, so, I implemented my own function.
void Research::WaitSerial(int MilliSecondsToWait)
{
QTime DieTime = QTime::currentTime().addMSecs(MilliSecondsToWait);
flag = 0;
while(QTime::currentTime() < DieTime && !flag)
{
QCoreApplication::processEvents(QEventLoop::AllEvents,100);
if(BufferSerial != "")
{
flag++;
}
}
}
Of course, your problem is similar but not the same. Just change the ifto have your "stopping condition". Hope this helps.
EDIT: This was not originally my ideia. I found it on a forum somewhere. So I don't take the credits.

QProcess doesn't show any output when it runs rsync

I start rsync in QProcess. My process runs fine (in its own terminal) if I use QProcess::startDetached() but nothing happens if I start it with QProcess:start(). The problem seems to be that QProcess can't apparently read messages from rsync and write it to the output window.
I have connect this signal in constructor.
MainWindow::~MainWindow()
{
process = new QProcess(this);
connect( process, SIGNAL(readyReadStandardOutput()), this, SLOT(onReadyReadStandardOutput() ) );
}
Later on button clicked I call:
void MainWindow::onButton1Clicked()
{
process->start("rsync -a root#10.0.0.1:/path/ /rsync_folder");
//process->start("ping 10.0.0.01"); // this works for testing and I see output but not the above.
}
When rsync starts, it prints a message and ask for password..none of it is received by my QProcess but the ping message are received..what could be possibly wrong here?
The above grieving line also works directly on windows 7 command line but it just doesn't seem to show any progress in QProcess.
Update
Here is how I displaying the output.
void MainWindow::onReadyReadStandardOutput()
{
qDebug() << process->readAllStandardOutput();
}
http://doc.qt.io/qt-5/qprocess.html#communicating-via-channels
Did you remember to link to and check the standard error channel?
http://doc.qt.io/qt-5/qprocess.html#readAllStandardError
That has fixed it for me in the past for some QProcesses I have started.
Another way I've done it, is to use QProcess::startDetached();
Hope that helps.
My research shows that rsync probably behaves like scp which accordingly this answer doesn't generate output when it is redirected.

Qt Execute external program

I want to start an external program out of my QT-Programm. The only working solution was:
system("start explorer.exe");
But it is only working for windows and starts a command line for a moment.
Next thing I tried was:
QProcess process;
QString file = QDir::homepath + "file.exe";
process.start(file);
//process.execute(file); //i tried as well
But nothing happened. Any ideas?
If your process object is a variable on the stack (e.g. in a method), the code wouldn't work as expected because the process you've already started will be killed in the destructor of QProcess, when the method finishes.
void MyClass::myMethod()
{
QProcess process;
QString file = QDir::homepath + "file.exe";
process.start(file);
}
You should instead allocate the QProcess object on the heap like that:
QProcess *process = new QProcess(this);
QString file = QDir::homepath + "/file.exe";
process->start(file);
If you want your program to wait while the process is executing and only need to get its exit code, you can use
QProcess::execute(file);
QProcess::exitCode(); // returns the exit code
instead of using process asynchronously like this.
QProcess process;
process.start(file);
Note that you can also block execution until process will be finished. In order to do that use
process.waitForFinished();
after start of the process.
QDir::homePath doesn't end with separator. Valid path to your exe
QString file = QDir::homePath + QDir::separator + "file.exe";
Just use QProcess::startDetached; it's static and you don't need to worry about waiting for it to finish or allocating things on the heap or anything like that:
QProcess::startDetached(QDir::homepath + "/file.exe");
It's the detached counterpart to QProcess::execute.
As of 5.15 that form is obsolete (but still present). The new preferred call is the same as the above but with a QStringList of command line arguments as the second parameter. If you don't have any arguments to pass just pass an empty list.

Use QProcess to only zcat as many lines as needed?

In Linux if I run this command
zcat bigFile | head
Then zcat will not decompress all of bigFile, only as much as it needs to in order to supply head with the data it needs.
But what about this
QProcess *process = new QProcess(this);
process->start("zcat bigFile");
process->readLine();
QTimer::singleShot(10000, process, SLOT(terminate()));
Will the zcat command that is run in process only decompress whatever is needed for readLine()? Or will it continuously zcat bigFile for 10 seconds?
Is it possible to use a QProcess similarly to the Linux pipe |, and thus only zcat as many lines as have been requested?
Will the zcat command that is run in process only decompress whatever
is needed for readLine()?
No
Or will it continuously zcat bigFile for 10 seconds?
Yes
To verify this, I wrote the following code
QProcess *process = new QProcess(this);
process->start("yes");
connect(process, SIGNAL(finished(int)), this, SLOT(_end()));
connect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(_end()));
QByteArray byteArray = process->readLine(5);
QString line = QString(byteArray);
process->closeReadChannel(QProcess::StandardOutput);
QTimer::singleShot(5000, process, SLOT(terminate()));
This basically starts the yes command which continuously outputs this
y
y
y
y
... (and so on)
And then reads only one line from the output of yes, and then terminates the process 5 seconds later.
I ran this command while watching top, and the result is 5 seconds of yes taking 100% CPU, after which it quits. This clearly shows that yes does not merely print out one line and then halt or quit.
Even closing the stdout read channel (which ignores the rest of the output of yes) still doesn't pause the yes execution.
You could try pausing the QProcess periodically until you have enough time to process the buffer, but that could get messy.
When you call start() on QProcess, it executes the zcat program, as it does in a terminal. This is a separate process from your Qt program, so it's free to run independently from your Qt application, or in the case of the code you've provided, it will run until it is terminated 10 seconds later.
Whether or not you choose for your application to read the output from zcat is up to you, but it will still continue to run.
Also note that calling process->readline() straight afterwards is probably not the best way of handling the process as your program may try to read the output stream before any data is ready. Instead, you should either call waitForReadyRead() before readline(), or connect a slot to readyRead() signal of QProcess and call readline from that slot.
---- EDITED -----
Based on the change to the question: -
I think you're missing the point of the pipe command. As I understand it, all of the file will be decompressed by zcat, but its output is redirected to the head command. The head command only displays the first number of lines of a file, which is why you only see the first part.
This is like having a file test.txt and calling the command: -
cat test.txt | head
The whole file exists, but head will only display the first number of lines.