diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/helper.cpp | 34 | ||||
| -rw-r--r-- | src/helper.h | 12 | ||||
| -rw-r--r-- | src/spawn.cpp | 30 |
3 files changed, 59 insertions, 17 deletions
diff --git a/src/helper.cpp b/src/helper.cpp index b7fc866c..59a2d3d1 100644 --- a/src/helper.cpp +++ b/src/helper.cpp @@ -26,6 +26,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <Windows.h>
#include <QDir>
+#include <QApplication>
using MOBase::reportError;
@@ -33,7 +34,7 @@ using MOBase::reportError; namespace Helper {
-static bool helperExec(LPCWSTR moDirectory, LPCWSTR commandLine)
+static bool helperExec(LPCWSTR moDirectory, LPCWSTR commandLine, BOOL async)
{
wchar_t fileName[MAX_PATH];
_snwprintf(fileName, MAX_PATH, L"%ls\\helper.exe", moDirectory);
@@ -51,7 +52,16 @@ static bool helperExec(LPCWSTR moDirectory, LPCWSTR commandLine) ::ShellExecuteExW(&execInfo);
- if ((execInfo.hProcess == 0) || (::WaitForSingleObject(execInfo.hProcess, INFINITE) != WAIT_OBJECT_0)) {
+ 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;
}
@@ -76,7 +86,7 @@ bool init(const std::wstring &moPath, const std::wstring &dataPath) _snwprintf(commandLine, 32768, L"init \"%ls\" \"%ls\"",
dataPath.c_str(), userName);
- bool res = helperExec(moPath.c_str(), commandLine);
+ bool res = helperExec(moPath.c_str(), commandLine, FALSE);
delete [] commandLine;
return res;
@@ -89,7 +99,23 @@ bool backdateBSAs(const std::wstring &moPath, const std::wstring &dataPath) _snwprintf(commandLine, 32768, L"backdateBSA \"%ls\"",
dataPath.c_str());
- bool res = helperExec(moPath.c_str(), commandLine);
+ 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;
diff --git a/src/helper.h b/src/helper.h index cd4b7883..f6667a84 100644 --- a/src/helper.h +++ b/src/helper.h @@ -26,7 +26,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. /**
* @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
**/
@@ -34,7 +34,7 @@ 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
*
@@ -50,6 +50,14 @@ bool init(const std::wstring &moPath, const std::wstring &dataPath); **/
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);
+
}
diff --git a/src/spawn.cpp b/src/spawn.cpp index 6bb34aea..1459aadb 100644 --- a/src/spawn.cpp +++ b/src/spawn.cpp @@ -26,6 +26,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <Shellapi.h>
#include <appconfig.h>
#include <windows_error.h>
+#include "helper.h"
#include <QApplication>
#include <QMessageBox>
@@ -148,24 +149,31 @@ HANDLE startBinary(const QFileInfo &binary, }
} catch (const windows_error &e) {
if (e.getErrorCode() == ERROR_ELEVATION_REQUIRED) {
- // TODO: check if this is really correct. Are all settings updated that the secondary instance may use?
-
- if (QMessageBox::question(nullptr, QObject::tr("Elevation required"),
+ if (QMessageBox::question(QApplication::activeModalWidget(), QObject::tr("Elevation required"),
QObject::tr("This process requires elevation to run.\n"
"This is a potential security risk so I highly advice you to investigate if\n"
"\"%1\"\n"
"can be installed to work without elevation.\n\n"
- "Start elevated anyway? "
- "(you will be asked if you want to allow ModOrganizer.exe to make changes to the system)").arg(
+ "Restart Mod Organizer as an elevated process?\n"
+ "You will be asked if you want to allow helper.exe to make changes to the system."
+ "You will need to relaunch the process above manually.").arg(
QDir::toNativeSeparators(binary.absoluteFilePath())),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
- std::wstring parameters = ToWString("\"" + QDir::toNativeSeparators(binary.absoluteFilePath()) + "\" " + QString(arguments).replace("\"", "\\\""));
- ::ShellExecuteW(nullptr, L"runas", ToWString(QCoreApplication::applicationFilePath()).c_str(),
- parameters.c_str(), currentDirectoryName.c_str(), SW_SHOWNORMAL);
- return INVALID_HANDLE_VALUE;
- } else {
- return INVALID_HANDLE_VALUE;
+ WCHAR cwd[MAX_PATH];
+ if (!GetCurrentDirectory(MAX_PATH, cwd)) {
+ reportError(QObject::tr("failed to spawn \"%1\": %2").arg(binary.fileName()).arg(::GetLastError()));
+ cwd[0] = L'\0';
+ }
+ if (!Helper::adminLaunch(
+ qApp->applicationDirPath().toStdWString(),
+ qApp->applicationFilePath().toStdWString(),
+ std::wstring(cwd))) {
+ return INVALID_HANDLE_VALUE;
+ }
+ qApp->exit(0);
}
+ return INVALID_HANDLE_VALUE;
+
} else {
reportError(QObject::tr("failed to spawn \"%1\": %2").arg(binary.fileName()).arg(e.what()));
return INVALID_HANDLE_VALUE;
|
