QProcess is not running - c++

I need some help with this:
I want to start a script ("test.sh") from inside my code and read the output. The script is giving an output string in an interval of 3 seconds for 5 times. So the output string is generated 5 times with a pause of 3 seconds in between. I want to display the output strings in a QTextBrowser. The string should be added every 3 seconds (as it comes from the script). Therefore I connected the readyReadStandardOutput() signal from QProcess to a slot but this slot is never entered. The connect function returns true. So no problem there, I guess.
There is some code:
void DialogWindow::startScript()
{
QProcess* prcs = new QProcess(this);
connect(prcs, SIGNAL(readyReadStandardOutput()), this, SLOT(slot_readyReadStandardOutput()));
QString program = "./test.sh";
prcs->setProgram(program);
prcs->open();
if(prcs->isOpen())
prcs->execute("test.sh"); //this line is executed
prcs->waitForStarted(6000);
qDebug() << prcs->state(); // --> "QProcess::NotRunning"
qDebug() << prcs->error(); // --> "QProcess::FailedToStart"
qDebug() << prcs->errorString(); // --> "0x000000c1"
qDebug() << prcs->workingDirectory(); // --> ""
}
void DialogWindow::slot_readyReadStandardOutput()
{
QTextBrowser* m_pTextBrowser = new QTextBrowser();
prcs->readAllStandardOutput();
prcs->readAllStandardError();
QString output = prcs->readAllStandardOutput();
if(output.contains("warning"))
m_pTextBrowser->setTextColor(QColor(Qt::yellow));
if(output.contains("error"))
{
m_pTextBrowser->setTextColor(QColor(Qt::red));
//emit errorOccured();
}
m_pTextBrowser->append(prcs->readAllStandardOutput());
m_pTextBrowser->setTextColor(QColor(Qt::black));
}
What am I missing????
My script is located in my project folder and I copied it to the debug folder. The script is running properly and returns the output text as expected when double clicking it or using the command "./test.sh" in the shell.
UPDATE: I could figure out which error string I get (0x000000c1) and I looked it up here. It means:
ERROR_BAD_EXE_FORMAT / %1 is not a valid Win32 application
What does that mean? The script is running as described above... Why can I not start it with QProcess?

Related

Read stdoutput of continuous QProcess in Qt

I am having some problem regarding QProcess using Qt. I have connected the following function with the onClick event of a push button. Basically, I want to execute another file when this button is clicked, and get its output on my Qt program. This file calculator executes, displays some output, and then waits for an input from the user.
void runPushButtonClicked() {
QProcess myprocess;
myprocess.start("./calculator")
myprocess.waitForFinished();
QString outputData= myprocess.readStandardOutput();
qDebug() << outputData;
}
In a scenario, when the calculator is such a file that only outputs some results and terminates eventually, this works perfect. But, in case when the calculator waits for some further input from the user after outputting some results, I get nothing in my outputData. In fact, waitForFinished() would time out, but even when I remove waitForFinished(), the outputData would still be empty.
I have already tried some of the solutions available here on SO, but have been unable to handle this case. Any guidance will be much appreciated.
I would suggest, that you setup a signal handler, that gets called when the subprocess produces output. E.g. you have to connect to readyReadStandardOutput.
Then you can identify, when subprocess demands input and send the input you want. This will be done in readSubProcess().
main.cpp
#include <QtCore>
#include "Foo.h"
int main(int argc, char **argv) {
QCoreApplication app(argc, argv);
Foo foo;
qDebug() << "Starting main loop";
app.exec();
}
In the following, the subprocess is started and the input checked. When the calculator program finishes, the main also exits.
Foo.h
#include <QtCore>
class Foo : public QObject {
Q_OBJECT
QProcess myprocess;
QString output;
public:
Foo() : QObject() {
myprocess.start("./calculator");
// probably nothing here yet
qDebug() << "Output right after start:"
<< myprocess.readAllStandardOutput();
// get informed when data is ready
connect(&myprocess, SIGNAL(readyReadStandardOutput()),
this, SLOT(readSubProcess()));
};
private slots:
// here we check what was received (called everytime new data is readable)
void readSubProcess(void) {
output.append(myprocess.readAllStandardOutput());
qDebug() << "complete output: " << output;
// check if input is expected
if (output.endsWith("type\n")) {
qDebug() << "ready to receive input";
// write something to subprocess, if the user has provided input,
// you need to (read it and) forward it here.
myprocess.write("hallo back!\n");
// reset outputbuffer
output = "";
}
// subprocess indicates it finished
if (output.endsWith("Bye!\n")) {
// wait for subprocess and exit
myprocess.waitForFinished();
QCoreApplication::exit();
}
};
};
For the subprocess calculator a simple script is used. You can see the where output is generated and where input is expected.
#/bin/bash
echo "Sub: Im calculator!"
# some processing here with occasionally feedback
sleep 3
echo "Sub: hallo"
sleep 1
echo "Sub: type"
# here the script blocks until some input with '\n' at the end comes via stdin
read BAR
# just echo what we got from input
echo "Sub: you typed: ${BAR}"
sleep 1
echo "Sub: Bye!"
If you do not need to do anything else in your main process (e.g. show a GUI, manage other threads/processes....), the easiest would be to just in a sleep in a loop after subprocess creation and then something like readSubprocess.

