Problems with QProcess, process output

I am trying to figure out the use of QProcess. I did not look at the Qt doc. http://doc.qt.io/qt-4.8/qprocess.html

EXAMPLES OF THE PROBLEM.

Example 1: The code below works.

#include <QtCore/QCoreApplication> #include <QTextStream> #include <QByteArray> #include <QProcess> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QTextStream qout(stdout); QProcess cmd; cmd.start("cmd"); if (!cmd.waitForStarted()) { return false; } cmd.waitForReadyRead(); QByteArray result = cmd.readAll(); //qout << result.data() << endl; //console junk captured, don't show. //My test command cmd.write("echo hello"); cmd.write("\n"); //Capture my result cmd.waitForReadyRead(); //This is my command shown by cmd, I don't show it, capture & discard it. result = cmd.readLine(); //Read result of my command ("hello") and the rest of output like cur dir. result = cmd.readAll(); qout << result.data(); qout << "\n\n---End, bye----" << endl; return a.exec(); } 

output of the above code

Hello

 F:\Dev_Qt\expControllingExtConsoleApps-build-desktop> ---End, bye---- 

The problem is that if I try to use ipconfig or 7zip this way using the Qprocess and cmd console, I cannot see any output from ipconfig or 7zip. I donโ€™t know if something has been done, if something has been done, why donโ€™t I see a way out? Below is the code below.

Example 2: Doesn't work. Unable to use ipconfig.

 #include <QtCore/QCoreApplication> #include <QTextStream> #include <QByteArray> #include <QString> #include <QProcess> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QTextStream qout(stdout); QProcess cmd2; cmd2.setWorkingDirectory("C:/Program Files/7-Zip"); //not needed in this example. cmd2.setReadChannel(QProcess::StandardOutput); cmd2.setProcessChannelMode(QProcess::MergedChannels); cmd2.start("cmd"); if (!cmd2.waitForStarted()) { qout << "Error: Could not start!" << endl; return false; } cmd2.waitForReadyRead(); QByteArray result = cmd2.readAll(); qout << result.data() << endl; //Console version info, etc. //My command cmd2.write("ipconfig"); cmd2.write("\n"); //Capture output of ipconfig command //DOES NOT WORK!! cmd2.waitForReadyRead(); while (! cmd2.atEnd()) { result = cmd2.readLine(); qout << result; result.clear(); } qout << endl; qout << "\n\n---end----" << endl; return a.exec(); } 

The result is below, there is no information about the result of connecting ipconfig. No output from ipconfig is written at all.

Microsoft Windows XP [version 5.1.2600] (C) Copyright 1985-2001 Microsoft Corp.

C: \ Program Files \ 7-Zip> ipconfig

--- end ----

It must be more like this (with ipconfig result).

Microsoft Windows XP [version 5.1.2600] (C) Copyright 1985-2001 Microsoft Corp.

C: \ Documents and Settings \ Noname> IPCONFIG

Windows IP Address Configuration

Ethernet adapter local area network Connection:

  Connection-specific DNS Suffix . : IP Address. . . . . . . . . . . . : 192.172.148.135 Subnet Mask . . . . . . . . . . . : 255.255.255.0 Default Gateway . . . . . . . . . : 192.172.148.177 

C: \ Documents and Settings \ noname>

Obviously, the output should have been slightly different than the above, but the connection information, which is the ipconfig output, should have been captured. Similarly, if I try to use 7zip through the cmd console ... I cannot see / write any 7zip output. So my question is: how can I use command line applications like ipconfig and 7zip through QProcess and cmd console and see the output of these applications?

Example 3: 7zip does not work

 #include <QtCore/QCoreApplication> #include <QTextStream> #include <QByteArray> #include <QProcess> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QTextStream qout(stdout); QProcess cmd2; cmd2.setWorkingDirectory("C:/Program Files/7-Zip"); cmd2.setReadChannel(QProcess::StandardOutput); cmd2.setProcessChannelMode(QProcess::MergedChannels); cmd2.start("cmd"); if (!cmd2.waitForStarted()) { return false; } //My Command cmd2.write("7z.exe"); cmd2.write("\n"); //Capture output of ipconfig command cmd2.waitForReadyRead(); QByteArray result; while (! cmd2.atEnd()) { result = cmd2.readLine(); qout << result; result.clear(); } qout << endl; qout << "\n\n---end----" << endl; return a.exec(); } 

The conclusion is below. Does not show anything from 7zip.

Microsoft Windows XP [version 5.1.2600] (C) Copyright 1985-2001 Microsoft Corp.

C: \ Program Files \ 7-Zip> 7z.exe

--- end ----

It is expected that the output will be performed line by line ...

Microsoft Windows XP [version 5.1.2600] (C) Copyright 1985-2001 Microsoft Corp.

C: \ Documents and Settings \ noname> cd C: \ Program Files \ 7-Zip

C: \ Program Files \ 7-Zip> 7z.exe

7-Zip 9.15 beta Copyright (c) 1999-2010 Igor Pavlov 2010-06-20

Usage: 7z [...] [...] [& L; @listfiles ...>]

