I've some problems with killing a process using taskkill.
My code:
QStringList args;
args << "/F";
args << "/IM testApp.exe";
QProcess::execute("taskkill", args); //Should be 'taskkill /IM testApp.exe /F'
Output (translated from german):
ERROR: Invalid argument - "/IM testApp.exe".
Type "TASKKILL /?" to show the syntax.
"/IM testApp.exe" makes a single arg, but should be two args. You get the command taskkill /F "/IM testApp.exe". The proper invocation is
QStringList args;
args << "/F";
args << "/IM";
args << "testApp.exe";
QProcess::execute("taskkill", args);
Related
QProcess p;
QString aa = "tasklist /FI 'IMAGENAME x32dbg.exe' /FO LIST | findstr 'PID:'";
aa.replace(0x27,0x22);
qInfo() << aa;
p.start(aa.toStdString().c_str());
p.waitForFinished();
qInfo() << "Output:" << p.readAllStandardOutput() << "Error:" << p.readAllStandardError();
// returned error <ERROR: Invalid argument/option - 'x32dbg.exe\"'.\r\nType \"TASKLIST /?\" for usage.\r\n">
qebug return
{tasklist /FI \"IMAGENAME x32dbg.exe\" /FO LIST | findstr \"PID:\"}
the correct text must be
{tasklist /FI "IMAGENAME eq x32dbg.exe" /FO LIST | findstr "PID:"}
i tried with \"
and add the command line in const char *
all return same result
The problem is you cannot run pipes with QProcess, but only a single process. The workaround would be to pass your command as an argument to cmd.exe:
QProcess p;
p.start("cmd.exe", QStringList() << "/C" << "tasklist /FI \"IMAGENAME x32dbg.exe\" /FO LIST | findstr \"PID:\"");
QDebug's quoting option enabled by default, so use noquote().
bool isRunning(const QString &process) {
QProcess tasklist;
tasklist.start(
"tasklist",
QStringList() << "/NH"
<< "/FO" << "CSV"
<< "/FI" << QString("IMAGENAME eq %1").arg(process));
tasklist.waitForFinished();
QString output = tasklist.readAllStandardOutput();
qInfo() << output ;
I need to pass some specific arguments from one programm to another using boost::program_options and boost::process. Here is a simple example. In this example I need to pass all args stored in vm_slave to child process, but in common case I wanna pass one or more specific args from vm_slave.
#include <iostream>
#include <boost/process.hpp>
#include <boost/program_options.hpp>
using namespace std;
namespace po = boost::program_options;
int main(int argc, char* argv[]) {
po::options_description tester_options("Tester options");
po::options_description slave_options("Slave options");
tester_options.add_options()
("help,h", "Show help")
("iter,i", po::value<short>()->default_value(1), "TODO")
("modules,m", po::value<std::vector<string>>()->multitoken(), "TODO");
slave_options.add_options()
("size,s", po::value<size_t>()->required(), "TODO")
("threads,t", po::value<short>()->default_value(1), "TODO");
po::variables_map vm;
po::variables_map vm_slave;
auto p0 = po::command_line_parser(argc, argv).options(tester_options).allow_unregistered().run();
auto p1 = po::command_line_parser(argc, argv).options(slave_options).allow_unregistered().run();
po::store(p0, vm);
po::store(p1, vm);
po::store(p1, vm_slave);
// Do some stuff such as write help if needed
// ...
// I need call child process with all (or specific) args from vm_slave
boost::process::ipstream pipe;
boost::process::child cp(
"slave" /* + vm_slave args */,
boost::process::std_err > pipe,
boost::process::std_out > pipe
);
cp.wait();
return 0;
}
Of course I can do something like this:
ostringstream args;
for (const auto& arg : p1.options) {
if (vm_slave.count(arg.string_key) == 0)
continue;
args << arg.string_key << " ";
for (const auto& val : arg.value)
args << val << " ";
}
string cmd_args = args.str();
But in this case some args stored in vm_slave by default is lost.
Or I can do this:
ostringstream args;
for (const auto& arg : vm_slave) {
args << arg.first << " ";
const auto& any_val = arg.second.value();
if (boost::any_cast<size_t>(any_val))
args << to_string(boost::any_cast<size_t>(any_val));
else if (boost::any_cast<short>(any_val))
args << to_string(boost::any_cast<size_t>(any_val));
// And more and more casts...
args << " ";
}
But now we have many any_cast...
If I just pass argv to child process, the child might fail because extra args presented (args like iter not intended for this application).
All this attempts seem bad to me.
What is the proper way to convert parsed arguments back to command line?
There is no "proper way" - as composing command lines is not a feature of the library (neither is writing config-files).
I would use the parsed options. Unless you need to interpret the options you don't have to notify/store into a variable map at all:
std::vector<std::string> passthrough;
for (auto& opt : p1.options) {
if (opt.unregistered || opt.string_key.empty())
continue;
assert(p1.description == &slave_options);
auto& tok = opt.original_tokens;
fmt::print("passing through {}: {}\n", opt.string_key, tok);
passthrough.insert(passthrough.end(), tok.begin(), tok.end());
}
Demoing, using printf instead of slave:
if (vm.count("help")) {
std::cout << tester_options << "\n\n" << slave_options << "\n";
} else {
// demo using printf '- %q\n'
passthrough.insert(passthrough.begin(), " - %q\n");
bp::child cp("/usr/bin/printf", passthrough);
cp.wait();
}
See it Compiler Explorer
running ./sotest -i 1000 -m some modules to follow -h
Tester options:
-h [ --help ] Show help
-i [ --iter ] arg (=1) TODO
-m [ --modules ] arg TODO
Slave options:
-s [ --size ] arg TODO
-t [ --threads ] arg (=1) TODO
running ./sotest -i 1000 -m some modules to follow -s=89 -t42
passing through size: ["-s=89"]
passing through threads: ["-t42"]
- '-s=89'
- -t42
running ./sotest -i 1000 -m some modules to follow --size 89 --threads=42
passing through size: ["--size", "89"]
passing through threads: ["--threads=42"]
- --size
- 89
- '--threads=42'
running ./sotest -i 1000 -m some modules to follow -s 89 -t 42
passing through size: ["-s", "89"]
passing through threads: ["-t", "42"]
- -s
- 89
- -t
- 42
I have two programs each with QProcess and I have a different behavior concerning the QProcess input with accentuated characters
(more precisely I create a Qprocess to execute a dos copy command and the path takes accent).
The environnement of execution and development is Windows 10.
The first program is a simple prototype that I made to test if my code can work correctly.
Here is the prototype code I have, in which the copy works correctly, integrated in a simple main() function.
The code is supposed to copy a file named sfx.exe into a path with accent F:\path_accentué and it indeed does the copy correctly.
#include <QCoreApplication>
#include <Qdebug>
#include <QObject>
#include <QProcess>
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QProcess* processus = new QProcess();
QStringList args;
QString path("F:\\path_accentué");
args << "/C" << "copy" << "E:\\test\\sfx.exe" << path;
processus->start("cmd.exe", args);
if (!processus->waitForStarted())
{
qDebug() << "Could not launch the process";
}
//processus->write(s.c_str());
if (!processus->waitForFinished(-1))
{
qDebug() << "Finished";
}
delete processus;
return app.exec();
}
However, when I integrate (literally copies and pasted without changing) this prototype within a bigger code project, my instance of QProcess does not recognize the accentuated path, as if accents are no more supported.
This is the part that I copy/paste in the bigger project and which I now execute via a button click in QT.
And this time, the QProcess doesn't recognize the accentuated path (Instead it creates a file with name like this path_accentu�)
QProcess* processus = new QProcess();
QStringList args;
QString path("F:\\path_accentué");
args << "/C" << "copy" << "E:\\test\\sfx.exe" << path; processus->start("cmd.exe", args);
if (!processus->waitForStarted())
{
qDebug() << "Could not launch the process";
}
//processus->write(s.c_str());
if (!processus->waitForFinished(-1))
{
qDebug() << "Finished";
}
I do not find in the documentation a way to force the QProcess to recognize accentuated inputs.
I would like to understand why the QProcess instance behaves differently when integrated within my bigger project.
What may impact the behavior of the QProcess and leads it to treat differently the input in the second case?
Note:
The QProcess is needed for more things but not only for the copy (such as getting feedback and percentage of operations). The copy is only to isolate the problem. In reality, I do much more things.
I tried to recreate your behaviour with Qt 5.15 and could create a file with accent with
start("cmd",{args...})
start("cmd /c args...")
setNativeArguments("/c args...") + start("cmd")
Last one is recommended for "cmd" calls, see the remarks here:
https://doc.qt.io/qt-5/qprocess.html#start
The only thing, which did not work, because it deadlocks was
setArguments({args...}) + start("cmd")
Demo here:
https://gist.github.com/elsamuko/59f110cf3a678beae9db27860f6305c9
I'm trying to accept automatically the host key when connecting to a server using this command
QString cmd = QString("echo y | plink.exe -ssh %1 -i root.ppk -l root exit").arg(strSensorAddress)
When I launch it from cmd.exe in Windows it is working.
I have tried to do it in Qt like this but it doesn't work :
QString cmd = QString("plink.exe -ssh %1 -i root.ppk -l root exit").arg(strSensorAddress);
process1.setStandardOutputProcess(&process2);
process1.start("echo y");
process2.start(cmd);
process2.setProcessChannelMode(QProcess::ForwardedChannels);
And like this :
QStringList arguments;
arguments << "plink.exe" << "-ssh" << strSensorAddress << "-i" << "root.ppk" << "-l" << "root" << "exit";
process1.setStandardOutputProcess(&process2);
process1.start("echo y");
process2.start("cmd.exe", arguments);
process2.setProcessChannelMode(QProcess::ForwardedChannels);
I am using boost::program_options to pass configuration files for my program. In particular I use often command line overriding of some of the options. For example if I register two options "opt1" and "opt2" I can successfully override the default values by running my program with
myProgram.exe --opt1=option_value_1 --opt2=option_value_2
All good, but it happened already few times that I run my program mistakenly as
myProgram.exe --opt1=option_value_1 opt2=option_value_2
In such a case (missing double hyphen) no error is thrown. In fact I can apparently run myProgram as
myProgram.exe list of any unregistered and unknown values
and it still runs correctly. I would expect to at least get informed that something unexpected happened. Is there a solution to my problem?
You should remove allow_unregistered() from your parse command. You command should simply be
po::store(parse_command_line(argc, argv, desc), vm);
then exception will be thrown on unknown options.
http://www.boost.org/doc/libs/1_54_0/doc/html/program_options/howto.html#idp123440592
If you want exception/error, if option has no "--" you should write extra parser, something like this, can help you
std::pair<std::string, std::string> fix_option(const std::string& value)
{
std::string name = value;
std::string val;
std::string::size_type pos = name.find("=");
if (pos != std::string::npos)
{
val = name.substr(pos + 1);
name = name.substr(0, pos);
}
if (name.substr(0, 2) != "--")
{
throw std::logic_error(std::string("invalid command, no -- in command: ") + name);
}
return std::make_pair(name.substr(2), val);
}
code example
results:
./new --help=j
output: j
./new help=j
output:
terminate called after throwing an instance of 'std::logic_error'
what(): invalid command, no -- in command: help
It seems that boost::program_options does not recognize positional arguments per default. This means that non-option arguments like opt2=option_value_2 are ignored. However, the documentation is not clear about it. You can enable handling of positional arguments with basic_command_line_parser::positional().
By Example
try {
po::variables_map vm;
po::store(po::command_line_parser(argc, argv).
options(desc).positional({}).run(),
vm);
po::notify(vm);
} catch (po::too_many_positional_options_error &e) {
// A positional argument like `opt2=option_value_2` was given
cerr << e.what() << endl;
exit(1);
} catch (po::error_with_option_name &e) {
// Another usage error occurred
cerr << e.what() << endl;
exit(1);
}
Explanation
Basically,
po::store(po::parse_command_line(argc, argv, desc), vm);
has been replaced with
po::store(po::command_line_parser(argc, argv)
.options(desc).positional({}).run(),
vm);
As I understand the documentation, parse_command_line(argc, argv, desc) is a shorthand for command_line_parser(argc, argv).options(desc).run(). Through adding a call to positional(), we are enabling handling of positional arguments. Through specifying {}, no positional arguments are allowed. An instance of too_many_positional_options_error is thrown when too many positional arguments are given.