Getting Exitcode from Powershell from within C++ Program with QProcess - c++

I wonder if someone has an Answer for this Problem.
I use QProcess to start a Powershell script. The start of the QProcess is initiated from a QThread. This Thread finishes like expected but the QProcess never calls its readyReadStandardOutput() Signal nor its finished() Signal. Both are bound to 2 different slots and I can see that the script gets executed and I also know that the script finshes with an exitCode.
My goal with this is basically to read the Exitcode of the Powershell script I wrote. I tried different approaches but could not find a solution to get the Exitcode of the Powershell script which is either ran with cstdlib function system() or QProcess. So I decided I would read it from stdout. For that I would simply print the $LastExitCode before exiting the script and read that from within the C++ Program.
Thanks in advance.
Edit:
Updated example:
main.cpp
#include <QtCore/QCoreApplication>
#include <QTextStream>
#include "ManagerClass.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTextStream wrappedStream(stdin);
QString scriptPath;
if (argc < 2)
{
std::cout << "Path to script:" << "\n";
wrappedStream >> scriptPath;
}
ManagerClass manager(scriptPath);
return a.exec();
}
ManagerClass.h
#pragma once
#include <QObject>
#include <QProcess>
#include <iostream>
#include "ExecutionThread.h"
class ManagerClass : public QObject
{
Q_OBJECT
public:
ManagerClass(const QString& p_scriptPath, QObject *parent = nullptr);
~ManagerClass();
public slots:
void threadFinished();
void processStarted();
void processFinished(int exitCode, QProcess::ExitStatus exitStatus);
private:
ExecutionThread m_thread;
const QString SCRIPT_PATH;
};
ManagerClass.cpp
#include "ManagerClass.h"
ManagerClass::ManagerClass(const QString& p_scriptPath, QObject* parent)
: QObject(parent), SCRIPT_PATH(p_scriptPath)
{
m_thread.getProcessPointer();
m_thread.registerScriptPath(p_scriptPath);
QObject::connect(m_thread.getProcessPointer(), QOverload<int, QProcess::ExitStatus> ::of(&QProcess::finished), this, &ManagerClass::processFinished);
QObject::connect(m_thread.getProcessPointer(), &QProcess::started, this, &ManagerClass::processStarted);
QObject::connect(&m_thread, &ExecutionThread::finished, this, &ManagerClass::threadFinished);
m_thread.start();
}
ManagerClass::~ManagerClass() {}
void ManagerClass::processFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
std::cout << " Process finished successfully." << "\n";
std::cin.get();
}
void ManagerClass::threadFinished()
{
std::cout << " Thread finished successfully." << "\n";
}
void ManagerClass::processStarted()
{
std::cout << " Process started." << "\n";
}
ExecutionThread.h
#pragma once
#include <QThread>
#include <QProcess>
#include <iostream>
class ExecutionThread : public QThread
{
Q_OBJECT
public:
ExecutionThread();
~ExecutionThread();
void run();
void registerScriptPath(const QString& p_scriptPath);
QProcess* getProcessPointer();
signals:
void finished();
private:
QProcess* m_Process;
QString m_scriptPath;
};
ExecutionThread.cpp
#include "ExecutionThread.h"
ExecutionThread::ExecutionThread() : m_Process(new QProcess) {}
ExecutionThread::~ExecutionThread()
{
std::cout << "ExecutionThread::~ExecutionThread()";
}
void ExecutionThread::run()
{
QStringList commands;
m_Process->start(m_scriptPath, commands);
emit finished();
}
void ExecutionThread::registerScriptPath(const QString& p_scriptPath)
{
m_scriptPath = p_scriptPath;
}
QProcess* ExecutionThread::getProcessPointer()
{
return m_Process;
}
EDIT:
I solved the issue I was facing with always getting 1 as Exitcode.
It turns out that I misunderstood the Qt API for QProcess.
Still I dont get Signals from that QProcess object when it finishes.
The above Example uses m_Process->start() and there is no signal whenever the given powershell script finishes. As mentioned before m_Process->execute() doesnt signal anything too.

Related

Qt QNetworkAccessManager post method works only in main thread

