executing cmd.exe with some console application
-
I am using C++ i Qt5.
I want to execute (from my Qt5 application) some console application with arguments but I want to have cmd.exe window visible with program's produced output.
I tried in my Qt5 application:std::string terminal = exec_system(L"echo %windir%") +
"\system32\cmd.exe";
QProcess *process = new QProcess();
QString exec = QString::fromStdString(terminal);
QStringList params;
params << "/C";
for (std::string s : explode(std::string(" "), command)) {
params << s.c_str();
}
process->start(exec, params);
process->waitForFinished();
delete process;Unfortunately cmd.exe window is not shown. I see hourglass for some time, but no cmd.exe window.
How to do it? -
@Robert-M said in executing cmd.exe with some console application:
std::string terminal = exec_system(L"echo %windir%") +
"\system32\cmd.exe";"cmd.exe" should be enough.
What exactly does exec contain?
You also should add error handling (https://doc.qt.io/qt-5/qprocess.html#errorOccurred)
No need to allocate process on the stack if you anyway wait for it to finish. -
@Robert-M said in executing cmd.exe with some console application:
This code does not display console window. Why?
What about it makes you think it should display any kind of console window? It will not.
How to make it correct?
I believe (I am not a Windows Qt user) you must do one of:
-
In
.pro
addCONFIG += console
. But that will display a console the whole time, and I don't think is compatible with GUI application. -
You probably want to look into the Windows
AllocConsole()
function. -
IIRC, use Windows
CreateProcess...
calls, instead ofQProcess
, which do allow console creation. -
Find a "terminal" which will execute your command. For example under Linux you could run it by invoking
xterm -e ...
; I don't know about Windows.
-
-
@Robert-M
There may be a way to get Qt'sQProcess
to control the arguments being passed to WindowsCreateProcess
, which I said you will need to do in order to have it create a new console for the sub-process. Have a look at void QProcess::setCreateProcessArgumentsModifier(QProcess::CreateProcessArgumentModifier modifier) and the discussion at typedef QProcess::CreateProcessArgumentModifier. I have not tried it, but in the sample code there I seeargs->flags |= CREATE_NEW_CONSOLE;
Try that, and then try it for your
pause
command. You may, or may not, need thecmd /k
it shows there rather thancmd /c
, depending what you want to happen about the console when your command finishes.Note that what you will want/expect to happen to the console after your command executes will depend on what command you are issuing. Likely not the same for
echo
versuspause
. -
I tried (according to Qt documentation):
QProcess process; process.setCreateProcessArgumentsModifier([] (QProcess::CreateProcessArguments *args) { args->flags |= CREATE_NEW_CONSOLE; args->startupInfo->dwFlags &= ~STARTF_USESTDHANDLES; args->startupInfo->dwFlags |= STARTF_USEFILLATTRIBUTE; args->startupInfo->dwFillAttribute = BACKGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY; }); process.start("C:\\Windows\\System32\\cmd.exe", QStringList() << "/c" << "pause");
but it does not display console window. Using /k instead of /c does not help.
-
start
is designed explicitly to avoid popping new consoles up, see the comment block in https://code.woboq.org/qt5/qtbase/src/corelib/io/qprocess_win.cpp.html#550we [...] do not want console tools launched from a GUI app to create new console windows (behavior consistent with UNIX).
-
@VRonin said in executing cmd.exe with some console application:
see the comment block in https://code.woboq.org/qt5/qtbase/src/corelib/io/qprocess_win.cpp.html#550
// However, we also do not want console tools launched from a GUI app to // create new console windows (behavior consistent with UNIX). DWORD dwCreationFlags = (GetConsoleWindow() ? 0 : CREATE_NO_WINDOW);
Well no wonder then :) But we don't get told this is a difference from
startDetached()
:) I will try to remember this for the future.P.S.
Isn't just lovely to seeUNIX
written? :) -
@VRonin said in executing cmd.exe with some console application:
start
is designed explicitly to avoid popping new consoles uNot 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; ...
?
If this works for
start()
like the OP says it apparently is working forstartDetached()
the advantage is you can still wait for sub-process completion, if desired. -
I have one problem in Linux. I invoke xterm with dirtyphp.sh script:
QProcess process; QString exec = QString::fromStdString(terminal); QStringList params; params << "-hold" << "-e"; bool p0 = true; for (std::string s : explode(std::string(" "), dirtyphp_command)) { if (p0) { std::string s0 = str_replace("'", "", s) + ".sh"; params << s0.c_str(); p0 = false; } else { params << str_replace("'", "", s).c_str(); } } process.start(exec, params); process.waitForFinished();
In dirtyphp.sh script I am waiting for CTRL+C at the end:
d=`dirname $0` if [ "$d" = "" ] then d="." fi $d/dirtyphp $@ echo 'Hit CTRL+C'; while true do sleep 1 done
The problem is that xterm window is closed automatically without waiting for CTRL+C and the user cannot browse output produced by program dirtyphp in xterm window. I do not understand why - the loop and the end of dirtyphp.sh script should be infinite.
-
@Robert-M
If you think it's even executing that script and getting as far as thewhile true
loop (goodness knows), put some debugging into the loop, like anecho
or aread
.Or maybe put a
set -x
at the start of the script so you can see what is going on? -
I changed the loop to the following:
while true
do
echo -n _
done
I see no underscores in xterm window.
Qt reports:
QProcess: Destroyed while process ("xterm") is still running.
I modified waitForFinish call:
process.waitForFinish(-1);
and now I can see underscores.
Problem solved. -
@Robert-M
bool QProcess::waitForFinished(int msecs = 30000) means thatwaitForFinished()
only waits up to 30 seconds, and then yourQProcess process;
goes out of scope and causes the error. If your sub-process takes longer that is why you wantedwaitForFinished(-1)
.