From 0015a12cf8916d8000c6d14356b4c17c62f4a588 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Wed, 11 Sep 2019 23:36:13 -0400
Subject: rewritten spawn() to use std::wstring instead of manual buffers error
dialogs now use TaskDialog with more user-friendly text
---
src/spawn.h | 19 -------------------
1 file changed, 19 deletions(-)
(limited to 'src/spawn.h')
diff --git a/src/spawn.h b/src/spawn.h
index c2d99bdb..9a2dbfbd 100644
--- a/src/spawn.h
+++ b/src/spawn.h
@@ -26,25 +26,6 @@ along with Mod Organizer. If not, see .
#include
#include
-
-/**
- * @brief a dirty little trick so we can issue a clean restart from startBinary
- * @note unused
- */
-/*class ExitProxy : public QObject {
- Q_OBJECT
-public:
- static ExitProxy *instance();
- void emitExit();
-signals:
- void exit();
-private:
- ExitProxy() {}
-private:
- static ExitProxy *s_Instance;
-};*/
-
-
/**
* @brief spawn a binary with Mod Organizer injected
*
--
cgit v1.3.1
From 971cecf343777894cec5144da11d16ef97d0db31 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Thu, 12 Sep 2019 01:09:40 -0400
Subject: split spawnBinaryProcess() into spawn, no changes
---
src/mainwindow.cpp | 2 +-
src/organizercore.cpp | 286 ++--------------------------------------------
src/spawn.cpp | 310 +++++++++++++++++++++++++++++++++++++++++++++++++-
src/spawn.h | 18 +++
4 files changed, 338 insertions(+), 278 deletions(-)
(limited to 'src/spawn.h')
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 054262e9..6737e330 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -6434,7 +6434,7 @@ void MainWindow::on_bossButton_clicked()
return;
}
- HANDLE loot = startBinary(QFileInfo(qApp->applicationDirPath() + "/loot/lootcli.exe"),
+ HANDLE loot = spawn::startBinary(QFileInfo(qApp->applicationDirPath() + "/loot/lootcli.exe"),
parameters.join(" "),
qApp->applicationDirPath() + "/loot",
true,
diff --git a/src/organizercore.cpp b/src/organizercore.cpp
index 91e16716..9403b47d 100644
--- a/src/organizercore.cpp
+++ b/src/organizercore.cpp
@@ -135,34 +135,6 @@ static DWORD getProcessParentID(DWORD pid)
return res;
}
-static void startSteam(QWidget *widget)
-{
- QSettings steamSettings("HKEY_CURRENT_USER\\Software\\Valve\\Steam",
- QSettings::NativeFormat);
- QString exe = steamSettings.value("SteamExe", "").toString();
- if (!exe.isEmpty()) {
- exe = QString("\"%1\"").arg(exe);
- // See if username and password supplied. If so, pass them into steam.
- QStringList args;
- QString username;
- QString password;
- if (Settings::instance().steam().login(username, password)) {
- args << "-login";
- args << username;
- if (password != "") {
- args << password;
- }
- }
- if (!QProcess::startDetached(exe, args)) {
- reportError(QObject::tr("Failed to start \"%1\"").arg(exe));
- } else {
- QMessageBox::information(
- widget, QObject::tr("Waiting"),
- QObject::tr("Please press OK once you're logged into steam."));
- }
- }
-}
-
template
QStringList toStringList(InputIterator current, InputIterator end)
{
@@ -173,86 +145,6 @@ QStringList toStringList(InputIterator current, InputIterator end)
return result;
}
-bool checkService()
-{
- SC_HANDLE serviceManagerHandle = NULL;
- SC_HANDLE serviceHandle = NULL;
- LPSERVICE_STATUS_PROCESS serviceStatus = NULL;
- LPQUERY_SERVICE_CONFIG serviceConfig = NULL;
- bool serviceRunning = true;
-
- DWORD bytesNeeded;
-
- try {
- serviceManagerHandle = OpenSCManager(NULL, NULL, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
- if (!serviceManagerHandle) {
- log::warn("failed to open service manager (query status) (error {})", GetLastError());
- throw 1;
- }
-
- serviceHandle = OpenService(serviceManagerHandle, L"EventLog", SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
- if (!serviceHandle) {
- log::warn("failed to open EventLog service (query status) (error {})", GetLastError());
- throw 2;
- }
-
- if (QueryServiceConfig(serviceHandle, NULL, 0, &bytesNeeded)
- || (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
- log::warn("failed to get size of service config (error {})", GetLastError());
- throw 3;
- }
-
- DWORD serviceConfigSize = bytesNeeded;
- serviceConfig = (LPQUERY_SERVICE_CONFIG)LocalAlloc(LMEM_FIXED, serviceConfigSize);
- if (!QueryServiceConfig(serviceHandle, serviceConfig, serviceConfigSize, &bytesNeeded)) {
- log::warn("failed to query service config (error {})", GetLastError());
- throw 4;
- }
-
- if (serviceConfig->dwStartType == SERVICE_DISABLED) {
- log::error("Windows Event Log service is disabled!");
- serviceRunning = false;
- }
-
- if (QueryServiceStatusEx(serviceHandle, SC_STATUS_PROCESS_INFO, NULL, 0, &bytesNeeded)
- || (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
- log::warn("failed to get size of service status (error {})", GetLastError());
- throw 5;
- }
-
- DWORD serviceStatusSize = bytesNeeded;
- serviceStatus = (LPSERVICE_STATUS_PROCESS)LocalAlloc(LMEM_FIXED, serviceStatusSize);
- if (!QueryServiceStatusEx(serviceHandle, SC_STATUS_PROCESS_INFO, (LPBYTE)serviceStatus, serviceStatusSize, &bytesNeeded)) {
- log::warn("failed to query service status (error {})", GetLastError());
- throw 6;
- }
-
- if (serviceStatus->dwCurrentState != SERVICE_RUNNING) {
- log::error("Windows Event Log service is not running");
- serviceRunning = false;
- }
- }
- catch (int e) {
- UNUSED_VAR(e);
- serviceRunning = false;
- }
-
- if (serviceStatus) {
- LocalFree(serviceStatus);
- }
- if (serviceConfig) {
- LocalFree(serviceConfig);
- }
- if (serviceHandle) {
- CloseServiceHandle(serviceHandle);
- }
- if (serviceManagerHandle) {
- CloseServiceHandle(serviceManagerHandle);
- }
-
- return serviceRunning;
-}
-
OrganizerCore::OrganizerCore(Settings &settings)
: m_UserInterface(nullptr)
@@ -361,67 +253,6 @@ void OrganizerCore::storeSettings()
}
}
-bool OrganizerCore::testForSteam(bool *found, bool *access)
-{
- HANDLE hProcessSnap;
- HANDLE hProcess;
- PROCESSENTRY32 pe32;
- DWORD lastError;
-
- if (found == nullptr || access == nullptr) {
- return false;
- }
-
- // Take a snapshot of all processes in the system.
- hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
- if (hProcessSnap == INVALID_HANDLE_VALUE) {
- lastError = GetLastError();
- log::error("unable to get snapshot of processes (error {})", lastError);
- return false;
- }
-
- // Retrieve information about the first process,
- // and exit if unsuccessful
- pe32.dwSize = sizeof(PROCESSENTRY32);
- if (!Process32First(hProcessSnap, &pe32)) {
- lastError = GetLastError();
- log::error("unable to get first process (error {})", lastError);
- CloseHandle(hProcessSnap);
- return false;
- }
-
- *found = false;
- *access = true;
-
- // Now walk the snapshot of processes, and
- // display information about each process in turn
- do {
- if ((_tcsicmp(pe32.szExeFile, L"Steam.exe") == 0) ||
- (_tcsicmp(pe32.szExeFile, L"SteamService.exe") == 0)) {
-
- *found = true;
-
- // Try to open the process to determine if MO has the proper access
- hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
- FALSE, pe32.th32ProcessID);
- if (hProcess == NULL) {
- lastError = GetLastError();
- if (lastError == ERROR_ACCESS_DENIED) {
- *access = false;
- }
- } else {
- CloseHandle(hProcess);
- }
- break;
- }
-
-} while(Process32Next(hProcessSnap, &pe32));
-
-CloseHandle(hProcessSnap);
-return true;
-
-}
-
void OrganizerCore::updateExecutablesList()
{
if (m_PluginContainer == nullptr) {
@@ -1453,93 +1284,18 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary,
{
prepareStart();
- if (!binary.exists()) {
- reportError(
- tr("Executable not found: %1").arg(qUtf8Printable(binary.absoluteFilePath())));
- return INVALID_HANDLE_VALUE;
- }
-
- if (!steamAppID.isEmpty()) {
- ::SetEnvironmentVariableW(L"SteamAPPId", ToWString(steamAppID).c_str());
- } else {
- ::SetEnvironmentVariableW(L"SteamAPPId",
- ToWString(m_Settings.steam().appID()).c_str());
- }
-
QWidget *window = qApp->activeWindow();
if ((window != nullptr) && (!window->isVisible())) {
window = nullptr;
}
- // This could possibly be extracted somewhere else but it's probably for when
- // we have more than one provider of game registration.
- if ((QFileInfo(
- managedGame()->gameDirectory().absoluteFilePath("steam_api.dll"))
- .exists()
- || QFileInfo(managedGame()->gameDirectory().absoluteFilePath(
- "steam_api64.dll"))
- .exists())
- && (m_Settings.game().loadMechanismType() == LoadMechanism::LOAD_MODORGANIZER)) {
-
- bool steamFound = true;
- bool steamAccess = true;
- if (!testForSteam(&steamFound, &steamAccess)) {
- log::error("unable to determine state of Steam");
- }
-
- if (!steamFound) {
- QDialogButtonBox::StandardButton result;
- result = QuestionBoxMemory::query(window, "steamQuery", binary.fileName(),
- tr("Start Steam?"),
- tr("Steam is required to be running already to correctly start the game. "
- "Should MO try to start steam now?"),
- QDialogButtonBox::Yes | QDialogButtonBox::No | QDialogButtonBox::Cancel);
- if (result == QDialogButtonBox::Yes) {
- startSteam(window);
-
- // double-check that Steam is started and MO has access
- steamFound = true;
- steamAccess = true;
- if (!testForSteam(&steamFound, &steamAccess)) {
- log::error("unable to determine state of Steam");
- } else if (!steamFound) {
- log::error("could not find Steam");
- }
- } else if (result == QDialogButtonBox::Cancel) {
- return INVALID_HANDLE_VALUE;
- }
- }
+ if (!spawn::checkBinary(binary)) {
+ return INVALID_HANDLE_VALUE;
+ }
- if (!steamAccess) {
- QDialogButtonBox::StandardButton result;
- result = QuestionBoxMemory::query(window, "steamAdminQuery", binary.fileName(),
- tr("Steam: Access Denied"),
- tr("MO was denied access to the Steam process. This normally indicates that "
- "Steam is being run as administrator while MO is not. This can cause issues "
- "launching the game. It is recommended to not run Steam as administrator unless "
- "absolutely necessary.\n\n"
- "Restart MO as administrator?"),
- QDialogButtonBox::Yes | QDialogButtonBox::No | QDialogButtonBox::Cancel);
- if (result == QDialogButtonBox::Yes) {
- WCHAR cwd[MAX_PATH];
- if (!GetCurrentDirectory(MAX_PATH, cwd)) {
- log::error("unable to get current directory (error {})", GetLastError());
- cwd[0] = L'\0';
- }
- if (!Helper::adminLaunch(
- qApp->applicationDirPath().toStdWString(),
- qApp->applicationFilePath().toStdWString(),
- std::wstring(cwd))) {
- log::error("unable to relaunch MO as admin");
- return INVALID_HANDLE_VALUE;
- }
- qApp->exit(0);
- return INVALID_HANDLE_VALUE;
- } else if (result == QDialogButtonBox::Cancel) {
- return INVALID_HANDLE_VALUE;
- }
- }
+ if (!spawn::checkSteam(window, managedGame()->gameDirectory(), binary, steamAppID, m_Settings)) {
+ return INVALID_HANDLE_VALUE;
}
while (m_DirectoryUpdate) {
@@ -1566,32 +1322,12 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary,
return INVALID_HANDLE_VALUE;
}
- // Check if the Windows Event Logging service is running. For some reason, this seems to be
- // critical to the successful running of usvfs.
- if (!checkService()) {
- if (QuestionBoxMemory::query(window, QString("eventLogService"), binary.fileName(),
- tr("Windows Event Log Error"),
- tr("The Windows Event Log service is disabled and/or not running. This prevents"
- " USVFS from running properly. Your mods may not be working in the executable"
- " that you are launching. Note that you may have to restart MO and/or your PC"
- " after the service is fixed.\n\nContinue launching %1?").arg(binary.fileName()),
- QDialogButtonBox::Yes | QDialogButtonBox::No) == QDialogButtonBox::No) {
- return INVALID_HANDLE_VALUE;
- }
+ if (!spawn::checkEnvironment(window, binary)) {
+ return INVALID_HANDLE_VALUE;
}
- for (auto exec : settings().executablesBlacklist().split(";")) {
- if (exec.compare(binary.fileName(), Qt::CaseInsensitive) == 0) {
- if (QuestionBoxMemory::query(window, QString("blacklistedExecutable"), binary.fileName(),
- tr("Blacklisted Executable"),
- tr("The executable you are attempted to launch is blacklisted in the virtual file"
- " system. This will likely prevent the executable, and any executables that are"
- " launched by this one, from seeing any mods. This could extend to INI files, save"
- " games and any other virtualized files.\n\nContinue launching %1?").arg(binary.fileName()),
- QDialogButtonBox::Yes | QDialogButtonBox::No) == QDialogButtonBox::No) {
- return INVALID_HANDLE_VALUE;
- }
- }
+ if (!spawn::checkBlacklist(window, m_Settings, binary)) {
+ return INVALID_HANDLE_VALUE;
}
QString modsPath = settings().paths().mods();
@@ -1628,11 +1364,11 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary,
log::debug("Spawning proxyed process <{}>", cmdline);
- return startBinary(QFileInfo(QCoreApplication::applicationFilePath()),
+ return spawn::startBinary(QFileInfo(QCoreApplication::applicationFilePath()),
cmdline, QCoreApplication::applicationDirPath(), true);
} else {
log::debug("Spawning direct process <{}, {}, {}>", binPath, arguments, cwdPath);
- return startBinary(binary, arguments, currentDirectory, true);
+ return spawn::startBinary(binary, arguments, currentDirectory, true);
}
} else {
log::debug("start of \"{}\" canceled by plugin", binary.absoluteFilePath());
diff --git a/src/spawn.cpp b/src/spawn.cpp
index 614bc92f..4376e5bf 100644
--- a/src/spawn.cpp
+++ b/src/spawn.cpp
@@ -24,6 +24,7 @@ along with Mod Organizer. If not, see .
#include "env.h"
#include "envwindows.h"
#include "envsecurity.h"
+#include "settings.h"
#include
#include
#include
@@ -41,6 +42,10 @@ along with Mod Organizer. If not, see .
using namespace MOBase;
using namespace MOShared;
+namespace spawn
+{
+
+// details
namespace
{
@@ -320,8 +325,6 @@ bool confirmRestartAsAdmin(const SpawnParameters& sp)
return (r == QMessageBox::Yes);
}
-} // namespace
-
void startBinaryAdmin(const SpawnParameters& sp)
{
if (!confirmRestartAsAdmin(sp)) {
@@ -344,6 +347,307 @@ void startBinaryAdmin(const SpawnParameters& sp)
}
}
+} // namespace
+
+
+bool checkBinary(const QFileInfo& binary)
+{
+ if (!binary.exists()) {
+ reportError(
+ QObject::tr("Executable not found: %1")
+ .arg(qUtf8Printable(binary.absoluteFilePath())));
+
+ return false;
+ }
+
+ return true;
+}
+
+bool testForSteam(bool *found, bool *access)
+{
+ HANDLE hProcessSnap;
+ HANDLE hProcess;
+ PROCESSENTRY32 pe32;
+ DWORD lastError;
+
+ if (found == nullptr || access == nullptr) {
+ return false;
+ }
+
+ // Take a snapshot of all processes in the system.
+ hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (hProcessSnap == INVALID_HANDLE_VALUE) {
+ lastError = GetLastError();
+ log::error("unable to get snapshot of processes (error {})", lastError);
+ return false;
+ }
+
+ // Retrieve information about the first process,
+ // and exit if unsuccessful
+ pe32.dwSize = sizeof(PROCESSENTRY32);
+ if (!Process32First(hProcessSnap, &pe32)) {
+ lastError = GetLastError();
+ log::error("unable to get first process (error {})", lastError);
+ CloseHandle(hProcessSnap);
+ return false;
+ }
+
+ *found = false;
+ *access = true;
+
+ // Now walk the snapshot of processes, and
+ // display information about each process in turn
+ do {
+ if ((_tcsicmp(pe32.szExeFile, L"Steam.exe") == 0) ||
+ (_tcsicmp(pe32.szExeFile, L"SteamService.exe") == 0)) {
+
+ *found = true;
+
+ // Try to open the process to determine if MO has the proper access
+ hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
+ FALSE, pe32.th32ProcessID);
+ if (hProcess == NULL) {
+ lastError = GetLastError();
+ if (lastError == ERROR_ACCESS_DENIED) {
+ *access = false;
+ }
+ } else {
+ CloseHandle(hProcess);
+ }
+ break;
+ }
+
+ } while(Process32Next(hProcessSnap, &pe32));
+
+ CloseHandle(hProcessSnap);
+ return true;
+}
+
+void startSteam(QWidget *widget)
+{
+ QSettings steamSettings("HKEY_CURRENT_USER\\Software\\Valve\\Steam",
+ QSettings::NativeFormat);
+ QString exe = steamSettings.value("SteamExe", "").toString();
+ if (!exe.isEmpty()) {
+ exe = QString("\"%1\"").arg(exe);
+ // See if username and password supplied. If so, pass them into steam.
+ QStringList args;
+ QString username;
+ QString password;
+ if (Settings::instance().steam().login(username, password)) {
+ args << "-login";
+ args << username;
+ if (password != "") {
+ args << password;
+ }
+ }
+ if (!QProcess::startDetached(exe, args)) {
+ reportError(QObject::tr("Failed to start \"%1\"").arg(exe));
+ } else {
+ QMessageBox::information(
+ widget, QObject::tr("Waiting"),
+ QObject::tr("Please press OK once you're logged into steam."));
+ }
+ }
+}
+
+bool checkSteam(
+ QWidget* parent, const QDir& gameDirectory,
+ const QFileInfo &binary, const QString &steamAppID, const Settings& settings)
+{
+ if (!steamAppID.isEmpty()) {
+ ::SetEnvironmentVariableW(L"SteamAPPId", ToWString(steamAppID).c_str());
+ } else {
+ ::SetEnvironmentVariableW(L"SteamAPPId",
+ ToWString(settings.steam().appID()).c_str());
+ }
+
+ if ((QFileInfo(gameDirectory.absoluteFilePath("steam_api.dll")).exists() ||
+ QFileInfo(gameDirectory.absoluteFilePath("steam_api64.dll")).exists())
+ && (settings.game().loadMechanismType() == LoadMechanism::LOAD_MODORGANIZER)) {
+
+ bool steamFound = true;
+ bool steamAccess = true;
+ if (!testForSteam(&steamFound, &steamAccess)) {
+ log::error("unable to determine state of Steam");
+ }
+
+ if (!steamFound) {
+ QDialogButtonBox::StandardButton result;
+ result = QuestionBoxMemory::query(parent, "steamQuery", binary.fileName(),
+ QObject::tr("Start Steam?"),
+ QObject::tr("Steam is required to be running already to correctly start the game. "
+ "Should MO try to start steam now?"),
+ QDialogButtonBox::Yes | QDialogButtonBox::No | QDialogButtonBox::Cancel);
+ if (result == QDialogButtonBox::Yes) {
+ startSteam(parent);
+
+ // double-check that Steam is started and MO has access
+ steamFound = true;
+ steamAccess = true;
+ if (!testForSteam(&steamFound, &steamAccess)) {
+ log::error("unable to determine state of Steam");
+ } else if (!steamFound) {
+ log::error("could not find Steam");
+ }
+
+ } else if (result == QDialogButtonBox::Cancel) {
+ return false;
+ }
+ }
+
+ if (!steamAccess) {
+ QDialogButtonBox::StandardButton result;
+ result = QuestionBoxMemory::query(parent, "steamAdminQuery", binary.fileName(),
+ QObject::tr("Steam: Access Denied"),
+ QObject::tr("MO was denied access to the Steam process. This normally indicates that "
+ "Steam is being run as administrator while MO is not. This can cause issues "
+ "launching the game. It is recommended to not run Steam as administrator unless "
+ "absolutely necessary.\n\n"
+ "Restart MO as administrator?"),
+ QDialogButtonBox::Yes | QDialogButtonBox::No | QDialogButtonBox::Cancel);
+ if (result == QDialogButtonBox::Yes) {
+ WCHAR cwd[MAX_PATH];
+ if (!GetCurrentDirectory(MAX_PATH, cwd)) {
+ log::error("unable to get current directory (error {})", GetLastError());
+ cwd[0] = L'\0';
+ }
+ if (!Helper::adminLaunch(
+ qApp->applicationDirPath().toStdWString(),
+ qApp->applicationFilePath().toStdWString(),
+ std::wstring(cwd))) {
+ log::error("unable to relaunch MO as admin");
+ return false;
+ }
+ qApp->exit(0);
+ return false;
+ } else if (result == QDialogButtonBox::Cancel) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool checkService()
+{
+ SC_HANDLE serviceManagerHandle = NULL;
+ SC_HANDLE serviceHandle = NULL;
+ LPSERVICE_STATUS_PROCESS serviceStatus = NULL;
+ LPQUERY_SERVICE_CONFIG serviceConfig = NULL;
+ bool serviceRunning = true;
+
+ DWORD bytesNeeded;
+
+ try {
+ serviceManagerHandle = OpenSCManager(NULL, NULL, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
+ if (!serviceManagerHandle) {
+ log::warn("failed to open service manager (query status) (error {})", GetLastError());
+ throw 1;
+ }
+
+ serviceHandle = OpenService(serviceManagerHandle, L"EventLog", SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
+ if (!serviceHandle) {
+ log::warn("failed to open EventLog service (query status) (error {})", GetLastError());
+ throw 2;
+ }
+
+ if (QueryServiceConfig(serviceHandle, NULL, 0, &bytesNeeded)
+ || (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
+ log::warn("failed to get size of service config (error {})", GetLastError());
+ throw 3;
+ }
+
+ DWORD serviceConfigSize = bytesNeeded;
+ serviceConfig = (LPQUERY_SERVICE_CONFIG)LocalAlloc(LMEM_FIXED, serviceConfigSize);
+ if (!QueryServiceConfig(serviceHandle, serviceConfig, serviceConfigSize, &bytesNeeded)) {
+ log::warn("failed to query service config (error {})", GetLastError());
+ throw 4;
+ }
+
+ if (serviceConfig->dwStartType == SERVICE_DISABLED) {
+ log::error("Windows Event Log service is disabled!");
+ serviceRunning = false;
+ }
+
+ if (QueryServiceStatusEx(serviceHandle, SC_STATUS_PROCESS_INFO, NULL, 0, &bytesNeeded)
+ || (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
+ log::warn("failed to get size of service status (error {})", GetLastError());
+ throw 5;
+ }
+
+ DWORD serviceStatusSize = bytesNeeded;
+ serviceStatus = (LPSERVICE_STATUS_PROCESS)LocalAlloc(LMEM_FIXED, serviceStatusSize);
+ if (!QueryServiceStatusEx(serviceHandle, SC_STATUS_PROCESS_INFO, (LPBYTE)serviceStatus, serviceStatusSize, &bytesNeeded)) {
+ log::warn("failed to query service status (error {})", GetLastError());
+ throw 6;
+ }
+
+ if (serviceStatus->dwCurrentState != SERVICE_RUNNING) {
+ log::error("Windows Event Log service is not running");
+ serviceRunning = false;
+ }
+ }
+ catch (int) {
+ serviceRunning = false;
+ }
+
+ if (serviceStatus) {
+ LocalFree(serviceStatus);
+ }
+ if (serviceConfig) {
+ LocalFree(serviceConfig);
+ }
+ if (serviceHandle) {
+ CloseServiceHandle(serviceHandle);
+ }
+ if (serviceManagerHandle) {
+ CloseServiceHandle(serviceManagerHandle);
+ }
+
+ return serviceRunning;
+}
+
+bool checkEnvironment(QWidget* parent, const QFileInfo& binary)
+{
+ // Check if the Windows Event Logging service is running. For some reason, this seems to be
+ // critical to the successful running of usvfs.
+ if (!checkService()) {
+ if (QuestionBoxMemory::query(parent, QString("eventLogService"), binary.fileName(),
+ QObject::tr("Windows Event Log Error"),
+ QObject::tr("The Windows Event Log service is disabled and/or not running. This prevents"
+ " USVFS from running properly. Your mods may not be working in the executable"
+ " that you are launching. Note that you may have to restart MO and/or your PC"
+ " after the service is fixed.\n\nContinue launching %1?").arg(binary.fileName()),
+ QDialogButtonBox::Yes | QDialogButtonBox::No) == QDialogButtonBox::No) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool checkBlacklist(QWidget* parent, const Settings& settings, const QFileInfo& binary)
+{
+ for (auto exec : settings.executablesBlacklist().split(";")) {
+ if (exec.compare(binary.fileName(), Qt::CaseInsensitive) == 0) {
+ if (QuestionBoxMemory::query(parent, QString("blacklistedExecutable"), binary.fileName(),
+ QObject::tr("Blacklisted Executable"),
+ QObject::tr("The executable you are attempted to launch is blacklisted in the virtual file"
+ " system. This will likely prevent the executable, and any executables that are"
+ " launched by this one, from seeing any mods. This could extend to INI files, save"
+ " games and any other virtualized files.\n\nContinue launching %1?").arg(binary.fileName()),
+ QDialogButtonBox::Yes | QDialogButtonBox::No) == QDialogButtonBox::No) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+
HANDLE startBinary(
const QFileInfo &binary, const QString &arguments, const QDir ¤tDirectory,
bool hooked, HANDLE stdOut, HANDLE stdErr)
@@ -382,3 +686,5 @@ HANDLE startBinary(
}
}
}
+
+} // namespace
\ No newline at end of file
diff --git a/src/spawn.h b/src/spawn.h
index 9a2dbfbd..9a5afb4a 100644
--- a/src/spawn.h
+++ b/src/spawn.h
@@ -26,6 +26,22 @@ along with Mod Organizer. If not, see .
#include
#include
+class Settings;
+
+namespace spawn
+{
+
+bool checkBinary(const QFileInfo& binary);
+
+bool checkSteam(
+ QWidget* parent, const QDir& gameDirectory,
+ const QFileInfo &binary, const QString &steamAppID, const Settings& settings);
+
+bool checkEnvironment(QWidget* parent, const QFileInfo& binary);
+
+bool checkBlacklist(
+ QWidget* parent, const Settings& settings, const QFileInfo& binary);
+
/**
* @brief spawn a binary with Mod Organizer injected
*
@@ -45,5 +61,7 @@ HANDLE startBinary(const QFileInfo &binary, const QString &arguments,
const QDir ¤tDirectory, bool hooked,
HANDLE stdOut = INVALID_HANDLE_VALUE, HANDLE stdErr = INVALID_HANDLE_VALUE);
+} // namespace
+
#endif // SPAWN_H
--
cgit v1.3.1
From bf3d7527801bcba16ba01735efd3d5acc052f485 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Thu, 12 Sep 2019 01:48:48 -0400
Subject: made SpawnParameters public, changed to Qt types removed 'suspended',
not used
---
src/mainwindow.cpp | 12 ++++---
src/organizercore.cpp | 24 ++++++++++----
src/spawn.cpp | 92 ++++++++++++++++++---------------------------------
src/spawn.h | 46 +++++++++++++++-----------
4 files changed, 83 insertions(+), 91 deletions(-)
(limited to 'src/spawn.h')
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 6737e330..7774d87d 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -6434,11 +6434,13 @@ void MainWindow::on_bossButton_clicked()
return;
}
- HANDLE loot = spawn::startBinary(QFileInfo(qApp->applicationDirPath() + "/loot/lootcli.exe"),
- parameters.join(" "),
- qApp->applicationDirPath() + "/loot",
- true,
- stdOutWrite);
+ spawn::SpawnParameters sp;
+ sp.binary = QFileInfo(qApp->applicationDirPath() + "/loot/lootcli.exe");
+ sp.arguments = parameters.join(" ");
+ sp.currentDirectory.setPath(qApp->applicationDirPath() + "/loot");
+ sp.stdOut = stdOutWrite;
+
+ HANDLE loot = spawn::startBinary(this, sp);
// we don't use the write end
::CloseHandle(stdOutWrite);
diff --git a/src/organizercore.cpp b/src/organizercore.cpp
index 9403b47d..dd4edbce 100644
--- a/src/organizercore.cpp
+++ b/src/organizercore.cpp
@@ -1282,6 +1282,13 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary,
const QString &customOverwrite,
const QList &forcedLibraries)
{
+ spawn::SpawnParameters sp;
+ sp.binary = binary;
+ sp.arguments = arguments;
+ sp.currentDirectory = currentDirectory;
+ sp.hooked = true;
+
+
prepareStart();
QWidget *window = qApp->activeWindow();
@@ -1290,11 +1297,11 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary,
}
- if (!spawn::checkBinary(binary)) {
+ if (!spawn::checkBinary(window, sp)) {
return INVALID_HANDLE_VALUE;
}
- if (!spawn::checkSteam(window, managedGame()->gameDirectory(), binary, steamAppID, m_Settings)) {
+ if (!spawn::checkSteam(window, sp, managedGame()->gameDirectory(), steamAppID, m_Settings)) {
return INVALID_HANDLE_VALUE;
}
@@ -1322,11 +1329,11 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary,
return INVALID_HANDLE_VALUE;
}
- if (!spawn::checkEnvironment(window, binary)) {
+ if (!spawn::checkEnvironment(window, sp)) {
return INVALID_HANDLE_VALUE;
}
- if (!spawn::checkBlacklist(window, m_Settings, binary)) {
+ if (!spawn::checkBlacklist(window, sp, m_Settings)) {
return INVALID_HANDLE_VALUE;
}
@@ -1364,11 +1371,14 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary,
log::debug("Spawning proxyed process <{}>", cmdline);
- return spawn::startBinary(QFileInfo(QCoreApplication::applicationFilePath()),
- cmdline, QCoreApplication::applicationDirPath(), true);
+ sp.binary = QFileInfo(QCoreApplication::applicationFilePath());
+ sp.arguments = cmdline;
+ sp.currentDirectory.setPath(QCoreApplication::applicationDirPath());
+
+ return spawn::startBinary(window, sp);
} else {
log::debug("Spawning direct process <{}, {}, {}>", binPath, arguments, cwdPath);
- return spawn::startBinary(binary, arguments, currentDirectory, true);
+ return spawn::startBinary(window, sp);
}
} else {
log::debug("start of \"{}\" canceled by plugin", binary.absoluteFilePath());
diff --git a/src/spawn.cpp b/src/spawn.cpp
index 4376e5bf..a56df23a 100644
--- a/src/spawn.cpp
+++ b/src/spawn.cpp
@@ -49,17 +49,6 @@ namespace spawn
namespace
{
-struct SpawnParameters
-{
- std::wstring binary;
- std::wstring arguments;
- std::wstring currentDirectory;
- bool suspended = false;
- bool hooked = false;
- HANDLE stdOut = INVALID_HANDLE_VALUE;
- HANDLE stdErr = INVALID_HANDLE_VALUE;
-};
-
std::wstring pathEnv()
{
@@ -103,12 +92,11 @@ DWORD spawn(const SpawnParameters& sp, HANDLE& processHandle, HANDLE& threadHand
si.dwFlags |= STARTF_USESTDHANDLES;
}
- std::wstring commandLine;
+ const auto bin = QDir::toNativeSeparators(sp.binary.absoluteFilePath()).toStdWString();
+ std::wstring commandLine = L"\"" + bin + L"\"";
if (sp.arguments[0] != L'\0') {
- commandLine = L"\"" + sp.binary + L"\" " + sp.arguments;
- } else {
- commandLine = L"\"" + sp.binary + L"\"";
+ commandLine += L" " + sp.arguments.toStdWString();
}
QString moPath = QCoreApplication::applicationDirPath();
@@ -119,16 +107,18 @@ DWORD spawn(const SpawnParameters& sp, HANDLE& processHandle, HANDLE& threadHand
PROCESS_INFORMATION pi;
BOOL success = FALSE;
+ const auto cwd = QDir::toNativeSeparators(sp.currentDirectory.absolutePath()).toStdWString();
+
if (sp.hooked) {
success = ::CreateProcessHooked(
nullptr, const_cast(commandLine.c_str()), nullptr, nullptr,
inheritHandles, CREATE_BREAKAWAY_FROM_JOB, nullptr,
- sp.currentDirectory.c_str(), &si, &pi);
+ cwd.c_str(), &si, &pi);
} else {
success = ::CreateProcess(
nullptr, const_cast(commandLine.c_str()), nullptr, nullptr,
inheritHandles, CREATE_BREAKAWAY_FROM_JOB, nullptr,
- sp.currentDirectory.c_str(), &si, &pi);
+ cwd.c_str(), &si, &pi);
}
const auto e = GetLastError();
@@ -164,11 +154,10 @@ std::wstring makeRightsDetails(const env::FileSecurity& fs)
std::wstring makeDetails(const SpawnParameters& sp, DWORD code)
{
- const QFileInfo bin(QString::fromStdWString(sp.binary));
std::wstring owner, rights;
- if (bin.isFile()) {
- const auto fs = env::getFileSecurity(bin.absoluteFilePath());
+ if (sp.binary.isFile()) {
+ const auto fs = env::getFileSecurity(sp.binary.absoluteFilePath());
if (fs.error.isEmpty()) {
owner = fs.owner.toStdWString();
@@ -182,8 +171,8 @@ std::wstring makeDetails(const SpawnParameters& sp, DWORD code)
rights = L"(file not found)";
}
- const bool cwdExists = (sp.currentDirectory.empty() ?
- true : QFileInfo(QString::fromStdWString(sp.currentDirectory)).isDir());
+ const bool cwdExists = (sp.currentDirectory.isEmpty() ?
+ true : sp.currentDirectory.exists());
const auto appDir = QCoreApplication::applicationDirPath();
const auto sep = QDir::separator();
@@ -214,21 +203,20 @@ std::wstring makeDetails(const SpawnParameters& sp, DWORD code)
L" . rights: {rights}\n"
L" . arguments: '{args}'\n"
L" . cwd: '{cwd}'{cwdexists}\n"
- L" . stdout: {stdout}, stderr: {stderr}, suspended: {susp}, hooked: {hooked}\n"
+ L" . stdout: {stdout}, stderr: {stderr}, hooked: {hooked}\n"
L" . usvfs x86:{x86_dll} x64:{x64_dll} proxy_x86:{x86_proxy} proxy_x64:{x64_proxy}\n"
L" . MO elevated: {elevated}",
fmt::arg(L"code", code),
fmt::arg(L"codename", errorCodeName(code)),
- fmt::arg(L"bin", sp.binary),
+ fmt::arg(L"bin", QDir::toNativeSeparators(sp.binary.absoluteFilePath()).toStdWString()),
fmt::arg(L"owner", owner),
fmt::arg(L"rights", rights),
fmt::arg(L"error", formatSystemMessage(code)),
- fmt::arg(L"args", sp.arguments),
- fmt::arg(L"cwd", sp.currentDirectory),
+ fmt::arg(L"args", sp.arguments.toStdWString()),
+ fmt::arg(L"cwd", QDir::toNativeSeparators(sp.currentDirectory.absolutePath()).toStdWString()),
fmt::arg(L"cwdexists", (cwdExists ? L"" : L" (not found)")),
fmt::arg(L"stdout", (sp.stdOut == INVALID_HANDLE_VALUE ? L"no" : L"yes")),
fmt::arg(L"stderr", (sp.stdErr == INVALID_HANDLE_VALUE ? L"no" : L"yes")),
- fmt::arg(L"susp", (sp.suspended ? L"yes" : L"no")),
fmt::arg(L"hooked", (sp.hooked ? L"yes" : L"no")),
fmt::arg(L"x86_dll", usvfs_x86_dll),
fmt::arg(L"x64_dll", usvfs_x64_dll),
@@ -242,12 +230,10 @@ void spawnFailed(const SpawnParameters& sp, DWORD code)
const auto details = QString::fromStdWString(makeDetails(sp, code));
log::error("{}", details);
- const auto binary = QFileInfo(QString::fromStdWString(sp.binary));
-
const auto title = QObject::tr("Cannot launch program");
const auto mainText = QObject::tr("Cannot start %1")
- .arg(binary.fileName());
+ .arg(sp.binary.fileName());
QString content;
@@ -286,12 +272,10 @@ bool confirmRestartAsAdmin(const SpawnParameters& sp)
log::error("{}", details);
- const auto binary = QFileInfo(QString::fromStdWString(sp.binary));
-
const auto title = QObject::tr("Elevation required");
const auto mainText = QObject::tr("Cannot start %1")
- .arg(binary.fileName());
+ .arg(sp.binary.fileName());
const auto content = QObject::tr(
"This program is requesting to run as administrator but Mod Organizer "
@@ -350,12 +334,12 @@ void startBinaryAdmin(const SpawnParameters& sp)
} // namespace
-bool checkBinary(const QFileInfo& binary)
+bool checkBinary(QWidget* parent, const SpawnParameters& sp)
{
- if (!binary.exists()) {
+ if (!sp.binary.exists()) {
reportError(
QObject::tr("Executable not found: %1")
- .arg(qUtf8Printable(binary.absoluteFilePath())));
+ .arg(sp.binary.absoluteFilePath()));
return false;
}
@@ -452,8 +436,8 @@ void startSteam(QWidget *widget)
}
bool checkSteam(
- QWidget* parent, const QDir& gameDirectory,
- const QFileInfo &binary, const QString &steamAppID, const Settings& settings)
+ QWidget* parent, const SpawnParameters& sp,
+ const QDir& gameDirectory, const QString &steamAppID, const Settings& settings)
{
if (!steamAppID.isEmpty()) {
::SetEnvironmentVariableW(L"SteamAPPId", ToWString(steamAppID).c_str());
@@ -474,7 +458,7 @@ bool checkSteam(
if (!steamFound) {
QDialogButtonBox::StandardButton result;
- result = QuestionBoxMemory::query(parent, "steamQuery", binary.fileName(),
+ result = QuestionBoxMemory::query(parent, "steamQuery", sp.binary.fileName(),
QObject::tr("Start Steam?"),
QObject::tr("Steam is required to be running already to correctly start the game. "
"Should MO try to start steam now?"),
@@ -498,7 +482,7 @@ bool checkSteam(
if (!steamAccess) {
QDialogButtonBox::StandardButton result;
- result = QuestionBoxMemory::query(parent, "steamAdminQuery", binary.fileName(),
+ result = QuestionBoxMemory::query(parent, "steamAdminQuery", sp.binary.fileName(),
QObject::tr("Steam: Access Denied"),
QObject::tr("MO was denied access to the Steam process. This normally indicates that "
"Steam is being run as administrator while MO is not. This can cause issues "
@@ -609,17 +593,17 @@ bool checkService()
return serviceRunning;
}
-bool checkEnvironment(QWidget* parent, const QFileInfo& binary)
+bool checkEnvironment(QWidget* parent, const SpawnParameters& sp)
{
// Check if the Windows Event Logging service is running. For some reason, this seems to be
// critical to the successful running of usvfs.
if (!checkService()) {
- if (QuestionBoxMemory::query(parent, QString("eventLogService"), binary.fileName(),
+ if (QuestionBoxMemory::query(parent, QString("eventLogService"), sp.binary.fileName(),
QObject::tr("Windows Event Log Error"),
QObject::tr("The Windows Event Log service is disabled and/or not running. This prevents"
" USVFS from running properly. Your mods may not be working in the executable"
" that you are launching. Note that you may have to restart MO and/or your PC"
- " after the service is fixed.\n\nContinue launching %1?").arg(binary.fileName()),
+ " after the service is fixed.\n\nContinue launching %1?").arg(sp.binary.fileName()),
QDialogButtonBox::Yes | QDialogButtonBox::No) == QDialogButtonBox::No) {
return false;
}
@@ -628,16 +612,16 @@ bool checkEnvironment(QWidget* parent, const QFileInfo& binary)
return true;
}
-bool checkBlacklist(QWidget* parent, const Settings& settings, const QFileInfo& binary)
+bool checkBlacklist(QWidget* parent, const SpawnParameters& sp, const Settings& settings)
{
for (auto exec : settings.executablesBlacklist().split(";")) {
- if (exec.compare(binary.fileName(), Qt::CaseInsensitive) == 0) {
- if (QuestionBoxMemory::query(parent, QString("blacklistedExecutable"), binary.fileName(),
+ if (exec.compare(sp.binary.fileName(), Qt::CaseInsensitive) == 0) {
+ if (QuestionBoxMemory::query(parent, QString("blacklistedExecutable"), sp.binary.fileName(),
QObject::tr("Blacklisted Executable"),
QObject::tr("The executable you are attempted to launch is blacklisted in the virtual file"
" system. This will likely prevent the executable, and any executables that are"
" launched by this one, from seeing any mods. This could extend to INI files, save"
- " games and any other virtualized files.\n\nContinue launching %1?").arg(binary.fileName()),
+ " games and any other virtualized files.\n\nContinue launching %1?").arg(sp.binary.fileName()),
QDialogButtonBox::Yes | QDialogButtonBox::No) == QDialogButtonBox::No) {
return false;
}
@@ -648,20 +632,8 @@ bool checkBlacklist(QWidget* parent, const Settings& settings, const QFileInfo&
}
-HANDLE startBinary(
- const QFileInfo &binary, const QString &arguments, const QDir ¤tDirectory,
- bool hooked, HANDLE stdOut, HANDLE stdErr)
+HANDLE startBinary(QWidget* parent, const SpawnParameters& sp)
{
- SpawnParameters sp;
-
- sp.binary = QDir::toNativeSeparators(binary.absoluteFilePath()).toStdWString();
- sp.arguments = arguments.toStdWString();
- sp.currentDirectory = QDir::toNativeSeparators(currentDirectory.absolutePath()).toStdWString();
- sp.suspended = true;
- sp.hooked = hooked;
- sp.stdOut = stdOut;
- sp.stdErr = stdErr;
-
HANDLE processHandle, threadHandle;
const auto e = spawn(sp, processHandle, threadHandle);
diff --git a/src/spawn.h b/src/spawn.h
index 9a5afb4a..9398b6cc 100644
--- a/src/spawn.h
+++ b/src/spawn.h
@@ -31,20 +31,7 @@ class Settings;
namespace spawn
{
-bool checkBinary(const QFileInfo& binary);
-
-bool checkSteam(
- QWidget* parent, const QDir& gameDirectory,
- const QFileInfo &binary, const QString &steamAppID, const Settings& settings);
-
-bool checkEnvironment(QWidget* parent, const QFileInfo& binary);
-
-bool checkBlacklist(
- QWidget* parent, const Settings& settings, const QFileInfo& binary);
-
-/**
- * @brief spawn a binary with Mod Organizer injected
- *
+/*
* @param binary the binary to spawn
* @param arguments arguments to pass to the binary
* @param profileName name of the active profile
@@ -53,13 +40,34 @@ bool checkBlacklist(
* @param hooked if set, the binary is started with mo injected
* @param stdout if not equal to INVALID_HANDLE_VALUE, this is used as stdout for the process
* @param stderr if not equal to INVALID_HANDLE_VALUE, this is used as stderr for the process
+*/
+struct SpawnParameters
+{
+ QFileInfo binary;
+ QString arguments;
+ QDir currentDirectory;
+ bool hooked = false;
+ HANDLE stdOut = INVALID_HANDLE_VALUE;
+ HANDLE stdErr = INVALID_HANDLE_VALUE;
+};
+
+
+bool checkBinary(QWidget* parent, const SpawnParameters& sp);
+
+bool checkSteam(
+ QWidget* parent, const SpawnParameters& sp,
+ const QDir& gameDirectory, const QString &steamAppID, const Settings& settings);
+
+bool checkEnvironment(QWidget* parent, const SpawnParameters& sp);
+
+bool checkBlacklist(
+ QWidget* parent, const SpawnParameters& sp, const Settings& settings);
+
+/**
+ * @brief spawn a binary with Mod Organizer injected
* @return the process handle
- * @todo is the profile name even used any more?
- * @todo is the hooked parameter used?
**/
-HANDLE startBinary(const QFileInfo &binary, const QString &arguments,
- const QDir ¤tDirectory, bool hooked,
- HANDLE stdOut = INVALID_HANDLE_VALUE, HANDLE stdErr = INVALID_HANDLE_VALUE);
+HANDLE startBinary(QWidget* parent, const SpawnParameters& sp);
} // namespace
--
cgit v1.3.1
From c603681115b6071f241f6931685d36a92b6403f8 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Thu, 19 Sep 2019 10:07:52 -0400
Subject: moved helper stuff to spawn so it can reuse error handling removed
unused helper::init() removed logging when deleting a credential that doesn't
exist, happens all the time
---
src/envsecurity.cpp | 2 +-
src/helper.cpp | 107 +---------------------------
src/helper.h | 42 +----------
src/settingsdialogworkarounds.cpp | 2 +-
src/settingsutilities.cpp | 18 ++---
src/spawn.cpp | 145 +++++++++++++++++++++++++++++++++++---
src/spawn.h | 25 +++++++
7 files changed, 175 insertions(+), 166 deletions(-)
(limited to 'src/spawn.h')
diff --git a/src/envsecurity.cpp b/src/envsecurity.cpp
index 6e3fadbe..3b4cdcaa 100644
--- a/src/envsecurity.cpp
+++ b/src/envsecurity.cpp
@@ -275,7 +275,7 @@ std::vector getSecurityProductsFromWMI()
}
if (prop.vt != VT_UI4 && prop.vt != VT_I4) {
- log::error("productState is a {}, is not a VT_UI4", prop.vt);
+ log::error("productState is a {}, not a VT_UI4", prop.vt);
return;
}
diff --git a/src/helper.cpp b/src/helper.cpp
index 59a2d3d1..24446cb8 100644
--- a/src/helper.cpp
+++ b/src/helper.cpp
@@ -17,109 +17,4 @@ You should have received a copy of the GNU General Public License
along with Mod Organizer. If not, see .
*/
-#include "helper.h"
-#include "utility.h"
-#include
-#include
-
-#define WIN32_LEAN_AND_MEAN
-#include
-
-#include
-#include
-
-using MOBase::reportError;
-
-
-namespace Helper {
-
-
-static bool helperExec(LPCWSTR moDirectory, LPCWSTR commandLine, BOOL async)
-{
- wchar_t fileName[MAX_PATH];
- _snwprintf(fileName, MAX_PATH, L"%ls\\helper.exe", moDirectory);
-
- SHELLEXECUTEINFOW execInfo = {0};
-
- execInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
- execInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
- execInfo.hwnd = nullptr;
- execInfo.lpVerb = L"runas";
- execInfo.lpFile = fileName;
- execInfo.lpParameters = commandLine;
- execInfo.lpDirectory = moDirectory;
- execInfo.nShow = SW_SHOW;
-
- ::ShellExecuteExW(&execInfo);
-
- if (execInfo.hProcess == 0) {
- reportError(QObject::tr("helper failed"));
- return false;
- }
-
- if (async) {
- return true;
- }
-
- if (::WaitForSingleObject(execInfo.hProcess, INFINITE) != WAIT_OBJECT_0) {
- reportError(QObject::tr("helper failed"));
- return false;
- }
-
- DWORD exitCode;
- GetExitCodeProcess(execInfo.hProcess, &exitCode);
- return exitCode == NOERROR;
-}
-
-
-bool init(const std::wstring &moPath, const std::wstring &dataPath)
-{
- DWORD userNameLen = UNLEN + 1;
- wchar_t userName[UNLEN + 1];
-
- if (!GetUserName(userName, &userNameLen)) {
- reportError(QObject::tr("failed to determine account name"));
- return false;
- }
- wchar_t *commandLine = new wchar_t[32768];
-
- _snwprintf(commandLine, 32768, L"init \"%ls\" \"%ls\"",
- dataPath.c_str(), userName);
-
- bool res = helperExec(moPath.c_str(), commandLine, FALSE);
- delete [] commandLine;
-
- return res;
-}
-
-
-bool backdateBSAs(const std::wstring &moPath, const std::wstring &dataPath)
-{
- wchar_t *commandLine = new wchar_t[32768];
- _snwprintf(commandLine, 32768, L"backdateBSA \"%ls\"",
- dataPath.c_str());
-
- bool res = helperExec(moPath.c_str(), commandLine, FALSE);
- delete [] commandLine;
-
- return res;
-}
-
-
-bool adminLaunch(const std::wstring &moPath, const std::wstring &moFile, const std::wstring &workingDir)
-{
- wchar_t *commandLine = new wchar_t[32768];
- _snwprintf(commandLine, 32768, L"adminLaunch %d \"%ls\" \"%ls\"",
- ::GetCurrentProcessId(),
- moFile.c_str(),
- workingDir.c_str()
- );
-
- bool res = helperExec(moPath.c_str(), commandLine, TRUE);
- delete [] commandLine;
-
- return res;
-}
-
-
-} // namespace
+// moved to spawn.cpp
diff --git a/src/helper.h b/src/helper.h
index f6667a84..335b8647 100644
--- a/src/helper.h
+++ b/src/helper.h
@@ -20,45 +20,7 @@ along with Mod Organizer. If not, see .
#ifndef HELPER_H
#define HELPER_H
-
-#include
-
-
-/**
- * @brief Convenience functions to work with the external helper program.
- *
- * The mo_helper program is used to make changes on the system that require administrative
- * rights, so that ModOrganizer itself can run without special privileges
- **/
-namespace Helper {
-
-/**
- * @brief initialise the specified directory for use with mod organizer.
- *
- * This will create all required sub-directories and give the user running ModOrganizer
- * write-access
- *
- * @param moPath absolute path to the ModOrganizer base directory
- * @return true on success
- **/
-bool init(const std::wstring &moPath, const std::wstring &dataPath);
-
-/**
- * @brief sets the last modified time for all .bsa-files in the target directory well into the past
- * @param moPath absolute path to the modOrganizer base directory
- * @param dataPath the path taht contains the .bsa-files, usually the data directory of the game
- **/
-bool backdateBSAs(const std::wstring &moPath, const std::wstring &dataPath);
-
-/**
- * @brief waits for the current process to exit and restarts it as an administrator
- * @param moPath absolute path to the modOrganizer base directory
- * @param moFile file name of modOrganizer
- * @param workingDir current working directory
- **/
-bool adminLaunch(const std::wstring &moPath, const std::wstring &moFile, const std::wstring &workingDir);
-
-}
-
+// all helper code moved to spawn.h and spawn.cpp
+#include "spawn.h"
#endif // HELPER_H
diff --git a/src/settingsdialogworkarounds.cpp b/src/settingsdialogworkarounds.cpp
index 4d811e40..f89b021c 100644
--- a/src/settingsdialogworkarounds.cpp
+++ b/src/settingsdialogworkarounds.cpp
@@ -83,7 +83,7 @@ void WorkaroundsSettingsTab::on_bsaDateBtn_clicked()
const auto* game = qApp->property("managed_game").value();
QDir dir = game->dataDirectory();
- Helper::backdateBSAs(qApp->applicationDirPath().toStdWString(),
+ helper::backdateBSAs(qApp->applicationDirPath().toStdWString(),
dir.absolutePath().toStdWString());
}
diff --git a/src/settingsutilities.cpp b/src/settingsutilities.cpp
index 6c99a602..db7c1818 100644
--- a/src/settingsutilities.cpp
+++ b/src/settingsutilities.cpp
@@ -224,16 +224,18 @@ bool deleteWindowsCredential(const QString& key)
if (!CredDeleteW(credName.toStdWString().c_str(), CRED_TYPE_GENERIC, 0)) {
const auto e = GetLastError();
+
+ // not an error if the key already doesn't exist, and don't log it because
+ // it happens all the time when the settings dialog is closed since it
+ // doesn't check first
if (e == ERROR_NOT_FOUND) {
- // not an error if the key already doesn't exist
- log::debug("can't delete windows credential {}, doesn't exist", credName);
return true;
- } else {
- log::error(
- "failed to delete windows credential {}, {}",
- credName, formatSystemMessage(e));
- return false;
}
+
+ log::error(
+ "failed to delete windows credential {}, {}",
+ credName, formatSystemMessage(e));
+ return false;
}
log::debug("deleted windows credential {}", credName);
@@ -269,7 +271,7 @@ bool addWindowsCredential(const QString& key, const QString& data)
return false;
}
- log::debug("added windows credential {}", credName);
+ log::debug("set windows credential {}", credName);
return true;
}
diff --git a/src/spawn.cpp b/src/spawn.cpp
index 94737871..6c524681 100644
--- a/src/spawn.cpp
+++ b/src/spawn.cpp
@@ -64,7 +64,7 @@ std::wstring makeRightsDetails(const env::FileSecurity& fs)
return s;
}
-std::wstring makeDetails(const SpawnParameters& sp, DWORD code)
+QString makeDetails(const SpawnParameters& sp, DWORD code, const QString& more={})
{
std::wstring owner, rights;
@@ -109,7 +109,7 @@ std::wstring makeDetails(const SpawnParameters& sp, DWORD code)
}
std::wstring f =
- L"Error {code} {codename}: {error}\n"
+ L"Error {code} {codename}{more}: {error}\n"
L" . binary: '{bin}'\n"
L" . owner: {owner}\n"
L" . rights: {rights}\n"
@@ -122,9 +122,12 @@ std::wstring makeDetails(const SpawnParameters& sp, DWORD code)
f += L"\n . usvfs x86:{x86_dll} x64:{x64_dll} proxy_x86:{x86_proxy} proxy_x64:{x64_proxy}";
}
- return fmt::format(f,
+ const std::wstring wmore = (more.isEmpty() ? L"" : (", " + more).toStdWString());
+
+ const auto s = fmt::format(f,
fmt::arg(L"code", code),
fmt::arg(L"codename", errorCodeName(code)),
+ fmt::arg(L"more", wmore),
fmt::arg(L"bin", QDir::toNativeSeparators(sp.binary.absoluteFilePath()).toStdWString()),
fmt::arg(L"owner", owner),
fmt::arg(L"rights", rights),
@@ -140,6 +143,8 @@ std::wstring makeDetails(const SpawnParameters& sp, DWORD code)
fmt::arg(L"x86_proxy", usvfs_x86_proxy),
fmt::arg(L"x64_proxy", usvfs_x64_proxy),
fmt::arg(L"elevated", elevated));
+
+ return QString::fromStdWString(s);
}
QString makeContent(const SpawnParameters& sp, DWORD code)
@@ -198,7 +203,7 @@ QMessageBox::StandardButton startSteamFailed(
return MOBase::TaskDialog(parent, QObject::tr("Cannot start Steam"))
.main(QObject::tr("Cannot start Steam"))
.content(makeContent(sp, e))
- .details(QString::fromStdWString(details))
+ .details(details)
.button({
QObject::tr("Continue without starting Steam"),
QObject::tr("The program may fail to launch."),
@@ -211,7 +216,7 @@ QMessageBox::StandardButton startSteamFailed(
void spawnFailed(const SpawnParameters& sp, DWORD code)
{
- const auto details = QString::fromStdWString(makeDetails(sp, code));
+ const auto details = makeDetails(sp, code);
log::error("{}", details);
const auto title = QObject::tr("Cannot launch program");
@@ -231,10 +236,38 @@ void spawnFailed(const SpawnParameters& sp, DWORD code)
.exec();
}
+void helperFailed(
+ DWORD code, const QString& why, const std::wstring& binary,
+ const std::wstring& cwd, const std::wstring& args)
+{
+ SpawnParameters sp;
+ sp.binary = QString::fromStdWString(binary);
+ sp.currentDirectory.setPath(QString::fromStdWString(cwd));
+ sp.arguments = QString::fromStdWString(args);
+
+ const auto details = makeDetails(sp, code, "in " + why);
+ log::error("{}", details);
+
+ const auto title = QObject::tr("Cannot launch helper");
+
+ const auto mainText = QObject::tr("Cannot start %1")
+ .arg(sp.binary.fileName());
+
+ QWidget *window = qApp->activeWindow();
+ if ((window != nullptr) && (!window->isVisible())) {
+ window = nullptr;
+ }
+
+ MOBase::TaskDialog(window, title)
+ .main(mainText)
+ .content(makeContent(sp, code))
+ .details(details)
+ .exec();
+}
+
bool confirmRestartAsAdmin(const SpawnParameters& sp)
{
- const auto details = QString::fromStdWString(
- makeDetails(sp, ERROR_ELEVATION_REQUIRED));
+ const auto details = makeDetails(sp, ERROR_ELEVATION_REQUIRED);
log::error("{}", details);
@@ -370,18 +403,18 @@ bool restartAsAdmin()
cwd[0] = L'\0';
}
- if (!Helper::adminLaunch(
+ if (!helper::adminLaunch(
qApp->applicationDirPath().toStdWString(),
qApp->applicationFilePath().toStdWString(),
std::wstring(cwd)))
{
- // todo
log::error("admin launch failed");
return false;
}
log::debug("exiting MO");
qApp->exit(0);
+
return true;
}
@@ -728,4 +761,96 @@ HANDLE startBinary(QWidget* parent, const SpawnParameters& sp)
}
}
-} // namespace
\ No newline at end of file
+} // namespace
+
+
+
+namespace helper
+{
+
+bool helperExec(
+ const std::wstring& moDirectory, const std::wstring& commandLine, BOOL async)
+{
+ const std::wstring fileName = moDirectory + L"\\helper.exe";
+
+ env::HandlePtr process;
+
+ {
+ SHELLEXECUTEINFOW execInfo = {};
+
+ ULONG flags = SEE_MASK_FLAG_NO_UI ;
+ if (!async)
+ flags |= SEE_MASK_NOCLOSEPROCESS;
+
+ execInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
+ execInfo.fMask = flags;
+ execInfo.hwnd = 0;
+ execInfo.lpVerb = L"runas";
+ execInfo.lpFile = fileName.c_str();
+ execInfo.lpParameters = commandLine.c_str();
+ execInfo.lpDirectory = moDirectory.c_str();
+ execInfo.nShow = SW_SHOW;
+
+ if (!::ShellExecuteExW(&execInfo) && execInfo.hProcess == 0) {
+ const auto e = GetLastError();
+
+ spawn::dialogs::helperFailed(
+ e, "ShellExecuteExW()", fileName, moDirectory, commandLine);
+
+ return false;
+ }
+
+ if (async) {
+ return true;
+ }
+
+ process.reset(execInfo.hProcess);
+ }
+
+ const auto r = ::WaitForSingleObject(process.get(), INFINITE);
+
+ if (r != WAIT_OBJECT_0) {
+ // for WAIT_ABANDONED, the documentation doesn't mention that GetLastError()
+ // returns something meaningful, but code ERROR_ABANDONED_WAIT_0 exists, so
+ // use that instead
+ const auto code = (r == WAIT_ABANDONED ?
+ ERROR_ABANDONED_WAIT_0 : GetLastError());
+
+ spawn::dialogs::helperFailed(
+ code, "WaitForSingleObject()", fileName, moDirectory, commandLine);
+
+ return false;
+ }
+
+ DWORD exitCode = 0;
+ if (!GetExitCodeProcess(process.get(), &exitCode)) {
+ const auto e = GetLastError();
+
+ spawn::dialogs::helperFailed(
+ e, "GetExitCodeProcess()", fileName, moDirectory, commandLine);
+
+ return false;
+ }
+
+ return (exitCode == 0);
+}
+
+bool backdateBSAs(const std::wstring &moPath, const std::wstring &dataPath)
+{
+ const std::wstring commandLine = fmt::format(
+ L"backdateBSA \"{}\"", dataPath);
+
+ return helperExec(moPath, commandLine, FALSE);
+}
+
+
+bool adminLaunch(const std::wstring &moPath, const std::wstring &moFile, const std::wstring &workingDir)
+{
+ const std::wstring commandLine = fmt::format(
+ L"adminLaunch {} \"{}\" \"{}\"",
+ ::GetCurrentProcessId(), moFile, workingDir);
+
+ return helperExec(moPath, commandLine, true);
+}
+
+} // namespace
diff --git a/src/spawn.h b/src/spawn.h
index 9398b6cc..da626329 100644
--- a/src/spawn.h
+++ b/src/spawn.h
@@ -71,5 +71,30 @@ HANDLE startBinary(QWidget* parent, const SpawnParameters& sp);
} // namespace
+
+// convenience functions to work with the external helper program, which is used
+// to make changes on the system that require administrative rights, so that
+// ModOrganizer itself can run without special privileges
+//
+namespace helper
+{
+
+/**
+* @brief sets the last modified time for all .bsa-files in the target directory well into the past
+* @param moPath absolute path to the modOrganizer base directory
+* @param dataPath the path taht contains the .bsa-files, usually the data directory of the game
+**/
+bool backdateBSAs(const std::wstring &moPath, const std::wstring &dataPath);
+
+/**
+* @brief waits for the current process to exit and restarts it as an administrator
+* @param moPath absolute path to the modOrganizer base directory
+* @param moFile file name of modOrganizer
+* @param workingDir current working directory
+**/
+bool adminLaunch(const std::wstring &moPath, const std::wstring &moFile, const std::wstring &workingDir);
+
+} // namespace
+
#endif // SPAWN_H
--
cgit v1.3.1
From f92e2c376d36132a9676b30f0b08543f27a13064 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Thu, 19 Sep 2019 16:27:41 -0400
Subject: TaskDialog for restarting as admin for steam added a parent widget
parameter to a bunch of places fixed paths still getting changed even if
folders can't be created made private the member variables that were
temporarily public during rework
---
src/settingsdialog.cpp | 44 ++++++++++------
src/settingsdialog.h | 20 +++----
src/settingsdialoggeneral.cpp | 7 ++-
src/settingsdialognexus.cpp | 14 ++---
src/settingsdialogpaths.cpp | 6 ++-
src/settingsdialogworkarounds.cpp | 6 ++-
src/spawn.cpp | 106 ++++++++++++++++++++------------------
src/spawn.h | 7 ++-
8 files changed, 121 insertions(+), 89 deletions(-)
(limited to 'src/spawn.h')
diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp
index 1d3d4a39..8fb25b1c 100644
--- a/src/settingsdialog.cpp
+++ b/src/settingsdialog.cpp
@@ -33,8 +33,8 @@ SettingsDialog::SettingsDialog(PluginContainer *pluginContainer, Settings& setti
: TutorableDialog("SettingsDialog", parent)
, ui(new Ui::SettingsDialog)
, m_settings(settings)
- , m_PluginContainer(pluginContainer)
- , m_keyChanged(false)
+ , m_pluginContainer(pluginContainer)
+ , m_restartNeeded(false)
{
ui->setupUi(this);
@@ -47,6 +47,25 @@ SettingsDialog::SettingsDialog(PluginContainer *pluginContainer, Settings& setti
m_tabs.push_back(std::unique_ptr(new WorkaroundsSettingsTab(settings, *this)));
}
+PluginContainer* SettingsDialog::pluginContainer()
+{
+ return m_pluginContainer;
+}
+
+QWidget* SettingsDialog::parentWidgetForDialogs()
+{
+ if (isVisible()) {
+ return this;
+ } else {
+ return parentWidget();
+ }
+}
+
+void SettingsDialog::setRestartNeeded()
+{
+ m_restartNeeded = true;
+}
+
int SettingsDialog::exec()
{
GeometrySaver gs(m_settings, this);
@@ -68,13 +87,8 @@ int SettingsDialog::exec()
}
}
- bool restartNeeded = false;
- if (getApiKeyChanged()) {
- restartNeeded = true;
- }
-
- if (restartNeeded) {
- if (QMessageBox::question(nullptr,
+ if (m_restartNeeded) {
+ if (QMessageBox::question(parentWidgetForDialogs(),
tr("Restart Mod Organizer?"),
tr("In order to finish configuration changes, MO must be restarted.\n"
"Restart it now?"),
@@ -111,7 +125,7 @@ void SettingsDialog::accept()
QDir::fromNativeSeparators(
Settings::instance().paths().mods(true))) &&
(QMessageBox::question(
- nullptr, tr("Confirm"),
+ parentWidgetForDialogs(), tr("Confirm"),
tr("Changing the mod directory affects all your profiles! "
"Mods not present (or named differently) in the new location "
"will be disabled in all profiles. "
@@ -124,11 +138,6 @@ void SettingsDialog::accept()
TutorableDialog::accept();
}
-bool SettingsDialog::getApiKeyChanged()
-{
- return m_keyChanged;
-}
-
SettingsTab::SettingsTab(Settings& s, SettingsDialog& d)
: ui(d.ui), m_settings(s), m_dialog(d)
@@ -146,3 +155,8 @@ SettingsDialog& SettingsTab::dialog()
{
return m_dialog;
}
+
+QWidget* SettingsTab::parentWidget()
+{
+ return m_dialog.parentWidgetForDialogs();
+}
diff --git a/src/settingsdialog.h b/src/settingsdialog.h
index 6a99cb8d..e89da665 100644
--- a/src/settingsdialog.h
+++ b/src/settingsdialog.h
@@ -42,6 +42,7 @@ protected:
Settings& settings();
SettingsDialog& dialog();
+ QWidget* parentWidget();
private:
Settings& m_settings;
@@ -56,11 +57,12 @@ private:
**/
class SettingsDialog : public MOBase::TutorableDialog
{
- Q_OBJECT
+ Q_OBJECT;
+ friend class SettingsTab;
public:
explicit SettingsDialog(
- PluginContainer *pluginContainer, Settings& settings, QWidget *parent = 0);
+ PluginContainer* pluginContainer, Settings& settings, QWidget* parent = 0);
~SettingsDialog();
@@ -70,23 +72,21 @@ public:
*/
QString getColoredButtonStyleSheet() const;
- // temp
- Ui::SettingsDialog *ui;
- bool m_keyChanged;
- PluginContainer *m_PluginContainer;
+ PluginContainer* pluginContainer();
+ QWidget* parentWidgetForDialogs();
+ void setRestartNeeded();
int exec() override;
public slots:
virtual void accept();
-public:
- bool getApiKeyChanged();
-
private:
Settings& m_settings;
std::vector> m_tabs;
-
+ Ui::SettingsDialog* ui;
+ bool m_restartNeeded;
+ PluginContainer* m_pluginContainer;
};
#endif // SETTINGSDIALOG_H
diff --git a/src/settingsdialoggeneral.cpp b/src/settingsdialoggeneral.cpp
index 3f7ece38..8ecdcbb9 100644
--- a/src/settingsdialoggeneral.cpp
+++ b/src/settingsdialoggeneral.cpp
@@ -238,8 +238,11 @@ void GeneralSettingsTab::on_resetColorsBtn_clicked()
void GeneralSettingsTab::on_resetDialogsButton_clicked()
{
- if (QMessageBox::question(&dialog(), QObject::tr("Confirm?"),
- QObject::tr("This will make all dialogs show up again where you checked the \"Remember selection\"-box. Continue?"),
+ if (QMessageBox::question(
+ parentWidget(), QObject::tr("Confirm?"),
+ QObject::tr(
+ "This will reset all the choices you made to dialogs and make them all "
+ "visible again. Continue?"),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
resetDialogs();
}
diff --git a/src/settingsdialognexus.cpp b/src/settingsdialognexus.cpp
index 0b08f13f..826075c0 100644
--- a/src/settingsdialognexus.cpp
+++ b/src/settingsdialognexus.cpp
@@ -226,7 +226,7 @@ void NexusSettingsTab::on_nexusDisconnect_clicked()
void NexusSettingsTab::on_clearCacheButton_clicked()
{
QDir(Settings::instance().paths().cache()).removeRecursively();
- NexusInterface::instance(dialog().m_PluginContainer)->clearCache();
+ NexusInterface::instance(dialog().pluginContainer())->clearCache();
}
void NexusSettingsTab::on_associateButton_clicked()
@@ -238,7 +238,7 @@ void NexusSettingsTab::validateKey(const QString& key)
{
if (!m_nexusValidator) {
m_nexusValidator.reset(new NexusKeyValidator(
- *NexusInterface::instance(dialog().m_PluginContainer)->getAccessManager()));
+ *NexusInterface::instance(dialog().pluginContainer())->getAccessManager()));
m_nexusValidator->stateChanged = [&](auto&& s, auto&& e){
onValidatorStateChanged(s, e);
@@ -294,7 +294,7 @@ void NexusSettingsTab::onValidatorStateChanged(
void NexusSettingsTab::onValidatorFinished(const APIUserAccount& user)
{
- NexusInterface::instance(dialog().m_PluginContainer)->setUserAccount(user);
+ NexusInterface::instance(dialog().pluginContainer())->setUserAccount(user);
if (!user.apiKey().isEmpty()) {
if (setKey(user.apiKey())) {
@@ -311,7 +311,7 @@ void NexusSettingsTab::addNexusLog(const QString& s)
bool NexusSettingsTab::setKey(const QString& key)
{
- dialog().m_keyChanged = true;
+ dialog().setRestartNeeded();
const bool ret = settings().nexus().setApiKey(key);
updateNexusState();
return ret;
@@ -319,10 +319,10 @@ bool NexusSettingsTab::setKey(const QString& key)
bool NexusSettingsTab::clearKey()
{
- dialog().m_keyChanged = true;
+ dialog().setRestartNeeded();
const auto ret = settings().nexus().clearApiKey();
- NexusInterface::instance(dialog().m_PluginContainer)->getAccessManager()->clearApiKey();
+ NexusInterface::instance(dialog().pluginContainer())->getAccessManager()->clearApiKey();
updateNexusState();
return ret;
@@ -371,7 +371,7 @@ void NexusSettingsTab::updateNexusButtons()
void NexusSettingsTab::updateNexusData()
{
- const auto user = NexusInterface::instance(dialog().m_PluginContainer)
+ const auto user = NexusInterface::instance(dialog().pluginContainer())
->getAPIUserAccount();
if (user.isValid()) {
diff --git a/src/settingsdialogpaths.cpp b/src/settingsdialogpaths.cpp
index aeb4dd5d..c6fd40a7 100644
--- a/src/settingsdialogpaths.cpp
+++ b/src/settingsdialogpaths.cpp
@@ -68,10 +68,12 @@ void PathsSettingsTab::update()
if (!QDir(realPath).exists()) {
if (!QDir().mkpath(realPath)) {
- QMessageBox::warning(qApp->activeWindow(), QObject::tr("Error"),
+ QMessageBox::warning(parentWidget(), QObject::tr("Error"),
QObject::tr("Failed to create \"%1\", you may not have the "
- "necessary permission. path remains unchanged.")
+ "necessary permissions. Path remains unchanged.")
.arg(realPath));
+
+ continue;
}
}
diff --git a/src/settingsdialogworkarounds.cpp b/src/settingsdialogworkarounds.cpp
index ccbfcbfe..5e70e5a6 100644
--- a/src/settingsdialogworkarounds.cpp
+++ b/src/settingsdialogworkarounds.cpp
@@ -83,7 +83,9 @@ void WorkaroundsSettingsTab::on_bsaDateBtn_clicked()
const auto* game = qApp->property("managed_game").value();
QDir dir = game->dataDirectory();
- helper::backdateBSAs(qApp->applicationDirPath().toStdWString(),
+ helper::backdateBSAs(
+ parentWidget(),
+ qApp->applicationDirPath().toStdWString(),
dir.absolutePath().toStdWString());
}
@@ -95,7 +97,7 @@ void WorkaroundsSettingsTab::on_resetGeometryBtn_clicked()
"Restart now?");
const auto res = QMessageBox::question(
- nullptr, caption, text, QMessageBox::Yes | QMessageBox::Cancel);
+ parentWidget(), caption, text, QMessageBox::Yes | QMessageBox::Cancel);
if (res == QMessageBox::Yes) {
settings().geometry().requestReset();
diff --git a/src/spawn.cpp b/src/spawn.cpp
index e18e6bb3..a0cf9fb6 100644
--- a/src/spawn.cpp
+++ b/src/spawn.cpp
@@ -215,7 +215,7 @@ QMessageBox::StandardButton startSteamFailed(
.exec();
}
-void spawnFailed(const SpawnParameters& sp, DWORD code)
+void spawnFailed(QWidget* parent, const SpawnParameters& sp, DWORD code)
{
const auto details = makeDetails(sp, code);
log::error("{}", details);
@@ -225,12 +225,7 @@ void spawnFailed(const SpawnParameters& sp, DWORD code)
const auto mainText = QObject::tr("Cannot start %1")
.arg(sp.binary.fileName());
- QWidget *window = qApp->activeWindow();
- if ((window != nullptr) && (!window->isVisible())) {
- window = nullptr;
- }
-
- MOBase::TaskDialog(window, title)
+ MOBase::TaskDialog(parent, title)
.main(mainText)
.content(makeContent(sp, code))
.details(details)
@@ -239,7 +234,7 @@ void spawnFailed(const SpawnParameters& sp, DWORD code)
}
void helperFailed(
- DWORD code, const QString& why, const std::wstring& binary,
+ QWidget* parent, DWORD code, const QString& why, const std::wstring& binary,
const std::wstring& cwd, const std::wstring& args)
{
SpawnParameters sp;
@@ -255,12 +250,7 @@ void helperFailed(
const auto mainText = QObject::tr("Cannot start %1")
.arg(sp.binary.fileName());
- QWidget *window = qApp->activeWindow();
- if ((window != nullptr) && (!window->isVisible())) {
- window = nullptr;
- }
-
- MOBase::TaskDialog(window, title)
+ MOBase::TaskDialog(parent, title)
.main(mainText)
.content(makeContent(sp, code))
.details(details)
@@ -268,7 +258,7 @@ void helperFailed(
.exec();
}
-bool confirmRestartAsAdmin(const SpawnParameters& sp)
+bool confirmRestartAsAdmin(QWidget* parent, const SpawnParameters& sp)
{
const auto details = makeDetails(sp, ERROR_ELEVATION_REQUIRED);
@@ -287,15 +277,9 @@ bool confirmRestartAsAdmin(const SpawnParameters& sp)
"You can restart Mod Organizer as administrator and try launching the "
"program again.");
-
- QWidget *window = qApp->activeWindow();
- if ((window != nullptr) && (!window->isVisible())) {
- window = nullptr;
- }
-
log::debug("asking user to restart MO as administrator");
- const auto r = MOBase::TaskDialog(window, title)
+ const auto r = MOBase::TaskDialog(parent, title)
.main(mainText)
.content(content)
.details(details)
@@ -313,7 +297,7 @@ bool confirmRestartAsAdmin(const SpawnParameters& sp)
}
QMessageBox::StandardButton confirmStartSteam(
- QWidget* window, const SpawnParameters& sp, const QString& details)
+ QWidget* parent, const SpawnParameters& sp, const QString& details)
{
const auto title = QObject::tr("Launch Steam");
const auto mainText = QObject::tr("This program requires Steam");
@@ -321,7 +305,7 @@ QMessageBox::StandardButton confirmStartSteam(
"Mod Organizer has detected that this program likely requires Steam to be "
"running to function properly.");
- return MOBase::TaskDialog(window, title)
+ return MOBase::TaskDialog(parent, title)
.main(mainText)
.content(content)
.details(details)
@@ -340,17 +324,35 @@ QMessageBox::StandardButton confirmStartSteam(
.exec();
}
-QuestionBoxMemory::Button confirmRestartAsAdminForSteam(QWidget* parent, const SpawnParameters& sp)
+QMessageBox::StandardButton confirmRestartAsAdminForSteam(
+ QWidget* parent, const SpawnParameters& sp)
{
- return QuestionBoxMemory::query(
- parent, "steamAdminQuery", sp.binary.fileName(),
- QObject::tr("Steam: Access Denied"),
- QObject::tr("MO was denied access to the Steam process. This normally indicates that "
- "Steam is being run as administrator while MO is not. This can cause issues "
- "launching the game. It is recommended to not run Steam as administrator unless "
- "absolutely necessary.\n\n"
- "Restart MO as administrator?"),
- QDialogButtonBox::Yes | QDialogButtonBox::No | QDialogButtonBox::Cancel);
+ const auto title = QObject::tr("Elevation required");
+ const auto mainText = QObject::tr("Steam is running as administrator");
+ const auto content = QObject::tr(
+ "Running Steam as administrator is typically unnecessary and can cause "
+ "problems when Mod Organizer is not running as administrato\r\n\r\n"
+ "You can restart Mod Organizer as administrator and try launching the "
+ "program again.");
+
+ return MOBase::TaskDialog(parent, title)
+ .main(mainText)
+ .content(content)
+ .details("")
+ .icon(QMessageBox::Question)
+ .button({
+ QObject::tr("Restart Mod Organizer as administrator"),
+ QObject::tr("You must allow \"helper.exe\" to make changes to the system."),
+ QMessageBox::Yes})
+ .button({
+ QObject::tr("Continue"),
+ QObject::tr("The program might fail to run."),
+ QMessageBox::No})
+ .button({
+ QObject::tr("Cancel"),
+ QMessageBox::Cancel})
+ .remember("steamAdminQuery", sp.binary.fileName())
+ .exec();
}
bool eventLogNotRunning(
@@ -447,7 +449,7 @@ DWORD spawn(const SpawnParameters& sp, HANDLE& processHandle, HANDLE& threadHand
return ERROR_SUCCESS;
}
-bool restartAsAdmin()
+bool restartAsAdmin(QWidget* parent)
{
WCHAR cwd[MAX_PATH] = {};
if (!GetCurrentDirectory(MAX_PATH, cwd)) {
@@ -455,6 +457,7 @@ bool restartAsAdmin()
}
if (!helper::adminLaunch(
+ parent,
qApp->applicationDirPath().toStdWString(),
qApp->applicationFilePath().toStdWString(),
std::wstring(cwd)))
@@ -469,21 +472,21 @@ bool restartAsAdmin()
return true;
}
-void startBinaryAdmin(const SpawnParameters& sp)
+void startBinaryAdmin(QWidget* parent, const SpawnParameters& sp)
{
- if (!dialogs::confirmRestartAsAdmin(sp)) {
+ if (!dialogs::confirmRestartAsAdmin(parent, sp)) {
log::debug("user declined");
return;
}
log::info("restarting MO as administrator");
- restartAsAdmin();
+ restartAsAdmin(parent);
}
bool checkBinary(QWidget* parent, const SpawnParameters& sp)
{
if (!sp.binary.exists()) {
- dialogs::spawnFailed(sp, ERROR_FILE_NOT_FOUND);
+ dialogs::spawnFailed(parent, sp, ERROR_FILE_NOT_FOUND);
return false;
}
@@ -660,7 +663,7 @@ bool checkSteam(
const auto c = dialogs::confirmRestartAsAdminForSteam(parent, sp);
if (c == QDialogButtonBox::Yes) {
- restartAsAdmin();
+ restartAsAdmin(parent);
return false;
} else if (c == QDialogButtonBox::No) {
log::debug("user declined to restart MO, continuing");
@@ -720,13 +723,13 @@ HANDLE startBinary(QWidget* parent, const SpawnParameters& sp)
case ERROR_ELEVATION_REQUIRED:
{
- startBinaryAdmin(sp);
+ startBinaryAdmin(parent, sp);
return INVALID_HANDLE_VALUE;
}
default:
{
- dialogs::spawnFailed(sp, e);
+ dialogs::spawnFailed(parent, sp, e);
return INVALID_HANDLE_VALUE;
}
}
@@ -740,6 +743,7 @@ namespace helper
{
bool helperExec(
+ QWidget* parent,
const std::wstring& moDirectory, const std::wstring& commandLine, BOOL async)
{
const std::wstring fileName = moDirectory + L"\\helper.exe";
@@ -766,7 +770,7 @@ bool helperExec(
const auto e = GetLastError();
spawn::dialogs::helperFailed(
- e, "ShellExecuteExW()", fileName, moDirectory, commandLine);
+ parent, e, "ShellExecuteExW()", fileName, moDirectory, commandLine);
return false;
}
@@ -788,7 +792,8 @@ bool helperExec(
ERROR_ABANDONED_WAIT_0 : GetLastError());
spawn::dialogs::helperFailed(
- code, "WaitForSingleObject()", fileName, moDirectory, commandLine);
+ parent, code, "WaitForSingleObject()",
+ fileName, moDirectory, commandLine);
return false;
}
@@ -798,7 +803,7 @@ bool helperExec(
const auto e = GetLastError();
spawn::dialogs::helperFailed(
- e, "GetExitCodeProcess()", fileName, moDirectory, commandLine);
+ parent, e, "GetExitCodeProcess()", fileName, moDirectory, commandLine);
return false;
}
@@ -806,21 +811,24 @@ bool helperExec(
return (exitCode == 0);
}
-bool backdateBSAs(const std::wstring &moPath, const std::wstring &dataPath)
+bool backdateBSAs(
+ QWidget* parent, const std::wstring &moPath, const std::wstring &dataPath)
{
const std::wstring commandLine = fmt::format(
L"backdateBSA \"{}\"", dataPath);
- return helperExec(moPath, commandLine, FALSE);
+ return helperExec(parent, moPath, commandLine, FALSE);
}
-bool adminLaunch(const std::wstring &moPath, const std::wstring &moFile, const std::wstring &workingDir)
+bool adminLaunch(
+ QWidget* parent, const std::wstring &moPath,
+ const std::wstring &moFile, const std::wstring &workingDir)
{
const std::wstring commandLine = fmt::format(
L"adminLaunch {} \"{}\" \"{}\"",
::GetCurrentProcessId(), moFile, workingDir);
- return helperExec(moPath, commandLine, true);
+ return helperExec(parent, moPath, commandLine, true);
}
} // namespace
diff --git a/src/spawn.h b/src/spawn.h
index da626329..9e1e2539 100644
--- a/src/spawn.h
+++ b/src/spawn.h
@@ -84,7 +84,8 @@ namespace helper
* @param moPath absolute path to the modOrganizer base directory
* @param dataPath the path taht contains the .bsa-files, usually the data directory of the game
**/
-bool backdateBSAs(const std::wstring &moPath, const std::wstring &dataPath);
+bool backdateBSAs(
+ QWidget* parent, const std::wstring &moPath, const std::wstring &dataPath);
/**
* @brief waits for the current process to exit and restarts it as an administrator
@@ -92,7 +93,9 @@ bool backdateBSAs(const std::wstring &moPath, const std::wstring &dataPath);
* @param moFile file name of modOrganizer
* @param workingDir current working directory
**/
-bool adminLaunch(const std::wstring &moPath, const std::wstring &moFile, const std::wstring &workingDir);
+bool adminLaunch(
+ QWidget* parent, const std::wstring &moPath,
+ const std::wstring &moFile, const std::wstring &workingDir);
} // namespace
--
cgit v1.3.1
From 54871e7b56a326f81e3de17f53604150d770793b Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Thu, 19 Sep 2019 17:14:09 -0400
Subject: added details to blacklist dialog
---
src/spawn.cpp | 15 ++++++++++-----
src/spawn.h | 2 +-
2 files changed, 11 insertions(+), 6 deletions(-)
(limited to 'src/spawn.h')
diff --git a/src/spawn.cpp b/src/spawn.cpp
index ab9d90a0..d2c8ddd5 100644
--- a/src/spawn.cpp
+++ b/src/spawn.cpp
@@ -384,7 +384,7 @@ bool eventLogNotRunning(
}
QMessageBox::StandardButton confirmBlacklisted(
- QWidget* parent, const SpawnParameters& sp)
+ QWidget* parent, const SpawnParameters& sp, Settings& settings)
{
const auto title = QObject::tr("Blacklisted program");
const auto mainText = QObject::tr("The program %1 is blacklisted")
@@ -394,10 +394,14 @@ QMessageBox::StandardButton confirmBlacklisted(
"filesystem. This will likely prevent it from seeing any mods, INI files "
"or any other virtualized files.");
+ const auto details =
+ "Executable: " + sp.binary.fileName() + "\n"
+ "Current blacklist: " + settings.executablesBlacklist();
+
auto r = MOBase::TaskDialog(parent, title)
.main(mainText)
.content(content)
- .details("")
+ .details(details)
.icon(QMessageBox::Question)
.remember("blacklistedExecutable", sp.binary.fileName())
.button({
@@ -413,7 +417,7 @@ QMessageBox::StandardButton confirmBlacklisted(
.exec();
if (r == QMessageBox::Retry) {
- if (!WorkaroundsSettingsTab::changeBlacklistNow(parent, Settings::instance())) {
+ if (!WorkaroundsSettingsTab::changeBlacklistNow(parent, settings)) {
r = QMessageBox::Cancel;
}
}
@@ -739,14 +743,15 @@ bool checkEnvironment(QWidget* parent, const SpawnParameters& sp)
return dialogs::eventLogNotRunning(parent, s, sp);
}
-bool checkBlacklist(QWidget* parent, const SpawnParameters& sp, const Settings& settings)
+bool checkBlacklist(
+ QWidget* parent, const SpawnParameters& sp, Settings& settings)
{
for (;;) {
if (!settings.isExecutableBlacklisted(sp.binary.fileName())) {
return true;
}
- const auto r = dialogs::confirmBlacklisted(parent, sp);
+ const auto r = dialogs::confirmBlacklisted(parent, sp, settings);
if (r != QMessageBox::Retry) {
return (r == QMessageBox::Yes);
diff --git a/src/spawn.h b/src/spawn.h
index 9e1e2539..31b44739 100644
--- a/src/spawn.h
+++ b/src/spawn.h
@@ -61,7 +61,7 @@ bool checkSteam(
bool checkEnvironment(QWidget* parent, const SpawnParameters& sp);
bool checkBlacklist(
- QWidget* parent, const SpawnParameters& sp, const Settings& settings);
+ QWidget* parent, const SpawnParameters& sp, Settings& settings);
/**
* @brief spawn a binary with Mod Organizer injected
--
cgit v1.3.1