/* 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 . */ #include "spawn.h" #include "report.h" #include "utility.h" #include #include #include #include #include using namespace MOBase; using namespace MOShared; bool spawn(LPCWSTR binary, LPCWSTR arguments, LPCWSTR currentDirectory, bool suspended, HANDLE& processHandle, HANDLE& threadHandle) { STARTUPINFO si; ::ZeroMemory(&si, sizeof(si)); 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); } PROCESS_INFORMATION pi; BOOL success = ::CreateProcess(NULL, commandLine, NULL, NULL, // no special process or thread attributes FALSE, // don't inherit handle 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 ); 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 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, processHandle, threadHandle)) { reportError(QObject::tr("failed to spawn \"%1\"").arg(binary.fileName())); return INVALID_HANDLE_VALUE; } } catch (const windows_error &e) { 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; }