a: Add files to archive
b: Test d: delete files from the archive e: Extract files from the archive (without using the names directory) l: List of archive contents
t: Check archive integrity u: Update files to x: eXtract archive files with full paths
-ai [r [- | 0]] {@listfile |! wildcard}: Enable archives
-ax [r [- | 0]] {@listfile |! wildcard}: eXclude archives -bd: disable percentage
-i [r [- | 0]] {@listfile |! wildcard}: Include file names -m {Parameters}: compression method -o {Directory}: set Output directory -p {Password}: set password -r [- | 0]: subdirectories Recurse -scs {UTF-8 | WIN | DOS}: set the encoding for the list files -sfx [{name}]: create an SFX archive -si [{name}]: read data from stdin -slt: show technical information for the l (List) -so command: write data to stdout -ssc [-]: set sensitive case mode -ssw: compress shared files
-t {type}: Set archive type -u [-] [p #] [q #] [r #] [x #] [y #] [z #] [! newArchiveName]: Update options -v {Size} [b | k | m | g]: Creating volumes -w [{path}]: assign the working directory. Empty path means temporary directory
-x [r [- | 0]]] {@listfile |! wildcard}: eXclude filenames -y: accept Yes all requests

C: \ Program Files \ 7-Zip>

+4
source share
2 answers

eI see one big problem. Under the windows, you issue a character by pressing the Enter key. Record

 cmd.write("command"); cmd.write("\n"); 


just not enough you need to write

 cmd.write("command"); cmd.write("\n\r"); 

Pay attention to the final \ r. Try this, it should work better, and better I mean 7zip. I do not know if you will earn ipconfig correctly.

Good luck and best wishes.
D

EDIT Here is a working solution:

 #include <QtCore/QCoreApplication> #include <QtCore/QProcess> #include <QtCore/QString> #include <QtCore/QTextStream> // Not clean, but fast QProcess *g_process = NULL; // Needed as a signal catcher class ProcOut : public QObject { Q_OBJECT public: ProcOut (QObject *parent = NULL); virtual ~ProcOut() {}; public slots: void readyRead(); void finished(); }; ProcOut::ProcOut (QObject *parent /* = NULL */): QObject(parent) {} void ProcOut::readyRead() { if (!g_process) return; QTextStream out(stdout); out << g_process->readAllStandardOutput() << endl; } void ProcOut::finished() { QCoreApplication::exit (0); } int main (int argc, char **argv) { QCoreApplication *app = new QCoreApplication (argc, argv); ProcOut *procOut = new ProcOut(); g_process = new QProcess(); QObject::connect (g_process, SIGNAL(readyReadStandardOutput()), procOut, SLOT(readyRead())); QObject::connect (g_process, SIGNAL(finished (int, QProcess::ExitStatus)), procOut, SLOT(finished())); g_process->start (QLatin1String ("cmd")); g_process->waitForStarted(); g_process->write ("ipconfig\n\r"); // Or cmd won't quit g_process->write ("exit\n\r"); int result = app->exec(); // Allright, process finished. delete procOut; procOut = NULL; delete g_process; g_process = NULL; delete app; app = NULL; // Lets us see the results system ("pause"); return result; } #include "main.moc" 

Hope this helps. He worked every time on my car.

+4
source

Despite the fact that Dariusz Sarsigig has already provided a solution to the problem, I would like to indicate what I consider to be the actual problem (s) that can be solved using the signal slot mechanism.

Problem 1. The condition in your while loop is based on bool QProcess::atEnd () const , which corresponds to the QProcess Documentation :

Reimplemented from QIODevice :: atEnd ().

Returns true if the process does not work and there is no more data to read; otherwise returns false.

But if you look at the QIODevice :: atEnd () documentation, it says:

Returns true if the current read and write position is at the end of the device (i.e. there is no more data to read on the device); otherwise returns false.

For some devices, atEnd () may return true, even if there is more data to read. Only this special case applies to devices that generate data in direct response to you calling read () (for example, / dev or / proc files on Unix and Mac OS X, or console input / stdin on all platforms ).

Solution 1. Change the condition of the while loop to check the status of your process: while(cmd2.state()!=QProcess::NotRunning){ .

Problem 2. You are using cmd2.waitForReadyRead(); out of cycle. Perhaps some data is ready for reading now, and when you finish reading, some of them become available:

  • you read the commands you just wrote: ipconfig\n
  • ipconfig takes some time to start and send text to the console. But by then you were already out of the loop because atEnd() gave true, even if your process is still running.

Solution 2. put waitForReadyRead() inside your loop.

Corollary 2. waitForReadyRead() will tell you when there is data that may be more than one row, so you should also change cmd2.ReadLine() to cmd2.ReadAll() .

Problem 3. As described in QProcess :: closeWriteChannel ()

Closing the write channel is necessary for programs that read input until the channel is closed.

Solution 3. One of the following options should work when you finish writing your entries.

  • End the process: cmd2.write("exit\n");
  • close Writechannel: cmd2.closeWriteChannel();

Work code:

 #include <QtCore/QCoreApplication> #include <QTextStream> #include <QByteArray> #include <QString> #include <QProcess> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QTextStream qout(stdout); QByteArray result; QProcess cmd2; cmd2.setReadChannel(QProcess::StandardOutput); cmd2.setProcessChannelMode(QProcess::MergedChannels); cmd2.start("cmd"); if (!cmd2.waitForStarted()){ qout << "Error: Could not start!" << endl; return 0; } cmd2.write("ipconfig\n"); cmd2.closeWriteChannel(); //done Writing while(cmd2.state()!=QProcess::NotRunning){ cmd2.waitForReadyRead(); result = cmd2.readAll(); qout << result; } qout << endl << "---end----" << endl; return a.exec(); } 

I wrote this answer to explain how I understand your problem and found a solution, but I would like to emphasize that the Preferred solution is to use the Signal / Slot Mechanism introduced by Dariusz .

+4
source

All Articles