From d43f35f56bc2d9164b6fe9aa5591eef287bebe07 Mon Sep 17 00:00:00 2001 From: Eran Mizrahi Date: Sun, 10 Dec 2017 23:33:01 +0200 Subject: Run shortcuts using moshortcut:// to avoid command line problems --- src/main.cpp | 21 ++++++++++- src/mainwindow.cpp | 7 ++-- src/organizercore.cpp | 96 +++++++++++++++++++++++++++++---------------------- src/organizercore.h | 10 +++++- 4 files changed, 87 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index 40224170..9b2afecc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -126,6 +126,16 @@ bool isNxmLink(const QString &link) return link.startsWith("nxm://", Qt::CaseInsensitive); } +bool isMoShortcut(const QString &link) +{ + return link.startsWith("moshortcut://", Qt::CaseInsensitive); +} + +QString moShortcutName(const QString &link) +{ + return link.mid(strlen("moshortcut://")); +} + static LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionPtrs) { if ((exceptionPtrs->ExceptionRecord->ExceptionCode < 0x80000000) // non-critical @@ -467,7 +477,16 @@ int runApplication(MOApplication &application, SingleInstance &instance, // if we have a command line parameter, it is either a nxm link or // a binary to start if (arguments.size() > 1) { - if (isNxmLink(arguments.at(1))) { + if (isMoShortcut(arguments.at(1))) { + try { + organizer.runShortcut(moShortcutName(arguments.at(1))); + return 0; + } catch (const std::exception &e) { + reportError( + QObject::tr("failed to start shortcut: %1").arg(e.what())); + return 1; + } + } else if (isNxmLink(arguments.at(1))) { qDebug("starting download from command line: %s", qPrintable(arguments.at(1))); organizer.externalMessage(arguments.at(1)); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 1db895fc..632b64e9 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -3199,11 +3199,10 @@ void MainWindow::addWindowsLink(const ShortcutType mapping) QString executable = QDir::toNativeSeparators(selectedExecutable.m_BinaryInfo.absoluteFilePath()); std::wstring targetFile = ToWString(exeInfo.absoluteFilePath()); - std::wstring parameter = ToWString(QString("\"%1\" %2").arg(executable) - .arg(selectedExecutable.m_Arguments)); - std::wstring description = ToWString(selectedExecutable.m_BinaryInfo.fileName()); + std::wstring parameter = ToWString(QString("\"moshortcut://%1\"").arg(selectedExecutable.m_Title)); + std::wstring description = ToWString(QString("Run %1 with ModOrganizer").arg(selectedExecutable.m_Title)); std::wstring iconFile = ToWString(executable); - std::wstring currentDirectory = ToWString(QDir::toNativeSeparators(exeInfo.absolutePath())); + std::wstring currentDirectory = ToWString(QDir::toNativeSeparators(qApp->applicationDirPath())); if (CreateShortcut(targetFile.c_str() , parameter.c_str() diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 30f96caf..116552df 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1068,19 +1068,9 @@ QStringList OrganizerCore::modsSortedByProfilePriority() const void OrganizerCore::spawnBinary(const QFileInfo &binary, const QString &arguments, const QDir ¤tDirectory, const QString &steamAppID, const QString &customOverwrite) { - ILockedWaitingForProcess* uilock = nullptr; - if (m_UserInterface != nullptr) { - uilock = m_UserInterface->lock(); - } - ON_BLOCK_EXIT([&] () { - if (m_UserInterface != nullptr) { m_UserInterface->unlock(); } - }); - - HANDLE processHandle = spawnBinaryDirect(binary, arguments, m_CurrentProfile->name(), currentDirectory, steamAppID, customOverwrite); + DWORD processExitCode = 0; + HANDLE processHandle = spawnBinaryDirect(binary, arguments, m_CurrentProfile->name(), currentDirectory, steamAppID, customOverwrite, &processExitCode); if (processHandle != INVALID_HANDLE_VALUE) { - DWORD processExitCode; - (void)waitForProcessCompletion(processHandle, &processExitCode, uilock); - refreshDirectoryStructure(); // need to remove our stored load order because it may be outdated if a foreign tool changed the // file time. After removing that file, refreshESPList will use the file time as the order @@ -1092,7 +1082,6 @@ void OrganizerCore::spawnBinary(const QFileInfo &binary, const QString &argument refreshESPList(); savePluginList(); - cycleDiagnostics(); //These callbacks should not fiddle with directoy structure and ESPs. m_FinishedRun(binary.absoluteFilePath(), processExitCode); @@ -1104,7 +1093,45 @@ HANDLE OrganizerCore::spawnBinaryDirect(const QFileInfo &binary, const QString &profileName, const QDir ¤tDirectory, const QString &steamAppID, - const QString &customOverwrite) + const QString &customOverwrite, + LPDWORD exitCode) +{ + HANDLE processHandle = spawnBinaryProcess(binary, arguments, profileName, currentDirectory, steamAppID, customOverwrite); + if (processHandle != INVALID_HANDLE_VALUE) { + std::unique_ptr dlg; + ILockedWaitingForProcess* uilock = nullptr; + + if (m_UserInterface != nullptr) { + uilock = m_UserInterface->lock(); + } + else { + // i.e. when running command line shortcuts there is no m_UserInterface + dlg.reset(new LockedDialog); + dlg->show(); + dlg->setEnabled(true); + uilock = dlg.get(); + } + + ON_BLOCK_EXIT([&]() { + if (m_UserInterface != nullptr) { + m_UserInterface->unlock(); + } }); + + DWORD ignoreExitCode; + waitForProcessCompletion(processHandle, exitCode ? exitCode : &ignoreExitCode, uilock); + cycleDiagnostics(); + } + + return processHandle; +} + + +HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary, + const QString &arguments, + const QString &profileName, + const QDir ¤tDirectory, + const QString &steamAppID, + const QString &customOverwrite) { prepareStart(); @@ -1199,6 +1226,19 @@ HANDLE OrganizerCore::spawnBinaryDirect(const QFileInfo &binary, } } +HANDLE OrganizerCore::runShortcut(const QString &title) +{ + Executable& exe = m_ExecutablesList.find(title); + + return spawnBinaryDirect( + exe.m_BinaryInfo, exe.m_Arguments, + m_CurrentProfile->name(), + exe.m_WorkingDirectory.length() != 0 + ? exe.m_WorkingDirectory + : exe.m_BinaryInfo.absolutePath(), + exe.m_SteamAppID, ""); +} + HANDLE OrganizerCore::startApplication(const QString &executable, const QStringList &args, const QString &cwd, @@ -1260,33 +1300,7 @@ HANDLE OrganizerCore::startApplication(const QString &executable, } } - HANDLE processHandle = spawnBinaryDirect(binary, arguments, profileName, currentDirectory, steamAppID, customOverwrite); - if (processHandle != INVALID_HANDLE_VALUE) { - std::unique_ptr dlg; - ILockedWaitingForProcess* uilock = nullptr; - - if (m_UserInterface != nullptr) { - uilock = m_UserInterface->lock(); - } - else { - // i.e. when running command line shortcuts there is no m_UserInterface - dlg.reset(new LockedDialog); - dlg->show(); - dlg->setEnabled(true); - uilock = dlg.get(); - } - - ON_BLOCK_EXIT([&]() { - if (m_UserInterface != nullptr) { - m_UserInterface->unlock(); - } }); - - DWORD processExitCode; - waitForProcessCompletion(processHandle, &processExitCode, uilock); - cycleDiagnostics(); - } - - return processHandle; + return spawnBinaryDirect(binary, arguments, profileName, currentDirectory, steamAppID, customOverwrite); } bool OrganizerCore::waitForApplication(HANDLE handle, LPDWORD exitCode) diff --git a/src/organizercore.h b/src/organizercore.h index 0927c88e..901780a1 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -145,7 +145,14 @@ public: const QString &profileName, const QDir ¤tDirectory, const QString &steamAppID, - const QString &customOverwrite); + const QString &customOverwrite, + LPDWORD exitCode = nullptr); + + HANDLE spawnBinaryProcess(const QFileInfo &binary, const QString &arguments, + const QString &profileName, + const QDir ¤tDirectory, + const QString &steamAppID, + const QString &customOverwrite); void loginSuccessfulUpdate(bool necessary); void loginFailedUpdate(const QString &message); @@ -192,6 +199,7 @@ public: DownloadManager *downloadManager(); PluginList *pluginList(); ModList *modList(); + HANDLE runShortcut(const QString &title); HANDLE startApplication(const QString &executable, const QStringList &args, const QString &cwd, const QString &profile); bool waitForApplication(HANDLE processHandle, LPDWORD exitCode = nullptr); bool onModInstalled(const std::function &func); -- cgit v1.3.1