Using QProcess to read standard output - c++

In my QT widget application I am attempting to run a shellscript that opens a C++ program and provides inputs to the program as well. The program starts a command prompt that requires the users input to start. Once the program is started the output of the program is redirected via the standard output to a text file. I am attempting to use QProcess to open and run this shellscript, then read the standard output that is being used to print the result of the C++ program to the text file. The shell script only runs this process and does not terminate it. This is because I need to continuously read this output into the GUI as the program is running. It will not be sufficient to wait until the program is finished to read this information. I am fairly new to QT and C++ programming. I was hoping that someone could help me with my implementation of this.
QProcess process;
process.start("/home/pi/Desktop/ShellScripts/RunTutorial3.sh");
QString output =process.readAllStandardOutput();
qDebug() << output;
QString err = process.readAllStandardError();
qDebug() << err;
I have experimented with using other read function such as readline and also trying to start the process as a detatched process. I have not had success with any of my experimentations. Is it possible to do what I am attempting in QT. I just need the program to run continuously and for QT to read this output every so often.
Shell script:
#!/bin/bash
cd
cd Desktop
cd tutorial3App
cd bin
echo "start" | ./tutorial3
C++ code: I need the meanTOE value to be captured in standard output to use in my GUI.
/ Calculate average time to end of discharge
double meanToE = std::accumulate(ToESamples.begin(), ToESamples.end(), 0.0)/ToESamples.size();
file << ": EOL in " << meanToE << " s" << std::endl;

As I said in my comments one of the main problems is that when you run tutorial3 that process is separated so you can not get the output. Therefore, I recommend executing it directly, and QProcess is probably a local variable, eliminating after printing an empty text, a possible solution is to create a pointer. Another improvement would be to use the readyReadStandardOutput and readyReadStandardError signals since the impressions are not automatic.
QProcess *process = new QProcess(this);
connect(process, &QProcess::readyReadStandardOutput, [process, this](){
QString output =process->readAllStandardOutput();
qDebug() << "output: "<< output;
});
connect(process, &QProcess::readyReadStandardError, [process](){
QString err = process->readAllStandardError();
qDebug() << "error: "<<err;
});
process->setWorkingDirectory("/home/pi/Desktop/tutorial3App/bin/")
process->start("tutorial3", QStringList() << "start");

I think you have to read about signals and slots in Qt. QProcess has got a signal readyReadStandardOutput. So you have to connect to this signal and in your slot you should use QProcess function readAllStandardOutput. In other words when your shell programm outputs something you catch it in your slot and dump it or whatever you want.
Check the answer on this question. It might help you.
reading and writing to QProcess in Qt Console Application

Related

Control ubuntu terminal from Qt C++

I want to write a routine that will automatically change my Machine learning parameters and execute the (Machine learning) code multiple times and save its result into a text file.
The Machine learning code is run from the Ubuntu terminal and its result also are written to the Ubuntu terminal.
I need a way to read data and write data to the Ubuntu terminal from the C++ code.
What I have found so far is the QProcess:
QProcess process;
process.start("gnome-terminal"); //THE TERMINAL IS OPENED INDEED
char w[] = "write";
process.write(w,sizeof(w));
process.waitForFinished();
But nothing is written or read from it
What does working is:
QProcess process1;
QProcess process2;
process1.setStandardOutputProcess(&process2);
process1.start("echo 0534230313");
process2.start("sudo -S poweroff");
process2.setProcessChannelMode(QProcess::ForwardedChannels);
And also this works:
int result = system("echo 0534230313 | sudo -S poweroff"); ///COMMANDS TO TERMINAL
int result2 = system("gnome-terminal"); ///OPEN TERMINAL
But the problem is that I wont be able to read the output result (My Machine learning program can open and write to the terminal by itself)
Use the finished signal to read the process output results
connect( poProcess, static_cast<void (QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished),
[=](int,QProcess::ExitStatus)
{
QByteArray oProcessOutput=
poProcess->readAllStandardOutput();
// Parse the process output.
//
// Mark process for deletion.
emit poProcess->deleteLater();
});

Running windows command prompt commands in a Qt application

I need to run an external exe through Qt application which requires commands to be entered in windows command prompt.
QString exePath = "C:\Windows\system32\cmd.exe";
QProcess pro;
pro.start(exePath);
pro.execute("cmd.exe");
But I got output like below plain cmd prompt
But I want windows command prompt like expected cmd
You need to read from QProcess standart output and print it on screen.
You can use pro.waitForReadyRead() and if it returns true do
QByteArray arr = pro.readAllStandardOutput();
QString str(arr);
qDebug() << str;
Better decision is to use signal slot mechanism and implement onReadyToRead() slot and connect QProcess readyReadStandardOutput() signal to it.
pro.start(exePath);
pro.execute("cmd.exe");
You should not use this two methods at same time, QProcess::execute is static member.
You need to start process detached:
QString exePath = "C:\Windows\system32\cmd.exe";
QProcess pro;
pro.startDetached(exePath);
pro.waitForStarted();
//Event Loop here