I have a problem with Qt QNetworkAccessManager. I want to use it to interact with my web server which propose an POST api.
In my main function, I can use QNetworkAccessManager::post(). My server receive the data from the client.
But if I move the post function in another thread, my server receive anything.
Here an example of my code :
Worked code :
#include <iostream>
#include <QNetworkRequest>
#include <QUrl>
#include <QNetworkAccessManager>
#include <QCoreApplication>
#include <thread>
#include <QThread>
#include <QObject>
#include <QNetworkReply>
class PostClass: public QObject {
Q_OBJECT
public:
PostClass() {
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onfinish(QNetworkReply*)));
};
QNetworkAccessManager* manager = nullptr;
public slots:
void post() {
const QUrl url("http://[ip:port]/users");
QNetworkRequest req(url);
manager->get(req);
QNetworkRequest req1(QUrl("[ip:port]/event"));
req1.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
qDebug() << "Send new request";
QByteArray data(R"({"data": "QtGroupHEllo"})");
manager->post(req1, data);
};
void onfinish(QNetworkReply* rep) {
qDebug() << "reply delete!";
rep->deleteLater();
qDebug() << "https post_request done!";
};
};
class ThreadTmp: public QThread {
Q_OBJECT
public:
ThreadTmp() = default;
public slots:
void onfinish(QNetworkReply* rep) {
rep->deleteLater();
qDebug() << "reply delete!";
qDebug() << "https post_request done!";
};
signals:
void postRequest();
protected:
void run() override {
while (1) {
emit postRequest();
sleep(1);
}
}
};
int main(int argc, char* argv[]) {
QCoreApplication app (argc, argv);
std::cout << "Hello, World!" << std::endl;
PostClass postObj;
ThreadTmp tmp();
QObject::connect(&tmp, SIGNAL(postRequest()), &postObj, SLOT(post()));
tmp.start();
return app.exec();
}
#include "main.moc"
But if I move the PostClass instance in my ThreadTmp class, in the run function, only get works and post doesn't work because in my server, I only received the get request and not the post request :
#include <iostream>
#include <QNetworkRequest>
#include <QUrl>
#include <QNetworkAccessManager>
#include <QCoreApplication>
#include <thread>
#include <QThread>
#include <QObject>
#include <QNetworkReply>
class PostClass: public QObject {
Q_OBJECT
public:
PostClass() {
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onfinish(QNetworkReply*)));
// connect(manager, SIGNAL(finished(QNetworkReply*)), manager, SLOT(deleteLater()));
};
QNetworkAccessManager* manager = nullptr;
public slots:
void post() {
const QUrl url("http://[ip:port]/users");
QNetworkRequest req(url);
manager->get(req);
QNetworkRequest req1(QUrl("http://[ip:port]/event"));
req1.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
qDebug() << "Send new request";
QByteArray data(R"({"data": "QtGroupHEllo"})");
manager->post(req1, data);
};
void onfinish(QNetworkReply* rep) {
qDebug() << "reply delete!";
rep->deleteLater();
qDebug() << "https post_request done!";
};
};
class ThreadTmp: public QThread {
Q_OBJECT
public:
ThreadTmp() = default;
public slots:
void onfinish(QNetworkReply* rep) {
rep->deleteLater();
qDebug() << "reply delete!";
qDebug() << "https post_request done!";
};
signals:
void postRequest();
protected:
void run() override {
PostClass postObj;
connect(this, SIGNAL(postRequest()), &postObj, SLOT(post()));
while (1) {
emit postRequest();
sleep(1);
}
}
};
int main(int argc, char* argv[]) {
QCoreApplication app (argc, argv);
std::cout << "Hello, World!" << std::endl;
ThreadTmp tmp();
tmp.start();
return app.exec();
}
#include "main.moc"
I don't know why I have this behavior ...
You need to use a blocking .exec() in order to have an event loop in a thread. Just overriding run(), causes the thread to fire off that code and then terminate. When you post via the QNetworkAccessManager, that actually occurs asynchronously, in the background, driven by the QEventLoop out of the box. It should not typically be necessary to use another thread, if you are interacting with a simple REST api, or even if using a get() to download a large file. Qt handles for you, what you are probably trying to avoid with another thread, i.e. clogging up the main thread and hindering performance with network traffic. The best reason to use another thread would be to process the response from the server in the event that's going to take a long time. To do that, just hook up the signals/slots across threads, while leaving the post operation / network manager in your main one. (Generally speaking of course...)

