I wanted to execute the cmd command "wmic share get name" with QProcess and then save the result of the command in the QString variable. In further, I wanted to show it in QMessageBox or ... How can I do that?
You can use QProcess for this. Let's say I want to execute g++. Example:
QProcess p;
p.setProgram("g++");
p.setArguments({"-O3", "filename.cpp"});
p.start();
// wait for the process to finish executing
// returns true on success
if (!p.waitForFinished()) {
qDebug() << "Failed to execute!!";
const QString error = p.readAllStandardError();
if (!error.isEmpty()) {
qDebug () << "Exit status: " << p.exitStatus() << ", Error: " << error;
}
return;
}
// read output
const QString output = p.readAllStandardOutput();
qDebug () << output;
// read error
const QString error = p.readAllStandardError();
if (!error.isEmpty()) {
qDebug () << error;
}
//do whatever you want with output
Related
I am trying to get data out of slot with a signal readyRead(). But my method doesn't seem to work. I googled a lot but still I can't solve the problem.
Here what I have:
In my main function I call the method sendPOST() to get cookies. I got cookies from this method using inside of it SIGNAL finished(QNetworkReply *) and SLOT replyFinishedSlot_(QNetworkReply *) :
connect(manager_, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinishedSlot_(QNetworkReply *)));
I made a public static bool variable isFinished = false by default to write if slot is finished it's job.
replyFinishedSlot_(QNetworkReply ):
if(reply->error())
qDebug() << "Error: " << reply->errorString();
else
{
cookie = reply->manager()->cookieJar()->cookiesForUrl(webReportsUrl);
QString cookieString = cookie[0].name() + "=" + cookie[0].value() + "; domain=" + cookie[0].domain() + "; path=" + cookie[0].path() + ";";
if(reply->isFinished()) isFinished = true; //isFinished is static public variable
}
reply->deleteLater();
And then I check in my main function if isFinished is true, and if it is I connect to another slot:
manager_ = new QNetworkAccessManager(this);
sendPOST("http://url");
if(isFinished)
{
QNetworkAccessManager *man = new QNetworkAccessManager();
QNetworkRequest request(webReportsUrl);
request.setHeader(QNetworkRequest::CookieHeader, QVariant::fromValue(cookie));
getReply = man->get(request);
connect(getReply, SIGNAL(readyRead()), this, SLOT(readyReadSlot_()));
if(isRead)
qDebug() << "reading";
else qDebug() << "not reading";
}
and isFinished in here works very well (but I am not sure if this is the right way to check finished or not like this). I get isFinished == true, and I can get cookies from replyFinishedSlot_.
But the problem is to get data from readyReadSlot_(). I tried different ways to receive the data from this slot, but there's no successful result.
I tried even something like this:
QEventLoop loop;
connect(getReply, SIGNAL(readyRead()), &loop, SLOT(readyReadSlot_()));
loop.exec();
But I got the error:
QObject::connect: No such slot QEventLoop::readyReadSlot_() in ...
Inside readyReadSlot_() I have to receive all the data from the page:
if(getReply->isReadable())
{
if(getReply->error() != QNetworkReply::NoError)
{
qDebug() << "Error: " << getReply->errorString();
}
else {
isRead = true;
response = getReply->readAll(); //here the data I need outside of this slot
qDebug() << "response: " << response;
}
}
getReply->deleteLater();
And I get it successfully inside, but I need to get response outside of this slot, in my main function, for example.
I know here's something with a threads, and I just don't wait till the data recieved, but I don't know how can I fix it.
I found a problem solvation for me.
void DataMartsModel::replyFinishedSlot_(QNetworkReply *reply)
{
static bool isRead = false;
if(reply->error())
qDebug() << "Error: " << reply->errorString();
else
{
cookie = reply->manager()->cookieJar()->cookiesForUrl(webReportsUrl);
QString cookieString = cookie[0].name() + "=" + cookie[0].value() + "; domain=" + cookie[0].domain() + "; path=" + cookie[0].path() + ";";
QNetworkAccessManager *man = new QNetworkAccessManager();
QNetworkRequest request(webReportsUrl);
request.setHeader(QNetworkRequest::CookieHeader, QVariant::fromValue(cookie));
getReply = man->get(request);
connect(getReply, &QNetworkReply::readyRead, [=](){
if(getReply->isReadable())
{
if(getReply->error() != QNetworkReply::NoError) qDebug() << "Error: " << getReply->errorString();
else {
isRead = true;
}
}
});
if(reply->isFinished() && getReply->isReadable()) isFinished = true; //here is the problem solvation I wanted
}
reply->deleteLater();
}
main function
manager_ = new QNetworkAccessManager(this);
sendPOST("http://url");
if(isFinished)
{
QByteArray array = getReply->readAll(); //here I got the data I needed to get from readyReady
qDebug() << array; //here I display it and I can use them in the future
}
If you know better way to solve the problem, I would like to check it, too.
I created a library which will handle all HTTP requests and parsing of response data in JSON format. When I called the method that includes get request in my main application (with GUI), I received a memory corruption error. So I added QEventLoop and a timer to wait for the response before proceeding to other processes. I was able to get the response data by calling QNetworkReply.readall(). I needed to get the char* value of the response data so I called the QNetworkReply.data() but it is empty. Why?
Here are the codes I wrote:
Library which handles HTTP requests:
void HttpRequest::getRequest(string param1, string param2)
{
pManager_ = new QNetworkAccessManager(this);
QUrl cUrl(sampleUrl);
QNetworkRequest request(cUrl);
request.setRawHeader(keyHeader.c_str(), param1.c_str());
connect(pManager_, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
connect(pManager_, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError> & )), this,
SLOT(handleSslErrors(QNetworkReply*, const QList<QSslError> & )));
cUrl.addQueryItem("name", QString::fromStdString(param2));
pManager_->get(request); // memory corruption error encountered in main application after calling this
std::cout << "after calling get" << std::endl;
}
void HttpRequest::requestFinished(QNetworkReply *pReply)
{
QByteArray responseData;
std::cout << " request finished" << std::endl;
int responseStatus = pReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
std::cout << " status code: " << responseStatus << std::endl;
if(pReply->error())
std::cout << " Error: " << pReply->errorString().toStdString() << std::endl;
else
{
responseData = pReply->readAll();
qDebug() << " Response data: " << responseData;
const char* pResponseData = responseData.data();
qDebug() << "pResponseData: " << pResponseData ;
// parsing here
}
pReply->deleteLater();
pManager_->deleteLater();
}
void HttpRequest::handleSslErrors(QNetworkReply *pReply, const QList<QSslError> & )
{
std::cout << " SSL ERROR" << std::endl;
int responseStatus = pReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
}
Main GUI application:
DialogTest::DialogTest(QWidget *parent) :
QDialog(parent),
ui(new Ui::DialogTest)
{
// some codes here
if(enabled)
{
HttpRequest::instance()->getInformation(param1, param2); // memory corruption happened here when I called getRequest() method with no event loop
}
// other threads here
}
Here is the code that uses QEventLoop:
void HttpRequest::getRequest(string param1, string param2)
{
QTimer qTimer;
QEventLoop loop;
pManager_ = new QNetworkAccessManager(this);
QUrl cUrl(sampleUrl);
QNetworkRequest request(cUrl);
request.setRawHeader(keyHeader.c_str(), param1.c_str());
connect(&qTimer,SIGNAL(timeout()),&loop, SLOT(quit()));
connect(pManager_, SIGNAL(finished(QNetworkReply*)),&loop, SLOT(quit()));
QNetworkReply *pReply = pManager_->get(request);
qTimer.start(1000);
loop.exec();
int responseCode = pReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
std::cout << "status code: " << responseCode << std::endl;
if(pReply->error())
{
std::cout << " Error: " << pReply->errorString().toStdString() << std::endl;
}
else
{
qDebug() << "[HttpRequest] Response data: " << pReply->readAll();
QByteArray response = pReply->readAll(); // it printed this value: "{"count":3,"codes":["x00000A","x00000B","x00000C"]}" which is correct
char* pResponseData = response.data();
qDebug() << "pResponseData: " << pResponseData ; //it printed this: pResponseData:
}
delete pReply;
delete pManager_;
}
I am expecting this response data from a HTTP get command:
"{"count":3,"codes":["x00000A","x00000B","x00000C"]}"
Problem:
What is the best way to implement this? I want to put all HTTP request in a library then call it my main application with GUI. Please note that:
When I use QEventLoop inside the library to wait for the response, QNetworkReply.data() is empty. I need the value of QNetworkReply.data() for parsing.
When I did not use QEventLoop and use signal and slot alone (as shown in the code above), memory corruption occurred in main application after executing HTTP get command. No response data is received.
an advice:
never use a direct delete for a QObject. BAD:
delete pReply;
delete pManager_;
Qt way,GOOD:
pReply->deleteLater();
pManager->deleteLater();
Better: no "new" (dynamic memory)
QNetworkAccessManager Manager_;
...
connect(&Manager_, SIGNAL(finished(QNetworkReply*)),&loop, SLOT(quit()));
..
pReply->deleteLater();
Noted: this appears to be a specific issue question but hopefully it can be edited for all to related to
I need to interact with a QProcess object.
The Problem:
I am not getting any output from QProcess after calling QProcess:write(input)
More Info:
Going through the doc pages led me to create an example below:
I have a script requesting user input, and finally displaying and appropriate message based on the user input.
Testing:
After adding a "log" feature to my script for testing, the following occurs:
script executes
script requests user input (confirmed by the 'first' qDebug() << p->readAll())
script accepts input from QProcess (confirmed by script 'log output')
After this, no output is received. The following 2 debug statements both fire (i.e. wait 30s each)
if (!p->waitForReadyRead()) {
qDebug() << "waitForReadyRead() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
if (!p->waitForFinished()) {
qDebug() << "waitForFinished() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
Followed by:
QString s = QString(p->readAll() + p->readAllStandardOutput());
where s is an empty string.
The issue is s should contain either "success" or "failed"
Calling Code:
QString cmd = QString("sh -c \"/path/to/bashscript.sh\"");
QString input = QString("Name");
QString result = runCommand(cmd, input)
Process Code:
//takes 2 parameters,
// cmd which is the code to be executed by the shell
// input which acts as the user input
QString runCommand(QString cmd, QString input){
QProcess *p = new QProcess(new QObject());
p->setProcessChannelMode(QProcess::MergedChannels); //no actual reason to do this
p->start(cmd);
if (p->waitForStarted()) {
if (!p->waitForReadyRead()) {
qDebug() << "waitForReadyRead() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
if (!p->waitForFinished()) {
//reads current stdout, this will show the input request from the bash script
//e.g. please enter your name:
qDebug() << p->readAll();
//here I write the input (the name) to the process, which is received by the script
p->write(ps.toLatin1());
//the script should then display a message i.e. ("success" o "failed")
if (!p->waitForReadyRead()) {
qDebug() << "waitForReadyRead() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
if (!p->waitForFinished()) {
qDebug() << "waitForFinished() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
}
QString s = QString(p->readAll() + p->readAllStandardOutput());
return s;
}
else{
qDebug() << "waitForStarted() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
p->waitForFinished();
p->kill();
return QString();
}
script.sh (-rwxrwxr-x)
#!/bin/bash
#returns
# "success" on non empty $n value
# "failed: on empty $n value
#
echo "enter your name:"
read n
if [[ ! -z $n ]];
then
echo "success"
exit 0;
else
echo "failed"
exit 1;
fi
UPDATE
#KevinKrammer I modified the run command as you said, also using the QStringList with the args.
Still does not get output, infact the waitForReadyRead() and waitForFinished() returns false instantly.
Called with:
QString r = runCommand(QString("text"));
Process Code:
QString runCommand(QString input){
QProcess *p = new QProcess(new QObject());
p->setProcessChannelMode(QProcess::MergedChannels);
//script is the same script refered to earlier, and the `cd /home/dev` IS required
p->start("sh", QStringList() << "-c" << "cd /home/dev" << "./script");
;
if (p->waitForStarted()) {
if (!p->waitForReadyRead(5000)) {
qDebug() << "waitForReadyRead() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
qDebug() << p->readAll();
p->write(input.toLatin1());
if(!p->waitForFinished(5000)){
qDebug() << "waitForFinished() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
QString s = QString(p->readAll() + p->readAllStandardOutput());
return s;
}
else{
qDebug() << "waitForStarted() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
p->waitForFinished();
p->kill();
return QString();
}
Terminal Output of the Process:
started
readChannelFinished
exit code = "0"
waitForReadyRead() [false] : CODE: "5" | ERROR STRING: "Unknown error"
""
waitForFinished() [false] : CODE: "5" | ERROR STRING: "Unknown error"
Press <RETURN> to close this window...
Thoughts on this?
UPDATE 2
#Tarod Thank you for taking the time to make a solution.
It works, however not completely is expected.
I copied over your code, exactly.
Made a few changes in the mReadyReadStandardOutput()
See additional info below.
The problem:
After running the application (and script), I get a result -> AWESOME
Everytime it is the incorrect result i.e. "failed". -> NOT AWESOME
Terminal Output:
void MyProcess::myReadyRead()
void MyProcess::myReadyReadStandardOutput()
"enter your name:\n"
""
void MyProcess::myReadyRead()
void MyProcess::myReadyReadStandardOutput()
"failed\n"
Press <RETURN> to close this window...
script contents:
#!/bin/bash
echo "enter your name:"
read n
echo $n > "/tmp/log_test.txt"
if [[ ! -z "$n" ]];
then
echo "success"
exit 0;
else
echo "failed"
exit 1;
fi
/tmp/log_test.txt output
myname
running this manually from console:
dev#dev-W55xEU:~$ ls -la script
-rwxrwxr-x 1 dev dev 155 Jan 25 14:53 script*
dev#dev-W55xEU:~$ ./script
enter your name:
TEST_NAME
success
dev#dev-W55xEU:~$ cat /tmp/log_test.txt
TEST_NAME
Full code:
#include <QCoreApplication>
#include <QProcess>
#include <QDebug>
class MyProcess : public QProcess
{
Q_OBJECT
public:
MyProcess(QObject *parent = 0);
~MyProcess() {}
public slots:
void myReadyRead();
void myReadyReadStandardOutput();
};
MyProcess::MyProcess(QObject *parent)
{
connect(this,SIGNAL(readyRead()),
this,SLOT(myReadyRead()));
connect(this,SIGNAL(readyReadStandardOutput()),
this,SLOT(myReadyReadStandardOutput()));
}
void MyProcess::myReadyRead() {
qDebug() << Q_FUNC_INFO;
}
void MyProcess::myReadyReadStandardOutput() {
qDebug() << Q_FUNC_INFO;
// Note we need to add \n (it's like pressing enter key)
QString s = this->readAllStandardOutput();
qDebug() << s;
if (s.contains("enter your name")) {
this->write(QString("myname" + QString("\n")).toLatin1());
qDebug() << this->readAllStandardOutput();
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyProcess *myProcess = new MyProcess();
QString program = "/home/dev/script";
myProcess->start("/bin/sh", QStringList() << program);
a.exec();
}
#include "main.moc"
script issue? QProcess issue?
Unfortunately I don't have all your code, so I made an example. I hope it helps you.
If I compare my code to yours, I think the problem could be you are not calling readAllStandardOutput() after writing or maybe you are not calling exec() in your main.cpp.
#include <QCoreApplication>
#include <QProcess>
#include <QDebug>
class MyProcess : public QProcess
{
Q_OBJECT
public:
MyProcess(QObject *parent = 0);
~MyProcess() {}
public slots:
void myReadyRead();
void myReadyReadStandardOutput();
};
MyProcess::MyProcess(QObject *parent)
{
connect(this,SIGNAL(readyRead()),
this,SLOT(myReadyRead()));
connect(this,SIGNAL(readyReadStandardOutput()),
this,SLOT(myReadyReadStandardOutput()));
}
void MyProcess::myReadyRead() {
qDebug() << Q_FUNC_INFO;
}
void MyProcess::myReadyReadStandardOutput() {
qDebug() << Q_FUNC_INFO;
// Note we need to add \n (it's like pressing enter key)
this->write(QString("myname" + QString("\n")).toLatin1());
// Next line no required
// qDebug() << this->readAll();
qDebug() << this->readAllStandardOutput();
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyProcess *myProcess = new MyProcess();
QString program = "/home/fran/code/myscript.sh";
myProcess->start("/bin/sh", QStringList() << program);
a.exec();
}
#include "main.moc"
Script to test the application:
echo "enter your name:"
read n
if [ ! -z "$n" ];
then
echo "success"
exit 0;
else
echo "failed"
exit 1;
fi
noted: this is a use-specific question, but I hope others can benefit from this too
To get a basic sense of what I want to do:
QProcess runs a command by:
QProcess::start("sh -c \"cd /tmp/tempdir ; ./my_script --option file.txt ; echo $?\" ")
The script expects input from the user (a password), QProcess::readAll() confirms the script's input request. The input is given by QProcess::write().
Here I get lost! -> No output is received. from readAll() and readAllStandardOutput(), both are empty.
I need the output: particularly the echo $? for later processing, but don't get anything since readAll() and readAllStandardOutput() returns empty strings
To me there are several possible issues to cause this, maybe more than one:
The script does not receive this input
The script receives the input, but expects a "return key press"
The script receives the input, QProcess::write automatically does a "return key press", the script continues and finishes but QProcess does not read this output
The Code:
// please ignore the messiness of the code, a placed a number of debugs just to see the code response.
cmd = "cd /tmp/tempdir ; ./my_script --option file.txt ; echo $?" (without quotes)
input => required input for script
QString gen_serv::runCommand(QString cmd, QString input){
Process *p = new QProcess(parent);
p->setProcessChannelMode(QProcess::MergedChannels);
// p->start("sh ", QStringList() << " -c " << cmd);
QString c = QString("sh -c \"" + cmd + "\" ");
p->start(c); <---- ACTUAL COMMAND : sh -c "cd /tmp/tempdir ; ./my_script --option file.txt ; echo $?"
if (p->waitForStarted()) {
if (!p->waitForReadyRead()) {
qDebug(log_lib_gen_serv) << "waitForReadyRead() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
if (!p->waitForFinished(1000)) {
qDebug() << p->readAll();
qDebug() << p->readAllStandardOutput();
//p->write(input.toLatin1());
p->write(QString(input + QString("\n")).toLatin1()); <--- added this "\n" incase the process/console was waiting for a return press, thus the /n should satisfy the return requirement
qDebug() << p->readAll();
qDebug() << p->readAllStandardOutput();
if (!p->waitForFinished()) {
qDebug() << p->readAll();
qDebug() << p->readAllStandardOutput();
qDebug(log_lib_gen_serv) << "waitForFinished() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
qDebug() << p->readAll();
qDebug() << p->readAllStandardOutput();
}
QString s = QString(p->readAll() + p->readAllStandardOutput());
return s;
}
else{
qDebug(log_lib_gen_serv) << "waitForStarted() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
}
p->waitForFinished();
p->kill();
return QString();
}
Please note:
The script is long and complicated, however it returns a message "done" if successfully executed and an exit code for each case.
Thus the echo $? should capture and return this for processing i.e. return s
I hope this makes sense, any suggestions how I can attempt to solve this issue?
I'm currently create an apps in Meego using QML and JS on most of the part. and now I stumbled upon a problem.
From javascript I want to call a C++ function to read text file, parse it, and then return an array of the parsing result.
so I create a Q_INVOKABLE function called parse() and call it through javascript
function parse() {
var myArray = new Array();
myArray = parser.parse("/home/user/MyDocs/angklungtext.txt")
if(myArray === undefined){
console.log("null found");
}
for(var i = 0; i < myArray.length; i++){
console.log(myArray[i][0] + "," + myArray[i][1])
}
}
and here is the parse function in C++
QVariantList* QMLParser::parse(QString filename)
{
qDebug() << "start debugging";
qDebug() << filename;
qDebug() << QDir::currentPath();
QDir dir;
qDebug()<< dir.absoluteFilePath(filename);
QFile file(filename);
if(!file.exists())
{
qDebug() << "File: " << file.fileName() << "tidak ditemukan";
return NULL;
}
if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
qDebug() << "Tidak dapat membuka file" << file.fileName() << "untuk ditulis";
return NULL;
}
QTextStream stream(&file);
QVariantList* myList = new QList<QVariant>;
while(!stream.atEnd())
{
QString line = stream.readLine();
qDebug() << line.trimmed();
QStringList lineList = line.split(":");
myList->append(lineList);
}
file.close();
return myList;
}
sadly.
when I try to run it it giving a result like this
start debugging
"/home/user/MyDocs/angklungtext.txt"
"/home/developer"
"/home/user/MyDocs/angklungtext.txt"
"1:1000"
"4:2000"
"5:3000"
"2:4000"
null found
file:///opt/memoryreader/qml/memoryreader/myjs.js:8: TypeError: Result of expression 'myArray' [undefined] is not an object.
looks like the C++ parse function successfully parsing the file. it can read it and it can save it into the QVariantList.
but after it return the result into javascript myArray still [undefined].
is there something wrong with the conversion?
Just simplify the C++ side like this :
QVariant QMLParser::parse(QString filename)
{
QStringList myList;
qDebug() << "start debugging";
qDebug() << filename;
qDebug() << QDir::currentPath();
QDir dir;
qDebug() << dir.absoluteFilePath(filename);
QFile file(filename);
if(!file.exists()) {
qDebug() << "File: " << file.fileName() << "tidak ditemukan";
return NULL;
}
if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "Tidak dapat membuka file" << file.fileName() << "untuk ditulis";
return NULL;
}
QTextStream stream(&file);
while(!stream.atEnd()) {
QString line = stream.readLine();
qDebug() << line.trimmed();
myList << line.trimmed().split(":");
}
file.close();
return QVariant::fromValue(myList);
}
And it should work !
Just remember, QML must see a QVariant, even if a QList is wrapped inside it, and Qt is able to convert most of its base types to QVariant using QVariant::fromValue(T) so use it extensively.
Oh and BTW a QVariant is reference not pointer.
Haven't done this myself, so I'm just thinking out loud. But I note that you're returning a pointer to a QVariantList...which looks suspect. (Also: if you new, then who would do the delete?)
Have you tried returning it by value?