C++ Run Batch file as standalone process and kill and remove argv[0]

Let's imagine I have following code:
ofstream selfdelfile;
selfdelfile.open("selfdel.bat",ios::out);
selfdelfile << "del \"" << argv[0] << "\"" << endl;
selfdelfile << "del %0";
selfdelfile.close();
system("cmd /K selfdel.bat &");
C++ Application creates/writes file selfdel.bat with following lines
del "C:\Users\temp\test_app.exe"
del %0
So, Batch should remove/delete the exe application, and itself.
So heres trouble: since C++ app runs batch by system("selfdel.bat") theres no way to delete exe application, the output says Process can't be terminated. Ofc, C++ app is waiting for batch, and batch cannot delete .exe.
I was trying, to Kill process, delte file, e.t.c.
SO how to do that? May be Start a new Process or Thread? Could someone provide an simple example C++ runs Batch , and Batch removes itself + application. Thank you
I found the working solution for me, just by adding "start" before batchfile
system("start selfdel.bat &");
Now batch opens in a new windows, and c++ application is getting closed and deleted.

Qt - How to output Windows PowerShell error message via QProcess

I am working in Qt 4.7, and I have a program that needs to use a QProcess to output the result of running a Windows PowerShell command. For the purposes of this question, let's say all that needs to be supported is use of the "-Command" option. Right now I have this:
QString path = "C:/windows/system32/WindowsPowerShell/v1.0/powershell.exe";
QStringList command;
command.append("-Command");
command.append(/*Whatever test command I want to use...*/);
process = new QProcess(); //Note: QProcess *process is a member of this class
connect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(/*slot to print qprocess errors...*/);
connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(/*slot to display PowerShell output...*/);
process->start(path, command);
The slot to print the PowerShell output is simply as follows:
std::cout << "RESULT: " << QString(process->readAllStandardOutput()).toStdString() << std::endl;
This works perfectly with correct PowerShell commands. For example, I tested it with the command "Get-ChildItem C:\", and it printed the correct data. It also works fine if there is a QProcess error. What I need to know how to do is, how can I have it print a PowerShell error message? For example, if I try to use the command "Get-ChildIte" (missing the m at the end) directly in PowerShell I get an error message. But with my code, it just doesn't print anything. I need it to print that error message. If anyone knows of a way this could be done, I'd really appreciate it. Thanks!
Ok, you posted your answer 7 seconds ago. I just wanted to confirm, and give a link to reference for you that may help troubleshoot this in the future.
QProcess Class
Yes, you want the readAllStandardError() function of QProcess.
So, about a minute after I posted this I discovered QProcess's signal readyReadStandardError(), which operates identically to readyReadStandardOutput except that it is emitted when whatever the QProcess is running has an error. I connected this to a slot identical to what I have above but instead printing QString(process->readAllStandardError()).toStdString() and it worked.

Command Line closing despite using QProcess::startDetached()

I'm trying to open a server via batch file in cmd.exe in my Qt application. Despite I'm using QProcess::startDetached() to start the command line it closes immediately after start. The server is starting, but instead of "serving" the process is killed. Here is my code:
void DICOMReceiver::startReceiver()
{
QProcess receiver;
boost::filesystem::path dbDir = boost::filesystem::absolute(databaseDirectory.toStdString());
receiver.startDetached("cmd.exe", QStringList() << "/c" <<
"dcmrcv.bat" << "AETitle:11112" << "-dest " << dbDir.string().c_str());
receiver.waitForStarted();
}
When I run the batch file manually in the cmd.exe it is working as desired.
Does anybody have an idea how to keep the process running so that I can use the server?
startDetached is a static function. You don't need a process instance.
You should pass a working directory to startDetached. For all I know it "closes" because the batch file doesn't exist where it's looking for it.
Your waitForStarted() call is a no-op since the startDetached method does not know anything about your receiver instance. You simply wrote obfuscated C++ that deceives you. There is no way to wait for a detached process to start when using Qt. A detached process is fire-and-forget.
Do not use waitForXxx methods, as they block the thread they're in, and make the UI unresponsive. Use signal-slot connections and write asynchronous code instead.
So, your method should be fixed as follows:
void DICOMReceiver::startReceiver()
{
boost::filesystem::path dbDir =
boost::filesystem::absolute(databaseDirectory.toStdString());
// FIXME
const QString batchPath = QStringLiteral("/path/to/the/batch/file");
QProcess::startDetached("cmd.exe", QStringList() << "/c"
<< "dcmrcv.bat" << "AETitle:11112" << "-dest "
<<< dbDir.string().c_str(), batchPath);
}