diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 0ed391faa..d2fc5184b 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -662,7 +662,12 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, #endif connect(&proc_jt9, static_cast (&QProcess::finished), [this] (int exitCode, QProcess::ExitStatus status) { - subProcessFailed (&proc_jt9, exitCode, status); + if (subProcessFailed (&proc_jt9, exitCode, status)) + { + m_valid = false; // ensures exit if still + // constructing + QTimer::singleShot (0, this, SLOT (close ())); + } }); connect(&p1, &QProcess::started, [this] () { showStatusMessage (QString {"Started: %1 \"%2\""}.arg (p1.program ()).arg (p1.arguments ().join (QLatin1String {"\" \""}))); @@ -680,25 +685,42 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, #endif connect(&p1, static_cast (&QProcess::finished), [this] (int exitCode, QProcess::ExitStatus status) { - subProcessFailed (&p1, exitCode, status); + if (subProcessFailed (&p1, exitCode, status)) + { + m_valid = false; // ensures exit if still + // constructing + QTimer::singleShot (0, this, SLOT (close ())); + } }); #if QT_VERSION < QT_VERSION_CHECK (5, 6, 0) connect(&p3, static_cast (&QProcess::error), [this] (QProcess::ProcessError error) { - subProcessError (&p3, error); - }); #else connect(&p3, &QProcess::errorOccurred, [this] (QProcess::ProcessError error) { - subProcessError (&p3, error); - }); #endif +#if not defined(Q_OS_WIN) + if (QProcess::FailedToStart != error) +#endif + { + subProcessError (&p3, error); + } + }); connect(&p3, &QProcess::started, [this] () { showStatusMessage (QString {"Started: %1 \"%2\""}.arg (p3.program ()).arg (p3.arguments ().join (QLatin1String {"\" \""}))); }); connect(&p3, static_cast (&QProcess::finished), [this] (int exitCode, QProcess::ExitStatus status) { - subProcessFailed (&p3, exitCode, status); +#if defined(Q_OS_WIN) + // We forgo detecting user_hardware failures with exit + // code 1 on Windows. This is because we use CMD.EXE to + // run the executable. CMD.EXE returns exit code 1 when it + // can't find the target executable. + if (exitCode != 1) // CMD.EXE couldn't find file to execute +#endif + { + subProcessFailed (&p3, exitCode, status); + } }); // hook up save WAV file exit handling @@ -2335,7 +2357,7 @@ void MainWindow::setup_status_bar (bool vhf) } } -void MainWindow::subProcessFailed (QProcess * process, int exit_code, QProcess::ExitStatus status) +bool MainWindow::subProcessFailed (QProcess * process, int exit_code, QProcess::ExitStatus status) { if (m_valid && (exit_code || QProcess::NormalExit != status)) { @@ -2352,9 +2374,9 @@ void MainWindow::subProcessFailed (QProcess * process, int exit_code, QProcess:: , tr ("Running: %1\n%2") .arg (process->program () + ' ' + arguments.join (' ')) .arg (QString {process->readAllStandardError()})); - QTimer::singleShot (0, this, SLOT (close ())); - m_valid = false; // ensures exit if still constructing + return true; } + return false; } void MainWindow::subProcessError (QProcess * process, QProcess::ProcessError) @@ -2372,8 +2394,8 @@ void MainWindow::subProcessError (QProcess * process, QProcess::ProcessError) , tr ("Running: %1\n%2") .arg (process->program () + ' ' + arguments.join (' ')) .arg (process->errorString ())); - QTimer::singleShot (0, this, SLOT (close ())); m_valid = false; // ensures exit if still constructing + QTimer::singleShot (0, this, SLOT (close ())); } } @@ -7895,22 +7917,25 @@ void MainWindow::WSPR_scheduling () if (hop_data.frequencies_index_ >= 0) { // new band ui->bandComboBox->setCurrentIndex (hop_data.frequencies_index_); on_bandComboBox_activated (hop_data.frequencies_index_); - QStringList prefixes {".bat", ".cmd", ".exe", ""}; - QString target; - for (auto const& prefix : prefixes) - { - target = QDir {m_appDir}.absoluteFilePath (QLatin1String {"user_hardware"}); - QFileInfo f {target + prefix}; - if (f.isExecutable ()) { - break; - } - } - if (target.size ()) - { - // Execute user's hardware controller - p3.start(QDir::toNativeSeparators (target) - , QStringList {m_config.bands ()->find (m_freqNominal).remove ('m')}); - } + // Execute user's hardware controller + auto const& band = m_config.bands ()->find (m_freqNominal).remove ('m'); +#if defined(Q_OS_WIN) + // On windows we use CMD.EXE to find and execute the + // user_hardware executable. This means that the first matching + // file extension on the PATHEXT environment variable found on + // the PATH environment variable path list. This give maximum + // flexibility for users to write user_hardware in their + // language of choice, and place the file anywhere on the PATH + // environment variable. Equivalent to typing user_hardware + // without any path or extension at the CMD.EXE prompt. + p3.start("CMD", QStringList {QLatin1String {"/C"}, QLatin1String {"user_hardware"}, band}); +#else + // On non-Windows systems we expect the user_hardware executable + // to be anywhere in the paths specified in the PATH environment + // variable path list, and executable. Equivalent to typing + // user_hardware without any path at the shell prompt. + p3.start(QLatin1String {"user_hardware"}, QStringList {band}); +#endif // Produce a short tuneup signal m_tuneup = false; diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index 6da871b37..047f39205 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -3,6 +3,7 @@ #define MAINWINDOW_H #include +#include #include #include #include @@ -749,7 +750,7 @@ private: void rm_tb4(QString houndCall); void read_wav_file (QString const& fname); void decodeDone (); - void subProcessFailed (QProcess *, int exit_code, QProcess::ExitStatus); + bool subProcessFailed (QProcess *, int exit_code, QProcess::ExitStatus); void subProcessError (QProcess *, QProcess::ProcessError); void statusUpdate () const; void update_watchdog_label ();