QT: manage the reply from a QNetworkReply

I'm new in QT development and I've to make a non-gui application that reads a token from a POST request and then launches some json requests using that token. My problem is what to do when the finished signal is launched. I've tried to pass the reply.readAll() to a QByteArray parameter of the object, but when I do this the value is always empty (""). My code was done based on this.
.h
#ifndef DOWNLOADER_H
#define DOWNLOADER_H
#include <QObject>
#include <QNetworkAccessManager>
class QNetworkReply;
class Downloader : public QObject
{
Q_OBJECT
public:
Downloader(QObject* parent=0);
void test();
bool finished = false;
QByteArray data;
public slots:
void handleReply(QNetworkReply* reply);
protected:
QNetworkAccessManager m_manager;
};
#endif // DOWNLOADER_H
.cpp
#include "downloader.h"
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QVariant>
#include <QDebug>
Downloader::Downloader(QObject *parent) :
QObject(parent)
{
connect(&m_manager, SIGNAL(finished(QNetworkReply*)), SLOT(handleReply(QNetworkReply*)));
}
void Downloader::test() {
QNetworkRequest request;
QUrl url("http://192.168.25.25:8080/path/to/token");
QUrl postData;
postData.addQueryItem("client_id", "foo");
postData.addQueryItem("username", "bar");
postData.addQueryItem("password", "12345");
postData.addQueryItem("grant_type", "password");
request.setUrl(url);
request.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded");
QNetworkReply* rep = m_manager.post(request,postData.encodedQuery());
rep->setProperty("url", QVariant(url));
qDebug() << "Post " << rep << rep->url();
}
void Downloader::handleReply(QNetworkReply *reply) {
qDebug() << "Handle" << reply << reply->url();
qDebug() << "Dynamic property" << reply->property("url").isValid() << reply->property("url");
qDebug() << "ReadAll " << reply->readAll();
finished = true;
data =reply->readAll();
reply->deleteLater();
}
In main, the call is:
Downloader down;
down.test();
while (!down.finished)
{
usleep(3*1000*1100);//3,3s
cout << "no finalizado";
}
What I'm trying to do is to use the reply to fill a parameter and use this parameter from the main, when the finished bool is true. I know it's not correct, but I don't know how to manage the asynchronous nature of the request. What I need it's some guide to understand what I'm doing, since I've been searching in qt page, stackoverflow and others without success. Thanks in advance.
Update: my main function
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Downloader down;
down.test();
return a.exec();
}
In class Downloader, declare a signal to emit the data to a slot of another QObject derived class. For example, in Downloader::handleReply you call emit dataReady(data). In the main function add below code:
Downloader down;
JsonSender obj;
connect(&down, &Downloader::dataReady, &obj, &JsonSender::dataReady);
down.test();
return a.exec();
In the slot dataReady of class JsonSender you can parse the token and send the request.

QProcess do not run an external application

