diff --git a/src/app/application.cpp b/src/app/application.cpp index 867bd5a0f..0a3c254b3 100644 --- a/src/app/application.cpp +++ b/src/app/application.cpp @@ -332,23 +332,47 @@ void Application::runExternalProgram(const BitTorrent::TorrentHandle *torrent) c logger->addMessage(tr("Torrent: %1, running external program, command: %2").arg(torrent->name(), program)); #if defined(Q_OS_WIN) - std::unique_ptr programWchar(new wchar_t[program.length() + 1] {}); + auto programWchar = std::make_unique(program.length() + 1); program.toWCharArray(programWchar.get()); // Need to split arguments manually because QProcess::startDetached(QString) // will strip off empty parameters. // E.g. `python.exe "1" "" "3"` will become `python.exe "1" "3"` int argCount = 0; - LPWSTR *args = ::CommandLineToArgvW(programWchar.get(), &argCount); + std::unique_ptr args {::CommandLineToArgvW(programWchar.get(), &argCount), ::LocalFree}; QStringList argList; for (int i = 1; i < argCount; ++i) argList += QString::fromWCharArray(args[i]); - QProcess::startDetached(QString::fromWCharArray(args[0]), argList); - - ::LocalFree(args); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) + QProcess proc; + proc.setProgram(QString::fromWCharArray(args[0])); + proc.setArguments(argList); + proc.setCreateProcessArgumentsModifier([](QProcess::CreateProcessArguments *args) + { + if (Preferences::instance()->isAutoRunConsoleEnabled()) { + args->flags |= CREATE_NEW_CONSOLE; + args->flags &= ~(CREATE_NO_WINDOW | DETACHED_PROCESS); + } + else { + args->flags |= CREATE_NO_WINDOW; + args->flags &= ~(CREATE_NEW_CONSOLE | DETACHED_PROCESS); + } + args->inheritHandles = false; + args->startupInfo->dwFlags &= ~STARTF_USESTDHANDLES; + ::CloseHandle(args->startupInfo->hStdInput); + ::CloseHandle(args->startupInfo->hStdOutput); + ::CloseHandle(args->startupInfo->hStdError); + args->startupInfo->hStdInput = nullptr; + args->startupInfo->hStdOutput = nullptr; + args->startupInfo->hStdError = nullptr; + }); + proc.startDetached(); #else + QProcess::startDetached(QString::fromWCharArray(args[0]), argList); +#endif // QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) +#else // Q_OS_WIN // Cannot give users shell environment by default, as doing so could // enable command injection via torrent name and other arguments // (especially when some automated download mechanism has been setup). diff --git a/src/base/preferences.cpp b/src/base/preferences.cpp index 2bbb5e33f..683f073fe 100644 --- a/src/base/preferences.cpp +++ b/src/base/preferences.cpp @@ -781,7 +781,7 @@ bool Preferences::isUILocked() const void Preferences::setUILocked(const bool locked) { - return setValue("Locking/locked", locked); + setValue("Locking/locked", locked); } bool Preferences::isAutoRunEnabled() const @@ -791,7 +791,7 @@ bool Preferences::isAutoRunEnabled() const void Preferences::setAutoRunEnabled(const bool enabled) { - return setValue("AutoRun/enabled", enabled); + setValue("AutoRun/enabled", enabled); } QString Preferences::getAutoRunProgram() const @@ -804,6 +804,18 @@ void Preferences::setAutoRunProgram(const QString &program) setValue("AutoRun/program", program); } +#if defined(Q_OS_WIN) && (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) +bool Preferences::isAutoRunConsoleEnabled() const +{ + return value("AutoRun/ConsoleEnabled", false).toBool(); +} + +void Preferences::setAutoRunConsoleEnabled(const bool enabled) +{ + setValue("AutoRun/ConsoleEnabled", enabled); +} +#endif + bool Preferences::shutdownWhenDownloadsComplete() const { return value("Preferences/Downloads/AutoShutDownOnCompletion", false).toBool(); diff --git a/src/base/preferences.h b/src/base/preferences.h index d141e1639..19723d70d 100644 --- a/src/base/preferences.h +++ b/src/base/preferences.h @@ -238,6 +238,10 @@ public: void setAutoRunEnabled(bool enabled); QString getAutoRunProgram() const; void setAutoRunProgram(const QString &program); +#if defined(Q_OS_WIN) && (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) + bool isAutoRunConsoleEnabled() const; + void setAutoRunConsoleEnabled(bool enabled); +#endif bool shutdownWhenDownloadsComplete() const; void setShutdownWhenDownloadsComplete(bool shutdown); bool suspendWhenDownloadsComplete() const; diff --git a/src/gui/optionsdialog.cpp b/src/gui/optionsdialog.cpp index 95cb6c604..44c4a9e02 100644 --- a/src/gui/optionsdialog.cpp +++ b/src/gui/optionsdialog.cpp @@ -295,6 +295,7 @@ OptionsDialog::OptionsDialog(QWidget *parent) connect(m_ui->mailNotifPassword, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); connect(m_ui->autoRunBox, &QGroupBox::toggled, this, &ThisType::enableApplyButton); connect(m_ui->lineEditAutoRun, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); + connect(m_ui->autoRunConsole, &QCheckBox::toggled, this, &ThisType::enableApplyButton); const QString autoRunStr = QString("%1\n %2\n %3\n %4\n %5\n %6\n %7\n %8\n %9\n %10\n %11\n%12") .arg(tr("Supported parameters (case sensitive):") @@ -696,6 +697,9 @@ void OptionsDialog::saveOptions() pref->setMailNotificationSMTPPassword(m_ui->mailNotifPassword->text()); pref->setAutoRunEnabled(m_ui->autoRunBox->isChecked()); pref->setAutoRunProgram(m_ui->lineEditAutoRun->text().trimmed()); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) && defined(Q_OS_WIN) + pref->setAutoRunConsoleEnabled(m_ui->autoRunConsole->isChecked()); +#endif pref->setActionOnDblClOnTorrentDl(getActionOnDblClOnTorrentDl()); pref->setActionOnDblClOnTorrentFn(getActionOnDblClOnTorrentFn()); TorrentFileGuard::setAutoDeleteMode(!m_ui->deleteTorrentBox->isChecked() ? TorrentFileGuard::Never @@ -970,6 +974,11 @@ void OptionsDialog::loadOptions() m_ui->autoRunBox->setChecked(pref->isAutoRunEnabled()); m_ui->lineEditAutoRun->setText(pref->getAutoRunProgram()); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) && defined(Q_OS_WIN) + m_ui->autoRunConsole->setChecked(pref->isAutoRunConsoleEnabled()); +#else + m_ui->autoRunConsole->hide(); +#endif intValue = pref->getActionOnDblClOnTorrentDl(); if (intValue >= m_ui->actionTorrentDlOnDblClBox->count()) intValue = 0; diff --git a/src/gui/optionsdialog.ui b/src/gui/optionsdialog.ui index 3ede266bf..f0988c327 100644 --- a/src/gui/optionsdialog.ui +++ b/src/gui/optionsdialog.ui @@ -1264,6 +1264,13 @@ + + + + Show console window + + +