QProcess issue in executing a exe with arguments - c++

I have a issue in setting the QProcess to run executable with the arguments. The Qt code for the same is as below,
QString program = "C:\Setup.exe";
QStringList arguments;
arguments << "-uninstall";
QProcess::startDetached(program, arguments);
The output of this snippet is to uninstall some program. But it is not happening. Am i doing any mistake?
But if I go to cmd prompt and execute the same thing like.,
c:/> "C:/Setup.exe" -uninstall
This works perfectly.

There are at least two options to solve your issue.
Use '/' for directory separators as per documentation:
If you always use "/", Qt will translate your paths to conform to the underlying operating system.
Escape the backslash whenever working with file paths as string as per an example from the documentation:
env.insert("TMPDIR", "C:\\MyApp\\temp"); // Add an environment variable
env.insert("PATH", env.value("Path") + ";C:\\Bin");
Therefore, you should be writing something like this:
QString program = "C:/Setup.exe";
QStringList arguments;
arguments << "-uninstall";
QProcess::startDetached(program, arguments);
or this:
QString program = "C:\\Setup.exe";
QStringList arguments;
arguments << "-uninstall";
QProcess::startDetached(program, arguments);
In general, when facing such issues, you could always print out the error string to get more information by using the following syntax:
qDebug() << myProcess.errorString();
This, for sure, needs an instance, however.

Related

What is the correct way to execute a CMD command with QProcess to get the output as QString?

I'm new using QT, I need to execute a CMD command on windows and get the output of this command as a string to later process and get specific data. The following code works well (it seems to work well). The only problem is that I get the following warning: "start is deprecated", I think this warning message is because the start method needs an arguments list as parameter.
QString command = "tasklist /FI \"IMAGENAME eq notepad.exe\"";
QProcess *executeCommand = new QProcess();
executeCommand->start(command);
executeCommand->waitForFinished(-1);
QString output = executeCommand->readAllStandardOutput();
executeCommand->terminate();
qDebug() << commandOutput;
how can I remove this warning message?
Also I found in the web that I can use system() to execute a CMD command, but I'm not able to catch the output as string.
Another question: which of the above options is better to achieve what I'm trying to do, the QProcess or System (if is possible to get the output as QString)?
Thanks in advance!
There is an answer read QProcess output to string recommending static method QProcess::readAllStandardOutput() returning QByteArray. Then just instantiate QString from QByteArray implicitly.
If you are working on Qt application, it is better to stay inside Qt API to keep the code more or less portable.

How to check if a program exists in path using Qt?

I have this code:
QProcess* proceso = new QProcess();
QString programa = "unknow -v";
proceso->start(programa);
proceso->waitForFinished();
QString normal = proceso->readAllStandardOutput();
QString errores = proceso->readAllStandardError();
qDebug() << normal;
qDebug() << errores;
The output I get is:
""
""
But I want get and error that says: Command not found.
Thanks in advance.
EDITED:
I found this solution using Qt:
int result = system("unknow -v");
if(result!=0) {
qDebug() << "No está instalado nasm";
} else {
qDebug() << "Está instalado.";
}
But I want get an output into a QString.
You could fetch the value of your PATH using getenv("PATH") then split it on colons (or semi-colons for Windows), iterate on every directory there, test that it contains a unknow file, etc....
So you don't need any Qt thing for that. Just plain C++ (string operations).
(this is not bullet-proof: some other process might modify a directory in your $PATH between such a test and the actual start of process; but it should often be enough in practice)
On POSIX systems, you might run your command thru sh -c (e.g. run sh -c 'unknow -v'), but be careful of escapes and code injections (so check the string unknow -v for things like single and double quotes, etc...)
You could also use popen(3) perhaps using which but I don't recommend that (too complex).
I am not sure it is worth the trouble anyway. Why don't you simply just run the program.... I don't see much difference between a missing executable and a command failing for many other reasons.
Please try this:
QProcess program;
QString commandToStart= "unknown -v";
QStringList environment = program.systemEnvironment();
program.start(commandToStart);
bool started = program.waitForStarted();
if (!program.waitForFinished(10000)) // 10 Second timeout
program.kill();
int exitCode = program.exitCode();
QString stdOutput = QString::fromLocal8Bit(program.readAllStandardOutput());
QString stdError = QString::fromLocal8Bit(program.readAllStandardError());
If started is true, the program could be started. That usually means, it was in the path. If it's false, check whether the path in environment is correct.
The exitCode is only helpful, if the process could actually be started and something else went wrong. If the program could not be started at all, exitCode will be 0 and stdOutput and stdError will be empty! That may be misleading.
The question is about if you are able to run the command aka if the command exists on your system. This means NOT trying to launch it and see what happens, huge difference!
How about this?
I like the idea of which but it won't work under Windows, AFAIK.
QProcess findProcess;
QStringList arguments;
arguments << myCommand;
findProcess.start("which", arguments);
findProcess.setReadChannel(QProcess::ProcessChannel::StandardOutput);
if(!findProcess.waitForFinished())
return false; // Not found or which does not work
QString retStr(findProcess.readAll());
retStr = retStr.trimmed();
QFile file(retStr);
QFileInfo check_file(file);
if (check_file.exists() && check_file.isFile())
return true; // Found!
else
return false; // Not found!

Qt - How to output Windows PowerShell error message via QProcess