I can run an external application using the following command:
system("/home/felippe/Área\\ de\\ Trabalho/Felippe/Mestrado/C_plus_plus/Codigos/build-Registration_ITK_CMAKE-Desktop_Qt_5_12_3_GCC_64bit-Default/Registration_ITK_CMAKE")
And the application runs successfully. But the system(.) command blocks the other commands until the application finishes. So I tried to implement this command in QT using the following code:
.h
#ifndef FOO_H
#define FOO_H
#include <QObject>
#include <iostream>
#include <QProcess>
class foo : public QObject
{
Q_OBJECT
public:
explicit foo(QObject *parent = nullptr);
signals:
public slots:
void process_started();
void processError(QProcess::ProcessError error);
private:
QProcess *process;
};
#endif // FOO_H
.cpp
#include "foo.h"
foo::foo(QObject *parent) : QObject(parent)
{
process = new QProcess();
bool status = QObject::connect( process, SIGNAL( started() ), this, SLOT( process_started() ) );
connect(process, &QProcess::errorOccurred, this, &foo::processError);
QString file = "/home/felippe/Área de Trabalho/Felippe/Mestrado/C_plus_plus/Codigos/build-Registration_ITK_CMAKE-Desktop_Qt_5_12_3_GCC_64bit-Default/Registration_ITK_CMAKE";
process->start(file);
std::cout << file.toStdString() << std::endl;
std::cout << "status: " << status << std::endl;
}
void foo::process_started()
{
std::cout << "It worked" << std::endl;
}
void foo::processError(QProcess::ProcessError error)
{
std::cout << "error enum val = " << error << std::endl;
}
main
#include <QCoreApplication>
#include <iostream>
#include "foo.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
foo *f = new foo();
return a.exec();
}
When I run the process->start(file); I receive a error with value of 0, but when I run process->start(file, {"sudo"}); I receive a signal that the program run successfully, but anything is showed on the screen.
I'm trying to run on UBUNTU 16.04.
So, what is happening?
The most obvious difference is that system passes your string to the shell, while QProcess::start takes a command and argument list separately.
I bet you will get "file not found" if you hook to the errorOccurred signal.
Solution: remove the \\ from your string, as those are only needed if a shell is involved.

How to pass user input form the console to an object in a diffrent thread -> QTcpsocket

I am trying to create an Application that lets the user input an integer value and then sends it via tcp to my esp32.
I have set up my esp32 as a tcp server which connects to my wifi router and than shows its ipv4 adress via serial Monitor. The esp32 is connected to 2 stepperdriver and shall later control them with the data from the Application.
So my Application is working when the data that has to be sent is known before runtime for example i could create a const char* variable with the desired data and then simply send it with socket->write(foo);.
But thats not working for me because i need to get input from the console at runtime and then pass it to the function socket->write(). The problem there is that the QTcpSocket Object has to be in another thread. So i am stuck at figuring out how to pass data in between threads.
I tried to use the signal and slot mechanism to do so which if i correctly understood is meant to be used for that.
Especially this line gives me a huge headache. (the line is in the main function)
emit IO->doSendData(IO->getInput());
I try to emit the signal doSendData and pass the input from the console to the connected slot sendData() which is a method from the network class which object is in the threadNET and the object thats getting the input from the console lives in the main thread i guess thats the problem here but i have no glue how to fix it.
I dont get any error messages in QTcreator.
Thanks in advance for taking your time to help me.
If something is unclear feel free to ask me anything. Thats my first post on Stack overflow and i would appreciate any feedback on how to increase the quality of my question.
Complete code
main.cpp
//MAIN
#include <QCoreApplication>
#include <network.h>
#include <userio.h>
#include <QThread>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QThread* threadNET = new QThread();
network* net = new network();
userIO* IO = new userIO();
net->moveToThread(threadNET);
QObject::connect(threadNET,
&QThread::started,
net,
&network::Connect);
QObject::connect(IO,
&userIO::doSendData,
net,
&network::sendData);
threadNET->start();
while(true)
{
emit IO->doSendData(IO->getInput());
}
return a.exec();
}
network.h
//NETWORK HEADER
#ifndef NETWORK_H
#define NETWORK_H
#include <QObject>
#include <QTcpSocket>
#include <QAbstractSocket>
#include <QString>
#include <QDebug>
#include <iostream>
#include <string>
class network : public QObject
{
Q_OBJECT
public:
explicit network(QObject *parent = nullptr);
~network();
signals:
void finished(QString ffs);
void error(QString err);
public slots:
void Connect();
void sendData(QString dataToSend);
private:
QTcpSocket *socket;
};
#endif // NETWORK_H
userIO.h
//USERIO HEADER
#ifndef USERIO_H
#define USERIO_H
#include <QObject>
#include <QString>
#include <iostream>
#include <QDebug>
#include <limits>
#include <string>
class userIO : public QObject
{
Q_OBJECT
public:
explicit userIO(QObject *parent = nullptr);
QString getInput();
signals:
void doSendData(QString dataToSend);
public slots:
};
#endif // USERIO_H
network.cpp
//NETWORK SOURCE
#include "network.h"
network::network(QObject *parent) : QObject(parent)
{
}
network::~network()
{
}
void network::Connect()
{
socket = new QTcpSocket(this);
socket->connectToHost("192.168.179.167", 80);
if(socket->waitForConnected(5000))
{
std::cout << "Connected to TcpServer";
}
else
{
qDebug() << "Error: " << socket->errorString();
}
emit finished("send help");
}
void network::sendData(QString dataToSend)
{
qDebug() << "sendData" << dataToSend << "\n";
std::string convert = dataToSend.toStdString();
const char* formattedData = convert.c_str();
socket->write(formattedData);
}
userIO.cpp
//USERIO SOURCE
#include "userio.h"
userIO::userIO(QObject *parent) : QObject(parent)
{
}
QString userIO::getInput()
{
std::string rawInput;
qDebug() << "Enter the amount of steps to go\n";
std::cin >> rawInput;
while(std::cin.fail())
{
qDebug() << "Invalid input only Integer numbers are allowed\n";
qDebug() << "try again...\n";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cin >> rawInput;
}
QString convert;
convert.fromStdString(rawInput);
return convert;
}
QString::fromStdString(const std::string &str)
is a static member that returns a copy of the str string.
calling convert.fromStdString(rawInput); does not store copied string in convert !!
you need to write :
convert = QString::fromStdString(rawInput)
OR
direct initialization:
...
QString convert(QString::fromStdString(rawInput));
return convert;

