startDetached fails under 5.15.2
-
I'm updating a program compiled with Qt 5.6 (static) to Qt 5.15.2 (static)
void MainWindow::on_doConsole_clicked() { QProcess::startDetached("/windows/system32/cmd.exe", {"/k", QCoreApplication::applicationDirPath() + "/cpath.bat"}); }
My problem is the code above. It's purpose is to open a cmd window / bat file and have the console stay open until manually closed. I can literally compile this code using 5.6 and it works fine, only to not work using 5.15.2. Press the button and nothing whatsoever happens.
Any ideas?
-
@Jedd this is obviously using connectSLotByName magic
on_doConsole_clicked
- try a proper connect call to your button and add a debug output see if the slot is actually called
- make sure path.bat is actually in the folder where the executable is. When changing Kits, you'll get a different shadow build directory and the bat file may have previously been copied by hand instead of a proper post link macro
- don't use the static method of Process and connect your error signals the the QProcess instance/object you create, see if that gives more information
-
@Jedd said in startDetached fails under 5.15.2:
"/windows/system32/cmd.exe"
This also looks a bit dubious. Try an absolute path using the drive letter, e.g.
C:/Windows/System32/cmd.exe
-
@Jedd said in startDetached fails under 5.15.2:
QProcess::startDetached("/windows/system32/cmd.exe", {"/k", QCoreApplication::applicationDirPath() + "/cpath.bat"});
A small point, probably not related to your issue, but one I believe people should get into good habits on. A bug-bear of mine.
Windows uses
\
as directory path separator. Qt allows/encourages you to use/
. This is fine where Qt knows you are specifying a pathname, e.g. toQFile
or in the first argument for the executable path tostartDetached()
: it will translate that for you to\
before sending to the OS.However, where Qt does not know it's a pathname, such as in the arguments to
startDetached()
you pass, it leaves/
as-is.Now, consider how e.g. the
dir
command treats its arguments, like say the/windows/...
path you used for the executable above:dir \windows
All good and correct, outputs contents of
\windows
directory. But now what happens if you pass your Qt-type path todir
:dir /windows Parameter format not correct - "windows".
Oh dear! It has taken the
/
as a parameter string passed todir
, not as a pathname!Whether an OS command will fall foul of this depends under Windows on each command's behaviour --- some will treat
/
s as an alternative for\
s in a path, but some as shown above will treat as parameters. Maybecmd /k
is happy with argument/windows/...
to treat as a pathname, but maybe not....So, for e.g. the arguments to the executable specified you really should use
\
s not/
s, or use QString QDir::toNativeSeparators(const QString &pathName), just in case.... -
try a proper connect call to your button and add a debug output see if the slot is actually called
don't use the static method of Process and connect your error signals the the QProcess instance/object you create, see if that gives more information
I'm sorry, I don't know what you mean by proper connect call or not using a static method of process. If you can explain further, that would be great.
void MainWindow::on_pushButton_clicked() { qDebug() << "Start Detached" QProcess::startDetached("C:/windows/system32/cmd.exe", {"/k"}); }
Just to simplify things, the function above simply opens a console on Windows, without calling a bat file. As before, this function works as expected using Qt 5.6 but does nothing under Qt 5.15.2. I did add a debug and it is called and works as expected with both versions.
-
@Jedd said in startDetached fails under 5.15.2:
I'm sorry, I don't know what you mean by proper connect call or not using a static method of process. If you can explain further, that would be great.
Instead of
QProcess::startDetached("...")
static method. Create aQProcess process
member variable inMainWindow
. Useprocess.startDetached()
. No arguments. See https://doc.qt.io/qt-5/qprocess.html#startDetached. See the property setters there, you'll needsetProgram()
&setArguments()
.That will use the
process
instance. See the signals at https://doc.qt.io/qt-5/qprocess.html#signals. Create slots for those.qDebug()
what you get in the slots.From all of this you will discover what is actually happening when it's not working.
Code is simpler to write if you want to test whether
QProcess::start()
does not work similarly toQProcess::startDetached()
. You might want to see ifstart()
fails for you too, or onlystartDetached()
. -
qDebug() << "Start Detached"; QStringList arguments; arguments << "/k"; //<< "cpath.bat"; QProcess *process = new QProcess(); process->startDetached("C:/windows/system32/cmd.exe", arguments); qDebug() << "error: " << process->error();
Start Detached
error: QProcess::UnknownErrorprocess->start returns the same error.
-
Also tried:
void MainWindow::on_pushButton_clicked() { qDebug() << "Start Detached"; QProcess process; process.setProgram("C:/windows/system32/cmd.exe"); process.setArguments({"/k"}); process.startDetached(); qDebug() << "error: " << process.error(); }
Same result.
-
@Jedd said in startDetached fails under 5.15.2:
error: QProcess::UnknownError
That is almost certainly because there is no error!
QProcess::error()
has to return something, https://doc.qt.io/qt-5/qprocess.html#ProcessError-enum:QProcess::UnknownError 5 An unknown error occurred. This is the default return value of error().
Unless something reports an error, like QProcess::errorOccurred(), there is no point looking at
QProcess::error()
. And in your first code it's not going going to return anything anyway because you use thestatic
methodbool QProcess::startDetached(const QString &program, const QStringList &arguments)
.I told you that if you want to find out what's going on you need to:
- Use the instance method
process.startDetached()
. That is per your second code. - Attach slots to the signals it raises.
I suggest you do so.
Meanwhile if you want to test whether
startDetached()
works at all, I suggest you try a command like e.g.cmd /c echo hello > C:\some\writable\folder\filename
, so that you can tell whether it created the file and therefore ran. - Use the instance method
-
Thanks for your patience, this is new ground for me.
void MainWindow::on_pushButton_clicked() { qDebug() << "Start Detached"; QStringList arguments; arguments << "/k"; //<< "cpath.bat"; QProcess *process = new QProcess(); connect(&process, &QProcess::errorOccurred, this, MainWindow::onSdetacherror); process->setProgram("C:/windows/system32/cmd.exe"); process->setArguments({"/k"}); process->startDetached("C:/windows/system32/cmd.exe", arguments); } void MainWindow::onSdetacherror() { qDebug() << "error:"; } ==== // from mainwindow.h private slots: void onSdetacherror();
No joy yet. the connect statement is in error and I'm not sure how to reference errorOccured in the slot.
-
BTW, following your suggestion, the code below works, showing that the startDetached call is working ...
qDebug() << "Start Detached"; QStringList arguments; arguments << "/c" << "echo xxxxx > /Users/jedd/Desktop/xxx.txt"; process->startDetached("C:/windows/system32/cmd.exe", arguments);
-
@Jedd said in startDetached fails under 5.15.2:
No joy yet. the connect statement is in error and I'm not sure how to reference errorOccured in the slot.
Please copy & paste any error messages you get rather than just stating there was an error! Saves me having to guess....
QProcess *process = new QProcess(); connect(&process, &QProcess::errorOccurred, this, MainWindow::onSdetacherror);
You already have a
QProcess *process
so you do not want to take its address with&process
. And both the signal and slot PointerToMemberFunctions require a leading&
:connect(process, &QProcess::errorOccurred, this, &MainWindow::onSdetacherror);
And the
QProcess::errorOccurred(QProcess::ProcessError error)
signal passes a parameter to the slot:void MainWindow::onSdetacherror(QProcess::ProcessError error) { qDebug() << "error:" << error; }
As for:
process->setProgram("C:/windows/system32/cmd.exe"); process->setArguments({"/k"}); process->startDetached("C:/windows/system32/cmd.exe", arguments);
I'm going to say this again: please read what I wrote earlier about which
QProcess::startDetached()
method you must use if you are attaching slots to signals. The one which has string and string list arguments is bool QProcess::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory = QString(), qint64 *pid = nullptr). That is astatic
method. Unfortunately C++ allows you to callstatic
methods on an instance of the class (process->startDetached("...")
), which makes it look like it is using yourprocess
, but in fact it is not. It's reallyQProcess::startDetached("...")
, you might as well call it that way, and that shows it does not use yourQProcess *
. It creates its own internally. And so any slots you haveconnect()
ed to your instance will not be called. Here you must use bool QProcess::startDetached(qint64 *pid = nullptr), which is notstatic
, does use your instance and will activate your slots:process->setProgram("C:/windows/system32/cmd.exe"); process->setArguments({"/k"}); process->startDetached();
Please do not make this mistake again!
While you're at it, you might as well add another signal slot handler, in case it tells us something:
connect(process, &QProcess::stateChanged, this, &MainWindow::onProcessStateChanged); void MainWindow::onProcessStateChanged(QProcess::ProcessState newState) { qDebug() << "newState:" << newState; }
BTW, following your suggestion, the code below works, showing that the startDetached call is working ...
Well that's a start! So we know
startDetached()
itself does work, as it should.I do not know at this point why your code which works at 5.6 should not work at 5.15. Let's hope that
errorOccurred
/stateChanged
slots reveal something. -
@Jedd
I have a possible theory as to what might be going on, ifstart()
does what you want butstartDetached()
does not.Please don't let this reply stop you reading my (long) previous one, and trying the things I ask you to there.
I'd like to summarize which things do work and which do not. I have 4 things for you to try:
QProcess *process = new QProcess();
followed by:process->start("C:/windows/system32/cmd.exe", { "/k" });
process->startDetached("C:/windows/system32/cmd.exe", { "/k" });
process->start("C:/windows/system32/cmd.exe", { "/k", "echo xxxxx > /Users/jedd/Desktop/xxx.txt" });
process->startDetached("C:/windows/system32/cmd.exe", { "/k", "echo yyyyy > /Users/jedd/Desktop/yyy.txt" });
For 1 & 2, in which one do you see a visible console remain?
For 3 & 4, do you see a visible console, but more significantly do they both create their respective files even if you don't see a console?Depending on results, this may all be to do with the discussions in https://forum.qt.io/topic/135952/executing-cmd-exe-with-some-console-application.
The strange thing from that is that as per @VRonin's post https://forum.qt.io/topic/135952/executing-cmd-exe-with-some-console-application/13 and my reply to that the implication is that it is
start()
which should fail to open the console window whilestartDetached()
should allow it, which seems to be the opposite of what you are reporting?Anyway, let me have clear & simple answers as to how 1--4 above behave wrt my questions about them, and we'll take it from there.
-
1. process->start("C:/windows/system32/cmd.exe", { "/k" }); 2. process->startDetached("C:/windows/system32/cmd.exe", { "/k" }); 3. process->start("C:/windows/system32/cmd.exe", { "/k", "echo xxxxx > /Users/jedd/Desktop/xxx.txt" }); 4. process->startDetached("C:/windows/system32/cmd.exe", { "/k", "echo yyyyy > /Users/jedd/Desktop/yyy.txt" });
For 1 and 2 there is no visible console at any time
For 3 and 4 there is no visible console, but for both start and startDetached the respective text file is produced
Using the code below:
with startDetached, neither NewState or error are triggeredwith start I get:
newState: QProcess::Starting
newState: QProcess::Runningvoid MainWindow::on_pushButton_clicked() { qDebug() << "Start Detached"; QStringList arguments; arguments << "/k"; QProcess *process = new QProcess(); connect(process, &QProcess::errorOccurred, this, &MainWindow::onSdetacherror); connect(process, &QProcess::stateChanged, this, &MainWindow::onProcessStateChanged); process->setProgram("C:/windows/system32/cmd.exe"); process->setArguments(arguments); process->startDetached("C:/windows/system32/cmd.exe", arguments); } void MainWindow::onProcessStateChanged(QProcess::ProcessState newState) { qDebug() << "newState:" << newState; } void MainWindow::onSdetacherror(QProcess::ProcessError error) { qDebug() << "error:" << error; }
-
@Jedd said in startDetached fails under 5.15.2:
with startDetached, neither NewState or error are triggered
process->startDetached("C:/windows/system32/cmd.exe", { "/k", "echo yyyyy > /Users/jedd/Desktop/yyy.txt" });
I wrote you a whole, long diatribe on why
process->startDetached("...")
will not trigger any signals. I explained this not once but twice:I told you that if you want to find out what's going on you need to:
- Use the instance method
process.startDetached()
. That is per your second code.
I'm going to say this again: please read what I wrote earlier about which
QProcess::startDetached()
method you must use if you are attaching slots to signals.You really should be able to get this right by now. I cannot/will not keep typing the same in over & over.
I do not know why neither
start()
norstartDetached()
show you a console. It does look like they are both running successfully.I suggest you read carefully through https://forum.qt.io/topic/135952/executing-cmd-exe-with-some-console-application. Among other posts there you will see:
You are great! Thanks a lot!
process.setProgram("C:\\Windows\\System32\\cmd.exe"); process.setArguments({"/k", "pause"}); qint64 pid; process.startDetached(&pid);
displays console with pause text.
You see that user reports it "displays console" I do not know why his does and yours does not. I would expect your
start()
not to display console butstartDetached()
to display console.Anyway, all I can sugest is that you try the post I made there at https://forum.qt.io/topic/135952/executing-cmd-exe-with-some-console-application/15
Not tested, but can't you change this in the same way in your
setCreateProcessArgumentsModifier()
anyway, just add the first line to whatever you want:args->flags &= ~CREATE_NO_WINDOW; // switch that *off* args->flags |= CREATE_NEW_CONSOLE; ...
Try this with both
start()
&startDetached()
. For the final time: do not use this with [static
]startDetached("...")
method, only withstartDetached()
[non-static
] one. - Use the instance method