Determine if QProcess has finished executing or is awaiting user input (or response)

I have 2 bash scripts
One script not requiring user input, it displays info
The other requires some user input, and displays some info too
Problem:
When creating a QProcess, I am unable to differentiate if the QProcess is finished or is hanging for user input.
I was hoping for some function e.g. QProcess::atEnd that returns true if the script is finished, but it returns true even if the QProcess is hanging for user input (from script)
More Info:
Script requiring user input : name-please.sh
Script not requiring input : hello.sh
name-please.sh
#!/bin/bash
echo "I am Mr Robot"
echo "what is your name:"
read n
if [[ ! -z "$n" ]];
then
echo "please to meet you"
exit 0;
else
echo "ok, bye..."
exit 1;
fi
hello.sh
#!/bin/bash
echo "I am Mr Robot"
using mReadyReadStandardOutput(), I read the script output. The issue exists around the fact that I need to read the output, determine if the output contains a line that requests user info (line from the script) and respond to that.
see code with pointer to line
Code:
#include <QCoreApplication>
#include <QLoggingCategory>
#include <QTextStream>
#include <QProcess>
#include <QString>
#include <QVariant>
#include <QDebug>
#include <QObject>
#include <QEventLoop>
class m_Proc : public QProcess
{
Q_OBJECT
public:
int exitCode = -1;
QString _out, _input;
m_Proc(QString input = QString(), QObject *parent = 0);
~m_Proc() {}
public slots:
void myReadyReadStandardOutput();
void myFinished(int i);
};
m_Proc::m_Proc(QString input, QObject *parent)
{
connect(this,SIGNAL(readyReadStandardOutput()),
this,SLOT(myReadyReadStandardOutput()));
connect(this, SIGNAL(finished(int)),
this, SLOT(myFinished(int)));
}
void m_Proc::myReadyReadStandardOutput() {
// Note we need to add \n (it's like pressing enter key)
_out = this->readAllStandardOutput();
if (!_input.isEmpty()) {
/*
* check if line matches that of the script,
* where the user is required to enter their name
*/
if (_out.contains("what is your name")) { <<< ---- LINE WITH ISSUE
this->write(QString(_input + QString("\n")).toLatin1());
_out = this->readAllStandardOutput();
}
}
else
qDebug() << "Input Emptry (should not be reached!) !";
}
void m_Proc::myFinished(int i){
exitCode = i;
qDebug() << "exit code = " << QString::number(exitCode);
qDebug() << _out;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
m_Proc *myProcess1 = new m_Proc(QString("text"));
// QString program = "/home/dev/script";
myProcess1->start("/home/dev/script", QStringList());// << "one" << "two");
// myProcess1->start("/bin/sh", QStringList() << "-c" << "ls" << "-la");
a.exec();
}
#include "main.moc"
Any advice to bypass this issue?
Three things.
According to the documentation for QProcess::atEnd(), this returns true only if the process is not running (QProcess::NotRunning). So...are you sure the process isn't truly done when you call atEnd()? I don't see it anywhere in the code you've posted, so I can't tell.
Your myReadyReadStandardOutput() signal is overwriting the m_Proc::_out member variable each time new data is available. Depending on how writes to standard output are buffered on your system (and by Qt), you may be reading partial lines into _out. Thus the _out.contains() call may return false, because you've got something like at is your in the line, rather than the full what is your name:.
You write the member string _input to the process's standard input, and then immediately try to read again from the standard output. This will most likely not return any data that you didn't already have in _out. Qt only really does actual I/O with the underlying device when control returns to the main event loop. From the documentation for QIODevice:
Certain subclasses of QIODevice, such as QTcpSocket and QProcess, are asynchronous. This means that I/O functions such as write() or read() always return immediately, while communication with the device itself may happen when control goes back to the event loop.
My suggestion for solving your issue would be to modify the myReadyReadStandardOutput signal. For asynchronous devices (such as sockets and sub-processes), data may arrive in arbitrary-sized chunks. This is point 2 I made above. The usual method for dealing with this is to put something like the following at the top of the signal:
if (!canReadLine())
return;
So you bail out of the signal and return to the main event loop if a full line of data is not available. If that returns true, you can do something like:
_out = readLine();
/* Process an entire line, e.g., check if it matches the request for name */
So the signal is designed to operate only on full lines of data. This is useful for terminals or network protocols that are line-oriented. In this case, you can call the QString::contains() method to check if this is the line requesting a name, and, if so, write it. But you must then return to the event loop in order for the data to be written, so you'd process the next line (please to meet you) in the next call to the signal in which a full line is available.

