QProcess start for mstsc (Remote Desktop) generates finished() signal immediately
-
Hi QT forum.
I'm working on QT application (Windows) that can initiate RDP session with other machine and I'm facing problems with keeping track of started "mstsc" process, as "process->start" call for RDP application immediately generates the "finished()" signal despite the fact, that RDP session is in progress. After RDP session is closed, no additional "finished()" signal occur.I'm using next code:
QProcess *process = new QProcess(); rdp_processes_list.append(process); connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(rdp_process_finished(int, QProcess::ExitStatus))); connect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(rdp_process_error(QProcess::ProcessError))); // start cmd and start mstsc app with /wait key to wait till RDP session is closed. process->start("cmd", QStringList() << "/c" << "start" << "/wait" << "mstsc" << "/v" << machine_address); // returns true if process started successfully process->waitForStarted(-1);
Tried also to do same without cmd involved:
process->start("mstsc", QStringList() << "/v" << machine_address);
And observe the same result - finished() signal is being generated immediately.
Passing "cmd /c start /w mstsc /v 172.16.30.113" command into Windows Run menu (Win + R) opens cmd, which opens my RDP session. CMD is closed right after RDP session is closed and this is the expected behavior, which I want to be used by QT.
Tried also to execute notepad app in same way:
QProcess *process = new QProcess(); rdp_processes_list.append(process); connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(rdp_process_finished(int, QProcess::ExitStatus))); connect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(rdp_process_error(QProcess::ProcessError))); // start cmd and start mstsc app with /wait key to wait till RDP session is closed. process->start("notepad"); // returns true if process started successfully process->waitForStarted(-1);
And in this case I observe another (correct) behavior - finished() signal is being generated right after notepad app is closed, so this may rather be related to
mstsc
app behavior. Can someone please suggest me what else I can try to fix / workaround it?QT version used: 5.13.2
-
As mentioned on microsoft forum post, most likely when building 32-bit app (which I was doing), it makes
mstsc
call of 32-bit version mstsc, which calls the correct 64-bit version and closes original process that was called from QT app.
Switched my QT project to build 64 bit application and it fixed my problem - now finished() signal is being emitted exactly after RDP session finished.
@Christian-Ehrlicher @JonB @mrjj thanks for your inputs.
Issue is solved. -
According to mstsc help
/v
needs the ip directly -->process->start("mstsc", {"/v:"+ machine_address});
-
According to mstsc help
/v
needs the ip directly -->process->start("mstsc", {"/v:"+ machine_address});
@Christian-Ehrlicher
Thanks for your message.
Call as you suggested still immediately generates finished() signal. -
@Christian-Ehrlicher
Thanks for your message.
Call as you suggested still immediately generates finished() signal.@m4kas
I'm afraid I know nothing aboutmstsc
. But as your code stands, for all I know it might not be on the path of thecmd
and we would not know.I would start by hooking slots for anything on stdout and particularly on stderr. Windows/DOS has a way of sending you messages on stderr when (failing to) start processes. Note that this is not the same as hooking to
error
signal. I would also look at what thefinished
exit status is, just in case there is a clue there. Finally I would also hook ontostarted
&stateChanged
signals. That's what I do when debugging odd behaviour! -
@m4kas
I'm afraid I know nothing aboutmstsc
. But as your code stands, for all I know it might not be on the path of thecmd
and we would not know.I would start by hooking slots for anything on stdout and particularly on stderr. Windows/DOS has a way of sending you messages on stderr when (failing to) start processes. Note that this is not the same as hooking to
error
signal. I would also look at what thefinished
exit status is, just in case there is a clue there. Finally I would also hook ontostarted
&stateChanged
signals. That's what I do when debugging odd behaviour!@JonB
Thanks for your reply and suggestions.
finished() signal is being emitted with QProcess::NormalExit exitStatus
Agree, stderr can contain something useful even though the RDP session with the target machine is being started correctly (at least, from user perspective), so I'll start with trying to read info from stderr and processing started & stateChanged signals. -
@JonB
Thanks for your reply and suggestions.
finished() signal is being emitted with QProcess::NormalExit exitStatus
Agree, stderr can contain something useful even though the RDP session with the target machine is being started correctly (at least, from user perspective), so I'll start with trying to read info from stderr and processing started & stateChanged signals. -
@m4kas
Do those. Also while I think of itcmd /k ...
is the same ascmd /c ...
but should keep the Command Prompt window open. Try that to see what it has to show? -
Updated my code in next way:
void MainWindow::on_tbl_machines_doubleClicked(const QModelIndex &index) { QString machine_address = ui->tbl_machines->model()->index(index.row(), 1).data().toString(); QString machine_user = ui->tbl_machines->model()->index(index.row(), 4).data().toString(); QString machine_password = ui->tbl_machines->model()->index(index.row(), 5).data().toString(); // cmdkey /generic:<servername> /user:<username> /pass:<password> QStringList arg_list= QStringList() << QString("/generic:%1").arg(machine_address) << QString("/user:%1").arg(machine_user) << QString("/pass:%1").arg(machine_password); QProcess::execute("cmdkey", arg_list); QProcess *process = new QProcess(); rdp_processes_list.append(process); connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(rdp_process_finished(int, QProcess::ExitStatus))); connect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(rdp_process_error(QProcess::ProcessError))); connect(process, SIGNAL(started()), this, SLOT(rdp_process_started())); connect(process, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(rdp_process_state_changed(QProcess::ProcessState))); // start cmd and start mstsc app with /wait key to wait till RDP session is closed. process->start("cmd", QStringList() << "/c" << "start" << "/wait" << "mstsc" << "/v" << machine_address); // returns true if process started successfully process->waitForStarted(-1); process->waitForReadyRead(-1); qDebug() << "readAllStandardError:" << process->readAllStandardError(); qDebug() << "readAllStandardOutput:" << process->readAllStandardOutput(); } /* SLOTS */ void MainWindow::rdp_process_started() { qDebug() << "started slot: Process started"; } void MainWindow::rdp_process_state_changed(QProcess::ProcessState newState) { qDebug() << "stateChanged slot: Process state changed. New state: " << newState; } void MainWindow::rdp_process_finished(int exitCode, QProcess::ExitStatus exitStatus) { qDebug() << "finished slot: Exit code: " << exitCode << " Exit status: " << exitStatus; } void MainWindow::rdp_process_error(QProcess::ProcessError error) { qDebug() << "error slot: Process error: " << error; }
And got next messages from qDebug():
CMDKEY: Credential added successfully. stateChanged slot: Process state changed. New state: QProcess::Starting stateChanged slot: Process state changed. New state: QProcess::Running started slot: Process started stateChanged slot: Process state changed. New state: QProcess::NotRunning finished slot: Exit code: 0 Exit status: QProcess::NormalExit readAllStandardError: "" readAllStandardOutput: ""
So, it does not look
mstsc
want to say something to me... -
int main(int argc, char* argv[]) { QApplication a(argc, argv); QProcess* proc = new QProcess; QObject::connect(proc, &QProcess::started, []() { qDebug() << "started"; }); QObject::connect(proc, &QProcess::stateChanged, [](QProcess::ProcessState s) { qDebug() << "stateChanged:" << s; }); QObject::connect(proc, qOverload<int,QProcess::ExitStatus>(&QProcess::finished), [](int c, QProcess::ExitStatus s) { qDebug() << "finished:" << c << s; QCoreApplication::quit(); }); proc->start("mstsc", { "/v:127.0.0.1" }); return a.exec(); } --> stateChanged: QProcess::Running started // connect dialog is shown, I kill it stateChanged: QProcess::NotRunning finished: 0 QProcess::NormalExit
Works perfectly fine for me. Still don't understand why everyone wants to use
cmd /c
to run a simple windows executable... -
int main(int argc, char* argv[]) { QApplication a(argc, argv); QProcess* proc = new QProcess; QObject::connect(proc, &QProcess::started, []() { qDebug() << "started"; }); QObject::connect(proc, &QProcess::stateChanged, [](QProcess::ProcessState s) { qDebug() << "stateChanged:" << s; }); QObject::connect(proc, qOverload<int,QProcess::ExitStatus>(&QProcess::finished), [](int c, QProcess::ExitStatus s) { qDebug() << "finished:" << c << s; QCoreApplication::quit(); }); proc->start("mstsc", { "/v:127.0.0.1" }); return a.exec(); } --> stateChanged: QProcess::Running started // connect dialog is shown, I kill it stateChanged: QProcess::NotRunning finished: 0 QProcess::NormalExit
Works perfectly fine for me. Still don't understand why everyone wants to use
cmd /c
to run a simple windows executable...@Christian-Ehrlicher
My log when using your code:stateChanged: QProcess::Starting stateChanged: QProcess::Running started stateChanged: QProcess::NotRunning finished: 0 QProcess::NormalExit // RDP session is still in progress
Update: when using your code, but not with loopback, but with real remote machine IP . Using with loopback gives error about "could not connect to another console session".
-
I don't know what exactly mstsc is doing but maybe it's detaching the rdp connection internally so the mstsc process is not running when the rdp session is open. Take a look into your running taskmanager/processes when you have an open rdp connection if the mstsc process which you're using for connecting is still there. I would say it's not the case.
-
I don't know what exactly mstsc is doing but maybe it's detaching the rdp connection internally so the mstsc process is not running when the rdp session is open. Take a look into your running taskmanager/processes when you have an open rdp connection if the mstsc process which you're using for connecting is still there. I would say it's not the case.
@Christian-Ehrlicher
Yes, I can see mstsc.exe in active processes list after QT reportedfinished()
for that process. -
@Christian-Ehrlicher
Yes, I can see mstsc.exe in active processes list after QT reportedfinished()
for that process.@m4kas said in QProcess start for mstsc (Remote Desktop) generates finished() signal immediately:
I can see mstsc.exe in active processes list after
And is it exactly this process which was started from Qt? Check the process id.
-
@m4kas said in QProcess start for mstsc (Remote Desktop) generates finished() signal immediately:
I can see mstsc.exe in active processes list after
And is it exactly this process which was started from Qt? Check the process id.
@Christian-Ehrlicher
Good catch!
PIDs really differs. Now I will try to understand how track the process, that is being started bymstsc
I am starting... -
@Christian-Ehrlicher
Good catch!
PIDs really differs. Now I will try to understand how track the process, that is being started bymstsc
I am starting...@m4kas
Hi
I think you are going to need to use the APIs
https://docs.microsoft.com/en-us/windows/win32/termserv/terminal-services-administration -
As mentioned on microsoft forum post, most likely when building 32-bit app (which I was doing), it makes
mstsc
call of 32-bit version mstsc, which calls the correct 64-bit version and closes original process that was called from QT app.
Switched my QT project to build 64 bit application and it fixed my problem - now finished() signal is being emitted exactly after RDP session finished.
@Christian-Ehrlicher @JonB @mrjj thanks for your inputs.
Issue is solved. -
As mentioned on microsoft forum post, most likely when building 32-bit app (which I was doing), it makes
mstsc
call of 32-bit version mstsc, which calls the correct 64-bit version and closes original process that was called from QT app.
Switched my QT project to build 64 bit application and it fixed my problem - now finished() signal is being emitted exactly after RDP session finished.
@Christian-Ehrlicher @JonB @mrjj thanks for your inputs.
Issue is solved.