summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLostDragonist <lost.dragonist@gmail.com>2019-02-19 03:24:52 -0600
committerLostDragonist <lost.dragonist@gmail.com>2019-02-19 03:26:08 -0600
commit9ec158dceea37c9d783a8439d3c1253186efbbda (patch)
tree1e66f6811d8ab6c94a93ff862481d5d80132f226
parent046a72346c82ac48f770ae6e015025f24d019460 (diff)
Fix for Steam being run as administrator
Previously, when Steam was run as administrator, MO couldn't access the process therefore couldn't detect it. Now, an alternative method for listing processes is now being used in order to determine if Steam is running. Additionally, MO will detect if Steam is admin and MO is not and prompt the user if they want to restart MO as admin.
-rw-r--r--src/organizercore.cpp143
-rw-r--r--src/organizercore.h2
2 files changed, 100 insertions, 45 deletions
diff --git a/src/organizercore.cpp b/src/organizercore.cpp
index bfe36b24..2f75439d 100644
--- a/src/organizercore.cpp
+++ b/src/organizercore.cpp
@@ -34,6 +34,7 @@
#include "lockeddialog.h"
#include "instancemanager.h"
#include <scriptextender.h>
+#include "helper.h"
#include <QApplication>
#include <QCoreApplication>
@@ -438,58 +439,65 @@ void OrganizerCore::storeSettings()
}
}
-bool OrganizerCore::testForSteam()
+bool OrganizerCore::testForSteam(bool *found, bool *access)
{
- size_t currentSize = 1024;
- std::unique_ptr<DWORD[]> processIDs;
- DWORD bytesReturned;
- bool success = false;
- while (!success) {
- processIDs.reset(new DWORD[currentSize]);
- if (!::EnumProcesses(processIDs.get(),
- static_cast<DWORD>(currentSize) * sizeof(DWORD),
- &bytesReturned)) {
- qWarning("failed to determine if steam is running");
- return true;
- }
- if (bytesReturned == (currentSize * sizeof(DWORD))) {
- // maximum size used, list probably truncated
- currentSize *= 2;
- } else {
- success = true;
- }
+ HANDLE hProcessSnap;
+ HANDLE hProcess;
+ PROCESSENTRY32 pe32;
+ DWORD lastError;
+
+ if (found == nullptr || access == nullptr) {
+ return false;
}
- TCHAR processName[MAX_PATH];
- for (unsigned int i = 0; i < bytesReturned / sizeof(DWORD); ++i) {
- memset(processName, '\0', sizeof(TCHAR) * MAX_PATH);
- if (processIDs[i] != 0) {
- HANDLE process = ::OpenProcess(
- PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processIDs[i]);
- if (process != nullptr) {
+ // Take a snapshot of all processes in the system.
+ hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (hProcessSnap == INVALID_HANDLE_VALUE) {
+ lastError = GetLastError();
+ qCritical("unable to get snapshot of processes (error %d)", lastError);
+ return false;
+ }
- ON_BLOCK_EXIT([&]() {
- if (process != INVALID_HANDLE_VALUE)
- ::CloseHandle(process);
- });
+ // Retrieve information about the first process,
+ // and exit if unsuccessful
+ pe32.dwSize = sizeof(PROCESSENTRY32);
+ if (!Process32First(hProcessSnap, &pe32)) {
+ lastError = GetLastError();
+ qCritical("unable to get first process (error %d)", lastError);
+ CloseHandle(hProcessSnap);
+ return false;
+ }
- HMODULE module;
- DWORD ignore;
+ *found = false;
+ *access = true;
- // first module in a process is always the binary
- if (EnumProcessModules(process, &module, sizeof(HMODULE) * 1,
- &ignore)) {
- ::GetModuleBaseName(process, module, processName, MAX_PATH);
- if ((_tcsicmp(processName, TEXT("steam.exe")) == 0)
- || (_tcsicmp(processName, TEXT("steamservice.exe")) == 0)) {
- return 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;
}
- }
- return false;
+} while(Process32Next(hProcessSnap, &pe32));
+
+CloseHandle(hProcessSnap);
+return true;
+
}
void OrganizerCore::updateExecutablesList(QSettings &settings)
@@ -1316,7 +1324,14 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary,
"steam_api64.dll"))
.exists())
&& (m_Settings.getLoadMechanism() == LoadMechanism::LOAD_MODORGANIZER)) {
- if (!testForSteam()) {
+
+ bool steamFound = true;
+ bool steamAccess = true;
+ if (!testForSteam(&steamFound, &steamAccess)) {
+ qCritical("unable to determine state of Steam");
+ }
+
+ if (!steamFound) {
QDialogButtonBox::StandardButton result;
result = QuestionBoxMemory::query(window, "steamQuery", binary.fileName(),
tr("Start Steam?"),
@@ -1325,7 +1340,47 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary,
QDialogButtonBox::Yes | QDialogButtonBox::No | QDialogButtonBox::Cancel);
if (result == QDialogButtonBox::Yes) {
startSteam(window);
- } else if(result == QDialogButtonBox::Cancel) {
+
+ // double-check that Steam is started and MO has access
+ steamFound = true;
+ steamAccess = true;
+ if (!testForSteam(&steamFound, &steamAccess)) {
+ qCritical("unable to determine state of Steam");
+ } else if (!steamFound) {
+ qCritical("could not find Steam");
+ }
+
+ } else if (result == QDialogButtonBox::Cancel) {
+ 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 neccessary.\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)) {
+ qCritical("unable to get current directory (error %d)", GetLastError());
+ cwd[0] = L'\0';
+ }
+ if (!Helper::adminLaunch(
+ qApp->applicationDirPath().toStdWString(),
+ qApp->applicationFilePath().toStdWString(),
+ std::wstring(cwd))) {
+ qCritical("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;
}
}
diff --git a/src/organizercore.h b/src/organizercore.h
index 0a4cff6c..2757aaf3 100644
--- a/src/organizercore.h
+++ b/src/organizercore.h
@@ -272,7 +272,7 @@ private:
void updateModActiveState(int index, bool active);
void updateModsActiveState(const QList<unsigned int> &modIndices, bool active);
- bool testForSteam();
+ bool testForSteam(bool *found, bool *access);
bool createDirectory(const QString &path);