Executing batch file and getting finished signal
-
Hello. I have batch file that is used for flashing external micrcocontrollers (ESP32). The batch file contents:
tools\esptool.exe -p COM33 -b 921600 --before default_reset --after hard_reset --chip esp32 write_flash --flash_mode dio --flash_size detect --flash_freq 80m 0x0 bins\flash_image.bin
As you can see from above, it is using esptool.exe that I have in the tools folder.
I need to execute this command batch file via QT and receive finished signal. I try 3 different methods:
METHOD 1:
void MainWindow::on_flash_button_clicked() { QStringList arguments; QProcess process; connect(&process, &QProcess::errorOccurred, this, &MainWindow::processError); connect(&process, &QProcess::finished, this, &MainWindow::flash_finished); arguments << "/C"<<"start"<<"bats\\esp32_flash2.bat"; process.setArguments(arguments); process.setProgram("cmd.exe"); qDebug() << process.program() << " " << process.arguments(); process.start(); }
When I click button to start my script, nothing happens and I get the following error:
"cmd.exe" QList("/C", "start", "bats\\esp32_flash2.bat") QProcess: Destroyed while process ("cmd.exe") is still running. error enum val = QProcess::Crashed flash finished
METHOD 2: (identical to method 1 except using startDetached() instead of start()
//works but not getting flash finished signal void MainWindow::on_flash2_button_clicked() { QStringList arguments; QProcess process; connect(&process, &QProcess::errorOccurred, this, &MainWindow::processError); connect(&process, &QProcess::finished, this, &MainWindow::flash_finished); arguments << "/C"<<"start"<<"bats\\esp32_flash2.bat"; process.setArguments(arguments); process.setProgram("cmd.exe"); qDebug() << process.program() << " " << process.arguments(); process.startDetached(); }
The above method opens a cmd instance and starts flashing the device. This works but I have 2 issues with this method:
- It starts a cmd instance and I do not want user to see this. I want everything to happen "behind the curtains".
- It does not generate a finished signal when the flashing is complete.
METHOD 3 (removed "start" from QProcess arguments)
void MainWindow::on_flash3_button_clicked() { QStringList arguments; QProcess process; connect(&process, &QProcess::errorOccurred, this, &MainWindow::processError); connect(&process, &QProcess::finished, this, &MainWindow::flash_finished); arguments <<"/C"<<"bats\\esp32_flash2.bat"; process.setArguments(arguments); process.setProgram("cmd.exe"); qDebug() << process.program() << " " << process.arguments(); process.startDetached(); }
This method works better than the method 2 because it does not start external cmd instance.
I have 1 issue with above method:- It does not generate QProcess::finished signal when the flashing is complete
Could someone help me understand how to call batch scripts from QT properly and how to make sure the QProcess::finished gets triggered at the end of batch file execution? I believe I need to use process.start() rather than startDetached() but I cannot get it to work using start(), I always get QProcess::Crashed error. Thanks in advance.
-
Your QProcess instance needs to exist longer than the process it is managing.
By default, Windows start does not wait for its child process to complete.
In Method 1 QProcess:start() runs
start
, which returns ('finishes') quickly, and then the QProcess is destroyed while the command shell(s) involved are still running. This generates the overt warning.Method 2 suffers the same problem except you moved the quick return into the Qt side.
Method 3 after the batch file process is launched detached the QProcess instance is destroyed and thus does not exist to send a finished() signal.
Make the a QProcess instance or a QProcess* used to track a heap-allocated QProcess a member variable.
-
Hello. I have batch file that is used for flashing external micrcocontrollers (ESP32). The batch file contents:
tools\esptool.exe -p COM33 -b 921600 --before default_reset --after hard_reset --chip esp32 write_flash --flash_mode dio --flash_size detect --flash_freq 80m 0x0 bins\flash_image.bin
As you can see from above, it is using esptool.exe that I have in the tools folder.
I need to execute this command batch file via QT and receive finished signal. I try 3 different methods:
METHOD 1:
void MainWindow::on_flash_button_clicked() { QStringList arguments; QProcess process; connect(&process, &QProcess::errorOccurred, this, &MainWindow::processError); connect(&process, &QProcess::finished, this, &MainWindow::flash_finished); arguments << "/C"<<"start"<<"bats\\esp32_flash2.bat"; process.setArguments(arguments); process.setProgram("cmd.exe"); qDebug() << process.program() << " " << process.arguments(); process.start(); }
When I click button to start my script, nothing happens and I get the following error:
"cmd.exe" QList("/C", "start", "bats\\esp32_flash2.bat") QProcess: Destroyed while process ("cmd.exe") is still running. error enum val = QProcess::Crashed flash finished
METHOD 2: (identical to method 1 except using startDetached() instead of start()
//works but not getting flash finished signal void MainWindow::on_flash2_button_clicked() { QStringList arguments; QProcess process; connect(&process, &QProcess::errorOccurred, this, &MainWindow::processError); connect(&process, &QProcess::finished, this, &MainWindow::flash_finished); arguments << "/C"<<"start"<<"bats\\esp32_flash2.bat"; process.setArguments(arguments); process.setProgram("cmd.exe"); qDebug() << process.program() << " " << process.arguments(); process.startDetached(); }
The above method opens a cmd instance and starts flashing the device. This works but I have 2 issues with this method:
- It starts a cmd instance and I do not want user to see this. I want everything to happen "behind the curtains".
- It does not generate a finished signal when the flashing is complete.
METHOD 3 (removed "start" from QProcess arguments)
void MainWindow::on_flash3_button_clicked() { QStringList arguments; QProcess process; connect(&process, &QProcess::errorOccurred, this, &MainWindow::processError); connect(&process, &QProcess::finished, this, &MainWindow::flash_finished); arguments <<"/C"<<"bats\\esp32_flash2.bat"; process.setArguments(arguments); process.setProgram("cmd.exe"); qDebug() << process.program() << " " << process.arguments(); process.startDetached(); }
This method works better than the method 2 because it does not start external cmd instance.
I have 1 issue with above method:- It does not generate QProcess::finished signal when the flashing is complete
Could someone help me understand how to call batch scripts from QT properly and how to make sure the QProcess::finished gets triggered at the end of batch file execution? I believe I need to use process.start() rather than startDetached() but I cannot get it to work using start(), I always get QProcess::Crashed error. Thanks in advance.
@lukutis222
As @ChrisW67 has written. Note that to wait for finished you will want to useQProcess::start()
and notstartDetached()
. Also do not try to run the Windowsstart
command, that will prevent waiting for finished on the program it runs. -
Thanks both for responses. I managed to get it working by creating process on the heap as you have suggested.
void MainWindow::on_flash3_button_clicked() { QStringList arguments; //QProcess* process; QProcess * process = new QProcess(); connect(process, &QProcess::errorOccurred, this, &MainWindow::processError); connect(process, &QProcess::finished, this, &MainWindow::flash_finished); arguments <<"/C"<<"bats\\esp32_flash2.bat"; process->setArguments(arguments); process->setProgram("cmd.exe"); qDebug() << process->program() << " " << process->arguments(); process->start(); }
Since I have a habit of never using heap (I always allocate everything on stack), I would like to know if there is anything else I need to be aware of when using this method. Do I need to manually free the memory once I receive the finished signal?
-
Thanks both for responses. I managed to get it working by creating process on the heap as you have suggested.
void MainWindow::on_flash3_button_clicked() { QStringList arguments; //QProcess* process; QProcess * process = new QProcess(); connect(process, &QProcess::errorOccurred, this, &MainWindow::processError); connect(process, &QProcess::finished, this, &MainWindow::flash_finished); arguments <<"/C"<<"bats\\esp32_flash2.bat"; process->setArguments(arguments); process->setProgram("cmd.exe"); qDebug() << process->program() << " " << process->arguments(); process->start(); }
Since I have a habit of never using heap (I always allocate everything on stack), I would like to know if there is anything else I need to be aware of when using this method. Do I need to manually free the memory once I receive the finished signal?
@lukutis222 said in Executing batch file and getting finished signal:
Do I need to manually free the memory once I receive the finished signal?
Yes!
If you don't like heap-allocating the
QProcess
you could make it a member variable of e.g.MainWindow
? Then you wouldn't have to think about deleting it.