Qt: How to get live output of a running QProcess

I have to get the output of a QProcess while it is running. Therefore I have written the following Code:
CommandExecutor_C::CommandExecutor_C():
mProcessStatus(AI_UNKNOWN),
mOnTdiActiveCallback(),
mTdiProcess(new QProcess)
{
connect(mTdiProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(CheckOutput()));
connect(mTdiProcess, SIGNAL(readyReadStandardError()), this, SLOT(CheckOutput()));
}
void CommandExecutor_C::ExecuteCommand(QString &aCommand)
{
mTdiProcess->start(aCommand, QProcess::Unbuffered | QProcess::ReadWrite);
LOGINFO(FB_TDI,"Launch command: " + aCommand.toStdString());
}
void CommandExecutor_C::CheckOutput()
{
QString StdOut = QString(mTdiProcess->readAllStandardOutput());
QString StdErr = QString(mTdiProcess->readAllStandardError());
mProcessStatus = CheckTdiAutomationInterface(StdOut.toStdString(), StdErr.toStdString());
if(mProcessStatus != AI_UNKNOWN)
{
OnTdiActive(mProcessStatus);
}
}
This works fine if QProcess gets finished but in my case the Process starts an automation interface which should run in background permanently. Therefore I have used "readyReadStandardOutput" and connect it to the slot CheckOutput(). CheckOutput() is getting called just if the process has been finished. Otherwise I am waiting endless.
I have googled a lot about the problem but nothing worked. I am very sure that the output is getting buffered and does just return if the Process has finished. Therefore I have started the Process in Unbuffered-Mode. I have also tried to forward the channels of mTdiProcess. Here the Code:
void CommandExecutor_C::ExecuteCommand(QString &aCommand)
{
mTdiProcess->setProcessChannelMode(QProcess::ForwardedChannels);
mTdiProcess->start(aCommand, QProcess::Unbuffered | QProcess::ReadWrite);
LOGINFO(FB_TDI,"Launch command: " + aCommand.toStdString());
}
But nothing worked. I hope you can help me.
I am using Qt 5.4.2 if that's important.
I usually check the output in regular intervals like this:
bool returnBool = false;
while (returnBool == false)
{
/*! Wait one second if the process finishes. Then read all output to
* stdout and stderr and redo. */
returnBool = process.waitForFinished(1000);
QString outputStdOut = process.readAllStandardOutput();
QString outputStdErr = process.readAllStandardError();
}

