I am trying to figure out the use of QProcess. I looked at Qt doc with no luck.
http://doc.qt.io/qt-4.8/qprocess.html
EXAMPLES OF PROBLEM.
Example 1: Code bellow 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();
}
The output of the above code is
hello
F:\Dev_Qt\expControllingExtConsoleApps-build-desktop> ---End, bye----
The problem is that if I try to use ipconfig or 7zip in this fashion via Qprocess and cmd console, I am unable to see any output from ipconfig or 7zip. I don't know if anything is even done, if something is done then why can't i see the output? Code bellow illustrates.
Example 2: Does not work. Can't 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();
}
Output is bellow, it is missing the ipconfig connection information result. No output from ipconfig is captured at all.
Microsoft Windows XP [Version 5.1.2600] (C) Copyright 1985-2001 Microsoft Corp.
C:\Program Files\7-Zip> ipconfig
---end----
Should have been 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 Configuration
Ethernet adapter Local Area 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 should have been a little diff than above but the Connection info wich is the output of "ipconfig" should have been captured. In the same way if I try to use 7zip via cmd console... I can not see/capture any output of 7zip. So my question is how can I use command line apps like ipconfig and 7zip via QProcess and cmd console and see the result of 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();
}
Output bellow. 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----
Output is expected to be along the lines of...
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 [...] [...] [<@listfiles...>]
a: Add files to archive
b: Benchmark d: Delete files from archive e: Extract files from archive (without using directory names) l: List contents of archive
t: Test integrity of archive u: Update files to archive x: eXtract files with full paths
-ai[r[-|0]]{@listfile|!wildcard}: Include archives
-ax[r[-|0]]{@listfile|!wildcard}: eXclude archives -bd: Disable percentage indicator
-i[r[-|0]]{@listfile|!wildcard}: Include filenames -m{Parameters}: set compression Method
-o{Directory}: set Output directory -p{Password}: set Password -r[-|0]: Recurse subdirectories -scs{UTF-8 | WIN | DOS}: set charset for list files -sfx[{name}]: Create SFX archive -si[{name}]: read data from stdin -slt: show technical information for l (List) command -so: write data to stdout -ssc[-]: set sensitive case mode -ssw: compress shared files
-t{Type}: Set type of archive -u[-][p#][q#][r#][x#][y#][z#][!newArchiveName]: Update options -v{Size}[b|k|m|g]: Create volumes -w[{path}]: assign Work directory. Empty path means a temporary directory
-x[r[-|0]]]{@listfile|!wildcard}: eXclude filenames -y: assume Yes on all queriesC:\Program Files\7-Zip>
eI see one big problem. Under windows you issue a commend pressing the Enter key. Writing
just isn't enough you have to write
Notice the trailing \r. Try this, it should work better, and by better I mean 7zip. I don't know if you'll get ipconfig to work properly.
Good luck and best regards
D
EDIT Here is a working solution:
Hope that helps. It worked everytime on my machine.
Even though Dariusz Scharsig already provided a solution to the problem, I would like to point out what I believe to be the actual problem(s) which can be solved using the signal slot mechanism.
Problem 1. The condition in your while loop is based on
bool QProcess::atEnd () const
which is according to QProcess Documentation states:But if you looking the documentation for QIODevice::atEnd(), it states:
Solution 1. Change the while loop condition to check the state of your process:
while(cmd2.state()!=QProcess::NotRunning){
.Problem 2. You use
cmd2.waitForReadyRead();
outside of the loop. Perhaps some data is ready for reading now and when you finished reading, some more gets made available:ipconfig\n
atEnd()
gave true even though your process is still running.Solution 2. place the
waitForReadyRead()
inside your loop.Consequence 2.
waitForReadyRead()
will tell you when there is data available, which could be more than one Line, so you should consequently also change thecmd2.ReadLine()
tocmd2.ReadAll()
.Problem 3. As documented in QProcess::closeWriteChannel()
Solution 3. One of the following options should work when finished writing your inputs
cmd2.write("exit\n");
cmd2.closeWriteChannel();
Working code:
I wrote this answer just to explain the way I understand your problem and found a solution but would like to emphasize that the Preferable Solution is to use the Signal/Slot Mechanism as presented by Dariusz.