Qt QProcess startDetached can't end process (bash session) - c++

I'm trying to call a shell script from a Qt GUI, but after running the script, the bash session stays open when it should finish.
Having this code:
QString s = "./script.sh " + argument;
qint64 *pid = NULL;
QProcess process;
process.startDetached("/bin/bash", QStringList() << "-c" << s, NULL, pid);
bool finished = process.waitForFinished(-1);
std::cout << "ended";
So after running the script, it is expecting a command to be entered, I can put any command and it will execute it. The problem is that it never finishes until I enter a command.
I also tried modifying the s variable like this:
QString s = "./script.sh " + argument + " ;exit";
hoping that it would end up the bash session, but nothing happens.
If instead of using the function startDetached I use start it does close the bash session without the ;exit command.
Hope someone knows how to solve it or a workaround!

startDetached() is a static method; you started a new process, but it's not represented by the process object.
When you wait for process to finish, it will wait forever, because process was never started.
Try something like:
process.start("/bin/bash", QStringList() << "-c" << s);
bool finished = process.waitForFinished(-1);
You might want to redirect I/O before start().

Related

Using QProcess to read standard output

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

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.

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

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);
}

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.