Serial connection does not work correctly with QPushbuttons

void CSerialController::sl_executeCommand(const QString s_command,QString&s_result){
QMutexLocker locker(mpo_mutex);
KT_Error t_error = ERROR_NONE;
QByteArray o_serialOutput;
QString s_serialAnswer = "";
char c_serialLetter = ' ';
// Port is already open
mpo_serial->clearBuffer(); // Flush and ReadAll
t_error = mpo_serial->sendStr(s_command); //
NO_SUCCESS(t_error)
{
Q_EMIT sg_throwError(t_error);
}
SUCCESS(t_error)
{
while ((t_error == ERROR_NONE) && (c_serialLetter != '\n')) // Reads Serial till newline is found
{
t_error = mpo_serial->getChar(c_serialLetter); // -> checks BytesAvailable -> if no bytes available -> waitForReadyRead(1) <- This is in a Loop while given time is over(Timeouttime)
o_serialOutput.append(c_serialLetter);
}
}
NO_SUCCESS(t_error)
{
Q_EMIT sg_throwError(t_error);
}
SUCCESS(t_error)
{
s_serialAnswer = o_serialOutput;
s_serialAnswer.remove("\r\n");
}
s_result = s_serialAnswer; }
Im working with C++ and Qt 5.5 and i cant get the serial connection to work correctly. Im using signals to connect a QPushButton with a slot in the CSerialController class which calls this function in the same class. I tried this function with a endless while-loop and it works correctly all the time. Its just not working when i use the buttons. First time i use a button it works correctly but the second time i press a button which calls this slot, the serialport only sometimes returns a value. (Writing works just not reading) I even tried changing the Thread of this class but that didnt help aswell. If you want i can post the sendStr and getChar functions aswell but like i said they work without a problem(allready used in a lot of projects)
UPDATE: I tried using the Windows API for the serial connection = problem is gone. Seems like a problem with QSerialPort usage on an old CPU (I7-870)

Outputting QProcess readAll response to label

I have a QProcess where i would like to output the response in a label. First off, here is what i have tried:
QProcess *proc = new QProcess();
proc->setProcessChannelMode(QProcess::MergedChannels);
proc->start(cmdLineRequest.toUtf8().constData()); // cmdLineRequest is omitted
if (!proc->waitForFinished()) {
qDebug() << "Make failed:" << proc->errorString();
ui->topBarcode->setText(QString(proc->errorString()));
} else {
qDebug() << "Make output:" << proc->readAll();
ui->topBarcode->setText(QString(proc->readAll()) + "asdf");
}
proc->readAll() is a QByteArray and setText accepts a QString. From what i've read, i should be able to cast the QByteArray to a QString, howver it does not work. I have also tried to convert proc->readAll() with the QString class
->setText(QString::fromUtf8(proc->readAll())) // not working
->setText(QString::fromLatin1(proc->readAll())) // not working
->setText(QString::fromLocal8Bit(proc->readAll())) // not working
... etc ...
It seems weird, since i'm adding pictures to labels in nearly the same matter using setPixmap(QPixmap::fromImage(image))
Any help appreciated, thank you.
Update:
If i add a QMessageBox before the end of the method that the above block of code belongs to, i can see the text added to the label. However when i close the QMessageBox, the text dissapears. Am i giving an address position to the label with proc->readAll() or how come this behaviour? Thank you.
The problem here is that you're calling proc->readAll twice; the first for the qDebug output and then again for the string which you set on the label.
{
qDebug() << "Make output:" << proc->readAll();
ui->topBarcode->setText(QString(proc->readAll()) + "asdf");
}
I expect that as QProcess is a QIODevice, it's returning a buffered byte array. When you read it, it removes that from the buffer.
Therefore, create a temporary string and read the buffer once, before calling qDebug and setting the string to the label: -
{
QString output = proc->readAll();
qDebug() << "Make output:" << output;
ui->topBarcode->setText(output + "asdf");
}
You should listen to readyReadStandardOutput() signal and call readAll() when you receive signal.
or you can call
bool waitForReadyRead(int msecs = 30000)
before calling readAll().