diff options
| author | Tannin <devnull@localhost> | 2014-07-17 22:02:15 +0200 |
|---|---|---|
| committer | Tannin <devnull@localhost> | 2014-07-17 22:02:15 +0200 |
| commit | cc9827cdda5776a4fd540a2ab0fb8a08ec9f75a7 (patch) | |
| tree | 570a4a3bea9457d82de2cf44aa440e4a4cec4271 /src/spawn.cpp | |
| parent | 4e5a67fc063243c4c10e04b5f601108dd01357f3 (diff) | |
normalized eol style (all files should now have windows line endings)
Diffstat (limited to 'src/spawn.cpp')
| -rw-r--r-- | src/spawn.cpp | 390 |
1 files changed, 195 insertions, 195 deletions
diff --git a/src/spawn.cpp b/src/spawn.cpp index 6adafba0..1392ec88 100644 --- a/src/spawn.cpp +++ b/src/spawn.cpp @@ -1,195 +1,195 @@ -/* -Copyright (C) 2012 Sebastian Herbord. All rights reserved. - -This file is part of Mod Organizer. - -Mod Organizer is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Mod Organizer is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "spawn.h" -#include "report.h" -#include "utility.h" -#include <boost/scoped_array.hpp> -#include <gameinfo.h> -#include <inject.h> -#include <Shellapi.h> -#include <appconfig.h> -#include <windows_error.h> -#include <QApplication> -#include <QMessageBox> - - -using namespace MOBase; -using namespace MOShared; - - -static const int BUFSIZE = 4096; - -bool spawn(LPCWSTR binary, LPCWSTR arguments, LPCWSTR currentDirectory, bool suspended, - HANDLE stdOut, HANDLE stdErr, - HANDLE& processHandle, HANDLE& threadHandle) -{ - BOOL inheritHandles = FALSE; - STARTUPINFO si; - ::ZeroMemory(&si, sizeof(si)); - if (stdOut != INVALID_HANDLE_VALUE) { - si.hStdOutput = stdOut; - inheritHandles = TRUE; - si.dwFlags |= STARTF_USESTDHANDLES; - } - if (stdErr != INVALID_HANDLE_VALUE) { - si.hStdError = stdErr; - inheritHandles = TRUE; - si.dwFlags |= STARTF_USESTDHANDLES; - } - si.cb = sizeof(si); - int length = wcslen(binary) + wcslen(arguments) + 4; - wchar_t *commandLine = NULL; - if (arguments[0] != L'\0') { - commandLine = new wchar_t[length]; - _snwprintf(commandLine, length, L"\"%ls\" %ls", binary, arguments); - } else { - commandLine = new wchar_t[length]; - _snwprintf(commandLine, length, L"\"%ls\"", binary); - } - - QString moPath = QCoreApplication::applicationDirPath(); - - boost::scoped_array<TCHAR> oldPath(new TCHAR[BUFSIZE]); - DWORD offset = ::GetEnvironmentVariable(TEXT("PATH"), oldPath.get(), BUFSIZE); - if (offset > BUFSIZE) { - oldPath.reset(new TCHAR[offset]); - ::GetEnvironmentVariable(TEXT("PATH"), oldPath.get(), offset); - } - - { - boost::scoped_array<TCHAR> newPath(new TCHAR[offset + moPath.length() + 2]); - _tcsncpy(newPath.get(), oldPath.get(), offset - 1); - newPath.get()[offset - 1] = L'\0'; - _tcsncat(newPath.get(), TEXT(";"), 1); - _tcsncat(newPath.get(), ToWString(QDir::toNativeSeparators(moPath)).c_str(), moPath.length()); - - ::SetEnvironmentVariable(TEXT("PATH"), newPath.get()); - } - - PROCESS_INFORMATION pi; - BOOL success = ::CreateProcess(NULL, - commandLine, - NULL, NULL, // no special process or thread attributes - inheritHandles, // inherit handles if we plan to use stdout or stderr reroute - suspended ? CREATE_SUSPENDED : 0, // create suspended so I have time to inject the DLL - NULL, // same environment as parent - currentDirectory, // current directory - &si, &pi // startup and process information - ); - - ::SetEnvironmentVariable(TEXT("PATH"), oldPath.get()); - - delete [] commandLine; - - if (!success) { - throw windows_error("failed to start process"); - } - - processHandle = pi.hProcess; - threadHandle = pi.hThread; - return true; -} - - -HANDLE startBinary(const QFileInfo &binary, - const QString &arguments, - const QString& profileName, - int logLevel, - const QDir ¤tDirectory, - bool hooked, - HANDLE stdOut, - HANDLE stdErr) -{ - HANDLE processHandle, threadHandle; - std::wstring binaryName = ToWString(QDir::toNativeSeparators(binary.absoluteFilePath())); - std::wstring currentDirectoryName = ToWString(QDir::toNativeSeparators(currentDirectory.absolutePath())); - - try { - if (!spawn(binaryName.c_str(), ToWString(arguments).c_str(), currentDirectoryName.c_str(), hooked, - stdOut, stdErr, processHandle, threadHandle)) { - reportError(QObject::tr("failed to spawn \"%1\"").arg(binary.fileName())); - return INVALID_HANDLE_VALUE; - } - } 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(NULL, 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( - QDir::toNativeSeparators(binary.absoluteFilePath())), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - ::ShellExecuteW(NULL, L"runas", ToWString(QCoreApplication::applicationFilePath()).c_str(), - (std::wstring(L"\"") + binaryName + L"\" " + ToWString(arguments)).c_str(), currentDirectoryName.c_str(), SW_SHOWNORMAL); - return INVALID_HANDLE_VALUE; - } else { - return INVALID_HANDLE_VALUE; - } - } else { - reportError(QObject::tr("failed to spawn \"%1\": %2").arg(binary.fileName()).arg(e.what())); - return INVALID_HANDLE_VALUE; - } - } - - if (hooked) { - try { - QFileInfo dllInfo(QApplication::applicationDirPath() + "/" + ToQString(AppConfig::hookDLLName())); - if (!dllInfo.exists()) { - reportError(QObject::tr("\"%1\" doesn't exist").arg(dllInfo.fileName())); - return INVALID_HANDLE_VALUE; - } - injectDLL(processHandle, threadHandle, - QDir::toNativeSeparators(dllInfo.canonicalFilePath()).toLocal8Bit().constData(), - ToWString(profileName).c_str(), logLevel); - } catch (const windows_error& e) { - reportError(QObject::tr("failed to inject dll into \"%1\": %2").arg(binary.fileName()).arg(e.what())); - ::TerminateProcess(processHandle, 1); - return INVALID_HANDLE_VALUE; - } -#ifdef _DEBUG - reportError("ready?"); -#endif // DEBUG - if (::ResumeThread(threadHandle) == (DWORD)-1) { - reportError(QObject::tr("failed to run \"%1\"").arg(binary.fileName())); - return INVALID_HANDLE_VALUE; - } - } - return processHandle; -} - -/* -ExitProxy *ExitProxy::s_Instance = NULL; - -ExitProxy *ExitProxy::instance() -{ - if (s_Instance == NULL) { - s_Instance = new ExitProxy(); - } - return s_Instance; -} - -void ExitProxy::emitExit() -{ - emit exit(); -}*/ +/*
+Copyright (C) 2012 Sebastian Herbord. All rights reserved.
+
+This file is part of Mod Organizer.
+
+Mod Organizer is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Mod Organizer is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "spawn.h"
+#include "report.h"
+#include "utility.h"
+#include <boost/scoped_array.hpp>
+#include <gameinfo.h>
+#include <inject.h>
+#include <Shellapi.h>
+#include <appconfig.h>
+#include <windows_error.h>
+#include <QApplication>
+#include <QMessageBox>
+
+
+using namespace MOBase;
+using namespace MOShared;
+
+
+static const int BUFSIZE = 4096;
+
+bool spawn(LPCWSTR binary, LPCWSTR arguments, LPCWSTR currentDirectory, bool suspended,
+ HANDLE stdOut, HANDLE stdErr,
+ HANDLE& processHandle, HANDLE& threadHandle)
+{
+ BOOL inheritHandles = FALSE;
+ STARTUPINFO si;
+ ::ZeroMemory(&si, sizeof(si));
+ if (stdOut != INVALID_HANDLE_VALUE) {
+ si.hStdOutput = stdOut;
+ inheritHandles = TRUE;
+ si.dwFlags |= STARTF_USESTDHANDLES;
+ }
+ if (stdErr != INVALID_HANDLE_VALUE) {
+ si.hStdError = stdErr;
+ inheritHandles = TRUE;
+ si.dwFlags |= STARTF_USESTDHANDLES;
+ }
+ si.cb = sizeof(si);
+ int length = wcslen(binary) + wcslen(arguments) + 4;
+ wchar_t *commandLine = NULL;
+ if (arguments[0] != L'\0') {
+ commandLine = new wchar_t[length];
+ _snwprintf(commandLine, length, L"\"%ls\" %ls", binary, arguments);
+ } else {
+ commandLine = new wchar_t[length];
+ _snwprintf(commandLine, length, L"\"%ls\"", binary);
+ }
+
+ QString moPath = QCoreApplication::applicationDirPath();
+
+ boost::scoped_array<TCHAR> oldPath(new TCHAR[BUFSIZE]);
+ DWORD offset = ::GetEnvironmentVariable(TEXT("PATH"), oldPath.get(), BUFSIZE);
+ if (offset > BUFSIZE) {
+ oldPath.reset(new TCHAR[offset]);
+ ::GetEnvironmentVariable(TEXT("PATH"), oldPath.get(), offset);
+ }
+
+ {
+ boost::scoped_array<TCHAR> newPath(new TCHAR[offset + moPath.length() + 2]);
+ _tcsncpy(newPath.get(), oldPath.get(), offset - 1);
+ newPath.get()[offset - 1] = L'\0';
+ _tcsncat(newPath.get(), TEXT(";"), 1);
+ _tcsncat(newPath.get(), ToWString(QDir::toNativeSeparators(moPath)).c_str(), moPath.length());
+
+ ::SetEnvironmentVariable(TEXT("PATH"), newPath.get());
+ }
+
+ PROCESS_INFORMATION pi;
+ BOOL success = ::CreateProcess(NULL,
+ commandLine,
+ NULL, NULL, // no special process or thread attributes
+ inheritHandles, // inherit handles if we plan to use stdout or stderr reroute
+ suspended ? CREATE_SUSPENDED : 0, // create suspended so I have time to inject the DLL
+ NULL, // same environment as parent
+ currentDirectory, // current directory
+ &si, &pi // startup and process information
+ );
+
+ ::SetEnvironmentVariable(TEXT("PATH"), oldPath.get());
+
+ delete [] commandLine;
+
+ if (!success) {
+ throw windows_error("failed to start process");
+ }
+
+ processHandle = pi.hProcess;
+ threadHandle = pi.hThread;
+ return true;
+}
+
+
+HANDLE startBinary(const QFileInfo &binary,
+ const QString &arguments,
+ const QString& profileName,
+ int logLevel,
+ const QDir ¤tDirectory,
+ bool hooked,
+ HANDLE stdOut,
+ HANDLE stdErr)
+{
+ HANDLE processHandle, threadHandle;
+ std::wstring binaryName = ToWString(QDir::toNativeSeparators(binary.absoluteFilePath()));
+ std::wstring currentDirectoryName = ToWString(QDir::toNativeSeparators(currentDirectory.absolutePath()));
+
+ try {
+ if (!spawn(binaryName.c_str(), ToWString(arguments).c_str(), currentDirectoryName.c_str(), hooked,
+ stdOut, stdErr, processHandle, threadHandle)) {
+ reportError(QObject::tr("failed to spawn \"%1\"").arg(binary.fileName()));
+ return INVALID_HANDLE_VALUE;
+ }
+ } 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(NULL, 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(
+ QDir::toNativeSeparators(binary.absoluteFilePath())),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ ::ShellExecuteW(NULL, L"runas", ToWString(QCoreApplication::applicationFilePath()).c_str(),
+ (std::wstring(L"\"") + binaryName + L"\" " + ToWString(arguments)).c_str(), currentDirectoryName.c_str(), SW_SHOWNORMAL);
+ return INVALID_HANDLE_VALUE;
+ } else {
+ return INVALID_HANDLE_VALUE;
+ }
+ } else {
+ reportError(QObject::tr("failed to spawn \"%1\": %2").arg(binary.fileName()).arg(e.what()));
+ return INVALID_HANDLE_VALUE;
+ }
+ }
+
+ if (hooked) {
+ try {
+ QFileInfo dllInfo(QApplication::applicationDirPath() + "/" + ToQString(AppConfig::hookDLLName()));
+ if (!dllInfo.exists()) {
+ reportError(QObject::tr("\"%1\" doesn't exist").arg(dllInfo.fileName()));
+ return INVALID_HANDLE_VALUE;
+ }
+ injectDLL(processHandle, threadHandle,
+ QDir::toNativeSeparators(dllInfo.canonicalFilePath()).toLocal8Bit().constData(),
+ ToWString(profileName).c_str(), logLevel);
+ } catch (const windows_error& e) {
+ reportError(QObject::tr("failed to inject dll into \"%1\": %2").arg(binary.fileName()).arg(e.what()));
+ ::TerminateProcess(processHandle, 1);
+ return INVALID_HANDLE_VALUE;
+ }
+#ifdef _DEBUG
+ reportError("ready?");
+#endif // DEBUG
+ if (::ResumeThread(threadHandle) == (DWORD)-1) {
+ reportError(QObject::tr("failed to run \"%1\"").arg(binary.fileName()));
+ return INVALID_HANDLE_VALUE;
+ }
+ }
+ return processHandle;
+}
+
+/*
+ExitProxy *ExitProxy::s_Instance = NULL;
+
+ExitProxy *ExitProxy::instance()
+{
+ if (s_Instance == NULL) {
+ s_Instance = new ExitProxy();
+ }
+ return s_Instance;
+}
+
+void ExitProxy::emitExit()
+{
+ emit exit();
+}*/
|