I am working in Qt 4.7, and I have a program that needs to use a QProcess to output the result of running a Windows PowerShell command. For the purposes of this question, let's say all that needs to be supported is use of the "-Command" option. Right now I have this:
QString path = "C:/windows/system32/WindowsPowerShell/v1.0/powershell.exe";
QStringList command;
command.append("-Command");
command.append(/*Whatever test command I want to use...*/);
process = new QProcess(); //Note: QProcess *process is a member of this class
connect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(/*slot to print qprocess errors...*/);
connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(/*slot to display PowerShell output...*/);
process->start(path, command);
The slot to print the PowerShell output is simply as follows:
std::cout << "RESULT: " << QString(process->readAllStandardOutput()).toStdString() << std::endl;
This works perfectly with correct PowerShell commands. For example, I tested it with the command "Get-ChildItem C:\", and it printed the correct data. It also works fine if there is a QProcess error. What I need to know how to do is, how can I have it print a PowerShell error message? For example, if I try to use the command "Get-ChildIte" (missing the m at the end) directly in PowerShell I get an error message. But with my code, it just doesn't print anything. I need it to print that error message. If anyone knows of a way this could be done, I'd really appreciate it. Thanks!
Ok, you posted your answer 7 seconds ago. I just wanted to confirm, and give a link to reference for you that may help troubleshoot this in the future.
QProcess Class
Yes, you want the readAllStandardError() function of QProcess.
So, about a minute after I posted this I discovered QProcess's signal readyReadStandardError(), which operates identically to readyReadStandardOutput except that it is emitted when whatever the QProcess is running has an error. I connected this to a slot identical to what I have above but instead printing QString(process->readAllStandardError()).toStdString() and it worked.

Problems passing source command to bash from c++ application

I am developing an application for work that allows the users to quickly set environment variables on a terminal basis. By setting the path in each terminal we ensure files with the same name in different directories aren't causing application testing to be problematic. I am Using Qt to build the program which is c++ based and all the datatypes are foundationally the same.
I am using the following code to invoke commands in the terminal from which the application launches from using system(). I can run commands into the bash just fine with code; however, I run into a problem when I attempt to use a command with arguments. This is probably why source doesn't seem to work right as the source command is followed by the filename. It would appear that I drop the argument appended after the bash command.
My Code:
void assignTerminalToPath(QString path)
{
QString data = "";
QString currentUsersHomeDirectory = QDir::homePath();
QString tmpScriptLocation = currentUsersHomeDirectory;
QByteArray ba;
tmpScriptLocation += "/.tmpSourceFile";
QFile tmpSourceFile(tmpScriptLocation);
if(tmpSourceFile.open(QFile::WriteOnly | QFile::Truncate))
{
QTextStream output(&tmpSourceFile);
data.append("export PATH=.:");
data.append(path);
data.append(":$PATH");
output << QString("#!/bin/bash\n");
output << data;
tmpSourceFile.close();
}
data.clear();
data.append("/bin/bash -c source ");
data.append(tmpScriptLocation);
ba = data.toLatin1();
const char *cStr = ba.data();
system(cStr);
}
Perhaps I'm not referencing bash correctly and I need something outside of -c?
Reference Execute shell/bash command using C/C++
Thanks for any help in advance!
source is not a program that you can call, it is embedded bash command. It is designed to be processed by bash without invoking another copy of bash, such that environment variables can be changed in current bash copy.
However, you cannot call source as part of system(). And even if you did succeed at that, its effects to change environment variables would be completely lost for caller app once system() has returned.
Try a command to envelop with parameters in double quotes ("command - arg1 - to arg2") to transfer in the function system().
used:
char *com = "\"command -arg1 -arg2\"";
system(com);

QProcess not working on win32 systems?

The process method is not working if I pass the user home directory programmatically in windows XP and windows 32 bit systems
The below code works fine:
QProcess process;
process.execute("C:/DOCUME~1/pjo/myprok/tmp/APP.exe");
Not working Code:
Here I am getting the path of the APP.exe using QDir::homePath
process.execute("C:/Documents and Settings/pjo/myprok/tmp/APP.exe");
The errorString returns "UnKnown error"
I tried with start method also which never works:
B Not working Code:
process.start("C:/Documents and Settings/pjo/myprok/tmp/APP.exe");
Error: Path Not found
process.start("C:/DOCUME~1/pjo/myprok/tmp/APP.exe");
Error : Unknown error
execute() is a static function, so it should be called like this:
QProcess::execute("C:/Documents and Settings/pjo/myprok/tmp/APP.exe");
You are saying that you get the home directory programmatically, but the code you show does not do that. Maybe you are creating the path like this:
QProcess::execute(QDir::homePath() + "APP.exe");
and then the path will miss / between directory and filename like this:
"C:/Documents and Settings/pjo/myprok/tmpAPP.exe"
Your issue is probably due quoting issues caused by the spaces in the path (C:\Documents and Settings...).
Note that there are two overloads for start():
void start ( const QString & program, OpenMode mode = ReadWrite )
void start ( const QString & program, const QStringList & arguments, OpenMode mode = ReadWrite )
You are using the first, which takes the executable path and all args in one string, and expects it to be quoted correctly. Without quoting, "c:\documents" is interpreted as the executable and "and" "Settings..." etc. as the arguments.
The second version takes the arguments separately, and will interpret the executable path correctly, without any quoting needed. Thus, the easiest way is to use
process.start("C:/Documents and Settings/pjo/myprok/tmp/APP.exe", QStringList());
This ensure the second version to be used, and should save you from all quoting issues.
I suggest to always use that overload.
The same applies to execute(), which is, as already said, a static method, so the error codes of the QProcess object won't be set.