QThread terminate and affinity

This example is for testing QThread. The main objective is to be able to run one time consuming blocking method in a dedicated thread and
being able to terminate and restart the thread at any point. The blocking method is a 3rd party lib which is outside our control. I know the documentation of Qt discourages using QThread::terminate but at the moment I do not see any other way.
Below is a pseduo example of the code needed to run in a dedicated thread. There is basically one method which can take 10-15 minutes to process. There is no logical place to add moveToThread to take the affinity back to main thread on QThread::termination, or executiong processEvent to handle a QThread::quit() method.
void run()
{
// initiate variables
thirdparty lib(var1, var2);
int res = lib.execute(var3, var4, var6);
// handle result and exit
}
Using Qt 4.7 on Windows 7.
Running the code produces this output
Test::doWork thread: QThread(0x219e960)
Test::started thread: QThread(0x239bce8)
Test::doTerminate thread: QThread(0x239bce8)
Test::doWork thread: QThread(0x239bce8)
QObject::moveToThread: Current thread (0x219e960) is not the object's thread (0x239bce8). Cannot move to target thread (0x239bd20)
The moveToThread API fails on the second execution of the Test::doWork() method. This appears to be because the Test instance has affinity to another thread (which is terminated at this point). How can I then change the affinity?
What is the recommended way to terminate and restart a QThread? Do I need to delete the Test instance?
The code;
#include <QCoreApplication>
#include <QThread>
#include <iostream>
#include <QDebug>
#include "Worker.h"
#include "Windows.h"
class Test : public QObject
{
Q_OBJECT
QThread* m_thread;
int m_state;
public:
Test() : m_thread(0), m_state(3) { }
public slots:
void doWork()
{
qDebug() << "Test::doWork thread:" << QObject::thread();
if (!m_thread)
{
m_thread = new QThread();
QObject::moveToThread(m_thread);
QObject::connect(m_thread, SIGNAL(started()), this, SLOT(started()));
QObject::connect(m_thread, SIGNAL(finished()), this, SLOT(finished()));
QObject::connect(m_thread, SIGNAL(terminated()), this, SLOT(terminated()));
m_thread->start();
}
}
void started()
{
qDebug() << "Test::started thread:" << QObject::thread();
Sleep(60);
}
void finished()
{
qDebug() << "Test::finished thread:" << QObject::thread();
}
void terminated()
{
qDebug() << "Test::terminated thread:" << QObject::thread();
}
void doTerminate()
{
qDebug() << "Test::doTerminate thread:" << QObject::thread();
QObject::disconnect(m_thread);
m_thread->terminate();
m_thread->wait();
m_thread = NULL;
}
int state()
{
return m_state;
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Test test;
test.doWork();
Sleep(10);
test.doTerminate();
Sleep(10);
test.doWork();
return a.exec();
}
Instead of using terminate, you can call the more acceptable function quit().