diff options
| author | Brian Munro <brian.alexander.munro@gmail.com> | 2018-02-22 18:02:02 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-02-22 18:02:02 +0200 |
| commit | 28714f0eb800f2170acbf29dddce1582d20d6b8b (patch) | |
| tree | 0684c123db375336e0e03f0240155a12e744db16 /src/main.cpp | |
| parent | 0bcd752b2758bdb072b498ccc90905276be065e9 (diff) | |
| parent | 5e5c9c07291f6b09623d31c92b1fb61c4ede576e (diff) | |
Merge pull request #236 from SuperSandro2000/new_vfs_library
Update reame.md
Diffstat (limited to 'src/main.cpp')
| -rw-r--r-- | src/main.cpp | 1000 |
1 files changed, 480 insertions, 520 deletions
diff --git a/src/main.cpp b/src/main.cpp index 935b7404..bc1b4bc5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,60 +17,58 @@ You should have received a copy of the GNU General Public License along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
-
#ifdef LEAK_CHECK_WITH_VLD
-#include <wchar.h>
#include <vld.h>
+#include <wchar.h>
#endif // LEAK_CHECK_WITH_VLD
#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
#include <DbgHelp.h>
+#include <windows.h>
-#include <appconfig.h>
-#include <utility.h>
-#include <scopeguard.h>
-#include "mainwindow.h"
-#include <report.h>
-#include "modlist.h"
-#include "profile.h"
-#include "spawn.h"
#include "executableslist.h"
-#include "singleinstance.h"
-#include "utility.h"
#include "helper.h"
+#include "instancemanager.h"
#include "logbuffer.h"
-#include "selectiondialog.h"
+#include "mainwindow.h"
#include "moapplication.h"
-#include "tutorialmanager.h"
-#include "nxmaccessmanager.h"
-#include "instancemanager.h"
+#include "modlist.h"
#include "moshortcut.h"
+#include "nxmaccessmanager.h"
+#include "profile.h"
+#include "selectiondialog.h"
+#include "singleinstance.h"
+#include "spawn.h"
+#include "tutorialmanager.h"
+#include "utility.h"
+#include <appconfig.h>
+#include <report.h>
+#include <scopeguard.h>
+#include <utility.h>
#include <eh.h>
-#include <windows_error.h>
#include <usvfs.h>
+#include <windows_error.h>
#include <QApplication>
-#include <QPushButton>
-#include <QListWidget>
-#include <QComboBox>
+#include <QBuffer>
#include <QCheckBox>
+#include <QComboBox>
+#include <QDesktopServices>
#include <QDir>
-#include <QFileInfo>
-#include <QSettings>
-#include <QWhatsThis>
-#include <QToolBar>
+#include <QDirIterator>
#include <QFileDialog>
-#include <QDesktopServices>
+#include <QFileInfo>
+#include <QLibraryInfo>
+#include <QListWidget>
#include <QMessageBox>
+#include <QPushButton>
+#include <QSettings>
#include <QSharedMemory>
-#include <QBuffer>
#include <QSplashScreen>
-#include <QDirIterator>
-#include <QDesktopServices>
-#include <QLibraryInfo>
#include <QSslSocket>
+#include <QToolBar>
+#include <QWhatsThis>
#include <boost/scoped_array.hpp>
@@ -81,629 +79,591 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <sstream>
#include <stdexcept>
-
-#pragma comment(linker, "/manifestDependency:\"name='dlls' processorArchitecture='x86' version='1.0.0.0' type='win32' \"")
-
+#pragma comment(linker, \
+ "/manifestDependency:\"name='dlls' processorArchitecture='x86' version='1.0.0.0' type='win32' \"")
using namespace MOBase;
using namespace MOShared;
-bool createAndMakeWritable(const std::wstring &subPath) {
- QString const dataPath = qApp->property("dataPath").toString();
- QString fullPath = dataPath + "/" + QString::fromStdWString(subPath);
+bool createAndMakeWritable(const std::wstring& subPath) {
+ QString const dataPath = qApp->property("dataPath").toString();
+ QString fullPath = dataPath + "/" + QString::fromStdWString(subPath);
- if (!QDir(fullPath).exists() && !QDir().mkdir(fullPath)) {
- QMessageBox::critical(nullptr, QObject::tr("Error"),
- QObject::tr("Failed to create \"%1\". Your user "
- "account probably lacks permission.")
- .arg(fullPath));
- return false;
- } else {
- return true;
- }
+ if (!QDir(fullPath).exists() && !QDir().mkdir(fullPath)) {
+ QMessageBox::critical(nullptr, QObject::tr("Error"),
+ QObject::tr("Failed to create \"%1\". Your user "
+ "account probably lacks permission.")
+ .arg(fullPath));
+ return false;
+ } else {
+ return true;
+ }
}
-bool bootstrap()
-{
- // remove the temporary backup directory in case we're restarting after an update
- QString backupDirectory = qApp->applicationDirPath() + "/update_backup";
- if (QDir(backupDirectory).exists()) {
- shellDelete(QStringList(backupDirectory));
- }
+bool bootstrap() {
+ // remove the temporary backup directory in case we're restarting after an update
+ QString backupDirectory = qApp->applicationDirPath() + "/update_backup";
+ if (QDir(backupDirectory).exists()) {
+ shellDelete(QStringList(backupDirectory));
+ }
- // cycle logfile
- removeOldFiles(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath()),
- "usvfs*.log", 5, QDir::Name);
+ // cycle logfile
+ removeOldFiles(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath()),
+ "usvfs*.log", 5, QDir::Name);
- if (!createAndMakeWritable(AppConfig::logPath())) {
- return false;
- }
+ if (!createAndMakeWritable(AppConfig::logPath())) {
+ return false;
+ }
- return true;
+ return true;
}
LPTOP_LEVEL_EXCEPTION_FILTER prevUnhandledExceptionFilter = nullptr;
-static LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionPtrs)
-{
- const std::wstring& dumpPath = OrganizerCore::crashDumpsPath();
- int dumpRes =
- CreateMiniDump(exceptionPtrs, OrganizerCore::getGlobalCrashDumpsType(), dumpPath.c_str());
- if (!dumpRes)
- qCritical("ModOrganizer has crashed, crash dump created.");
- else
- qCritical("ModOrganizer has crashed, CreateMiniDump failed (%d, error %lu).", dumpRes, GetLastError());
+static LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS* exceptionPtrs) {
+ const std::wstring& dumpPath = OrganizerCore::crashDumpsPath();
+ int dumpRes = CreateMiniDump(exceptionPtrs, OrganizerCore::getGlobalCrashDumpsType(), dumpPath.c_str());
+ if (!dumpRes)
+ qCritical("ModOrganizer has crashed, crash dump created.");
+ else
+ qCritical("ModOrganizer has crashed, CreateMiniDump failed (%d, error %lu).", dumpRes, GetLastError());
- if (prevUnhandledExceptionFilter)
- return prevUnhandledExceptionFilter(exceptionPtrs);
- else
- return EXCEPTION_CONTINUE_SEARCH;
+ if (prevUnhandledExceptionFilter)
+ return prevUnhandledExceptionFilter(exceptionPtrs);
+ else
+ return EXCEPTION_CONTINUE_SEARCH;
}
// Parses the first parseArgCount arguments of the current process command line and returns
// them in parsedArgs, the rest of the command line is returned untouched.
-LPCWSTR UntouchedCommandLineArguments(int parseArgCount, std::vector<std::wstring>& parsedArgs)
-{
- LPCWSTR cmd = GetCommandLineW();
- LPCWSTR arg = nullptr; // to skip executable name
- for (; parseArgCount >= 0 && *cmd; ++cmd)
- {
- if (*cmd == '"') {
- int escaped = 0;
- for (++cmd; *cmd && (*cmd != '"' || escaped % 2 != 0); ++cmd)
- escaped = *cmd == '\\' ? escaped + 1 : 0;
- }
- if (*cmd == ' ') {
- if (arg)
- if (cmd-1 > arg && *arg == '"' && *(cmd-1) == '"')
- parsedArgs.push_back(std::wstring(arg+1, cmd-1));
- else
- parsedArgs.push_back(std::wstring(arg, cmd));
- arg = cmd + 1;
- --parseArgCount;
+LPCWSTR UntouchedCommandLineArguments(int parseArgCount, std::vector<std::wstring>& parsedArgs) {
+ LPCWSTR cmd = GetCommandLineW();
+ LPCWSTR arg = nullptr; // to skip executable name
+ for (; parseArgCount >= 0 && *cmd; ++cmd) {
+ if (*cmd == '"') {
+ int escaped = 0;
+ for (++cmd; *cmd && (*cmd != '"' || escaped % 2 != 0); ++cmd)
+ escaped = *cmd == '\\' ? escaped + 1 : 0;
+ }
+ if (*cmd == ' ') {
+ if (arg)
+ if (cmd - 1 > arg && *arg == '"' && *(cmd - 1) == '"')
+ parsedArgs.push_back(std::wstring(arg + 1, cmd - 1));
+ else
+ parsedArgs.push_back(std::wstring(arg, cmd));
+ arg = cmd + 1;
+ --parseArgCount;
+ }
}
- }
- return cmd;
+ return cmd;
}
static int SpawnWaitProcess(LPCWSTR workingDirectory, LPCWSTR commandLine) {
- PROCESS_INFORMATION pi{ 0 };
- STARTUPINFO si{ 0 };
- si.cb = sizeof(si);
- std::wstring commandLineCopy = commandLine;
+ PROCESS_INFORMATION pi{0};
+ STARTUPINFO si{0};
+ si.cb = sizeof(si);
+ std::wstring commandLineCopy = commandLine;
- if (!CreateProcessW(NULL, &commandLineCopy[0], NULL, NULL, FALSE, 0, NULL, workingDirectory, &si, &pi)) {
- // A bit of a problem where to log the error message here, at least this way you can get the message
- // using a either DebugView or a live debugger:
- std::wostringstream ost;
- ost << L"CreateProcess failed: " << commandLine << ", " << GetLastError();
- OutputDebugStringW(ost.str().c_str());
- return -1;
- }
+ if (!CreateProcessW(NULL, &commandLineCopy[0], NULL, NULL, FALSE, 0, NULL, workingDirectory, &si, &pi)) {
+ // A bit of a problem where to log the error message here, at least this way you can get the message
+ // using a either DebugView or a live debugger:
+ std::wostringstream ost;
+ ost << L"CreateProcess failed: " << commandLine << ", " << GetLastError();
+ OutputDebugStringW(ost.str().c_str());
+ return -1;
+ }
- WaitForSingleObject(pi.hProcess, INFINITE);
+ WaitForSingleObject(pi.hProcess, INFINITE);
- DWORD exitCode = (DWORD)-1;
- ::GetExitCodeProcess(pi.hProcess, &exitCode);
- CloseHandle(pi.hThread);
- CloseHandle(pi.hProcess);
- return static_cast<int>(exitCode);
+ DWORD exitCode = (DWORD)-1;
+ ::GetExitCodeProcess(pi.hProcess, &exitCode);
+ CloseHandle(pi.hThread);
+ CloseHandle(pi.hProcess);
+ return static_cast<int>(exitCode);
}
-static DWORD WaitForProcess() {
+static DWORD WaitForProcess() {}
-}
+static bool HaveWriteAccess(const std::wstring& path) {
+ bool writable = false;
-static bool HaveWriteAccess(const std::wstring &path)
-{
- bool writable = false;
+ const static SECURITY_INFORMATION requestedFileInformation =
+ OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
- const static SECURITY_INFORMATION requestedFileInformation = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
+ DWORD length = 0;
+ if (!::GetFileSecurityW(path.c_str(), requestedFileInformation, nullptr, 0UL, &length) &&
+ (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
+ std::string tempBuffer;
+ tempBuffer.reserve(length);
+ PSECURITY_DESCRIPTOR security = (PSECURITY_DESCRIPTOR)tempBuffer.data();
+ if (security && ::GetFileSecurity(path.c_str(), requestedFileInformation, security, length, &length)) {
+ HANDLE token = nullptr;
+ const static DWORD tokenDesiredAccess =
+ TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_DUPLICATE | STANDARD_RIGHTS_READ;
+ if (!::OpenThreadToken(::GetCurrentThread(), tokenDesiredAccess, TRUE, &token)) {
+ if (!::OpenProcessToken(::GetCurrentProcess(), tokenDesiredAccess, &token)) {
+ throw std::runtime_error("Unable to get any thread or process token");
+ }
+ }
- DWORD length = 0;
- if (!::GetFileSecurityW(path.c_str(), requestedFileInformation, nullptr, 0UL, &length)
- && (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
- std::string tempBuffer;
- tempBuffer.reserve(length);
- PSECURITY_DESCRIPTOR security = (PSECURITY_DESCRIPTOR)tempBuffer.data();
- if (security
- && ::GetFileSecurity(path.c_str(), requestedFileInformation, security, length, &length)) {
- HANDLE token = nullptr;
- const static DWORD tokenDesiredAccess = TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_DUPLICATE | STANDARD_RIGHTS_READ;
- if (!::OpenThreadToken(::GetCurrentThread(), tokenDesiredAccess, TRUE, &token)) {
- if (!::OpenProcessToken(::GetCurrentProcess(), tokenDesiredAccess, &token)) {
- throw std::runtime_error("Unable to get any thread or process token");
- }
- }
+ HANDLE impersonatedToken = nullptr;
+ if (::DuplicateToken(token, SecurityImpersonation, &impersonatedToken)) {
+ GENERIC_MAPPING mapping = {0xFFFFFFFF};
+ mapping.GenericRead = FILE_GENERIC_READ;
+ mapping.GenericWrite = FILE_GENERIC_WRITE;
+ mapping.GenericExecute = FILE_GENERIC_EXECUTE;
+ mapping.GenericAll = FILE_ALL_ACCESS;
- HANDLE impersonatedToken = nullptr;
- if (::DuplicateToken(token, SecurityImpersonation, &impersonatedToken)) {
- GENERIC_MAPPING mapping = { 0xFFFFFFFF };
- mapping.GenericRead = FILE_GENERIC_READ;
- mapping.GenericWrite = FILE_GENERIC_WRITE;
- mapping.GenericExecute = FILE_GENERIC_EXECUTE;
- mapping.GenericAll = FILE_ALL_ACCESS;
+ DWORD genericAccessRights = FILE_GENERIC_WRITE;
+ ::MapGenericMask(&genericAccessRights, &mapping);
- DWORD genericAccessRights = FILE_GENERIC_WRITE;
- ::MapGenericMask(&genericAccessRights, &mapping);
+ PRIVILEGE_SET privileges = {0};
+ DWORD grantedAccess = 0;
+ DWORD privilegesLength = sizeof(privileges);
+ BOOL result = 0;
+ if (::AccessCheck(security, impersonatedToken, genericAccessRights, &mapping, &privileges,
+ &privilegesLength, &grantedAccess, &result)) {
+ writable = result != 0;
+ }
+ ::CloseHandle(impersonatedToken);
+ }
- PRIVILEGE_SET privileges = { 0 };
- DWORD grantedAccess = 0;
- DWORD privilegesLength = sizeof(privileges);
- BOOL result = 0;
- if (::AccessCheck(security, impersonatedToken, genericAccessRights, &mapping, &privileges, &privilegesLength, &grantedAccess, &result)) {
- writable = result != 0;
+ ::CloseHandle(token);
}
- ::CloseHandle(impersonatedToken);
- }
-
- ::CloseHandle(token);
}
- }
- return writable;
+ return writable;
}
-
-QString determineProfile(QStringList &arguments, const QSettings &settings)
-{
- QString selectedProfileName = QString::fromUtf8(settings.value("selected_profile", "").toByteArray());
- { // see if there is a profile on the command line
- int profileIndex = arguments.indexOf("-p", 1);
- if ((profileIndex != -1) && (profileIndex < arguments.size() - 1)) {
- qDebug("profile overwritten on command line");
- selectedProfileName = arguments.at(profileIndex + 1);
+QString determineProfile(QStringList& arguments, const QSettings& settings) {
+ QString selectedProfileName = QString::fromUtf8(settings.value("selected_profile", "").toByteArray());
+ { // see if there is a profile on the command line
+ int profileIndex = arguments.indexOf("-p", 1);
+ if ((profileIndex != -1) && (profileIndex < arguments.size() - 1)) {
+ qDebug("profile overwritten on command line");
+ selectedProfileName = arguments.at(profileIndex + 1);
+ }
+ arguments.removeAt(profileIndex);
+ arguments.removeAt(profileIndex);
+ }
+ if (selectedProfileName.isEmpty()) {
+ qDebug("no configured profile");
+ selectedProfileName = "Default";
+ } else {
+ qDebug("configured profile: %s", qPrintable(selectedProfileName));
}
- arguments.removeAt(profileIndex);
- arguments.removeAt(profileIndex);
- }
- if (selectedProfileName.isEmpty()) {
- qDebug("no configured profile");
- selectedProfileName = "Default";
- } else {
- qDebug("configured profile: %s", qPrintable(selectedProfileName));
- }
- return selectedProfileName;
+ return selectedProfileName;
}
-MOBase::IPluginGame *selectGame(QSettings &settings, QDir const &gamePath, MOBase::IPluginGame *game)
-{
- settings.setValue("gameName", game->gameName());
- //Sadly, hookdll needs gamePath in order to run. So following code block is
- //commented out
- /*if (gamePath == game->gameDirectory()) {
+MOBase::IPluginGame* selectGame(QSettings& settings, QDir const& gamePath, MOBase::IPluginGame* game) {
+ settings.setValue("gameName", game->gameName());
+ // Sadly, hookdll needs gamePath in order to run. So following code block is
+ // commented out
+ /*if (gamePath == game->gameDirectory()) {
settings.remove("gamePath");
} else*/ {
- QString gameDir = gamePath.absolutePath();
- game->setGamePath(gameDir);
- settings.setValue("gamePath", QDir::toNativeSeparators(gameDir).toUtf8().constData());
- }
- return game; //Woot
+ QString gameDir = gamePath.absolutePath();
+ game->setGamePath(gameDir);
+ settings.setValue("gamePath", QDir::toNativeSeparators(gameDir).toUtf8().constData());
+ }
+ return game; // Woot
}
-
-MOBase::IPluginGame *determineCurrentGame(QString const &moPath, QSettings &settings, PluginContainer const &plugins)
-{
- //Determine what game we are running where. Be very paranoid in case the
- //user has done something odd.
- //If the game name has been set up, use that.
- QString gameName = settings.value("gameName", "").toString();
- if (!gameName.isEmpty()) {
- MOBase::IPluginGame *game = plugins.managedGame(gameName);
- if (game == nullptr) {
- reportError(QObject::tr("Plugin to handle %1 no longer installed").arg(gameName));
- return nullptr;
+MOBase::IPluginGame* determineCurrentGame(QString const& moPath, QSettings& settings, PluginContainer const& plugins) {
+ // Determine what game we are running where. Be very paranoid in case the
+ // user has done something odd.
+ // If the game name has been set up, use that.
+ QString gameName = settings.value("gameName", "").toString();
+ if (!gameName.isEmpty()) {
+ MOBase::IPluginGame* game = plugins.managedGame(gameName);
+ if (game == nullptr) {
+ reportError(QObject::tr("Plugin to handle %1 no longer installed").arg(gameName));
+ return nullptr;
+ }
+ QString gamePath = QString::fromUtf8(settings.value("gamePath", "").toByteArray());
+ if (gamePath == "") {
+ gamePath = game->gameDirectory().absolutePath();
+ }
+ QDir gameDir(gamePath);
+ if (game->looksValid(gameDir)) {
+ return selectGame(settings, gameDir, game);
+ }
}
+
+ // gameName wasn't set, or otherwise can't be found. Try looking through all
+ // the plugins using the gamePath
QString gamePath = QString::fromUtf8(settings.value("gamePath", "").toByteArray());
- if (gamePath == "") {
- gamePath = game->gameDirectory().absolutePath();
- }
- QDir gameDir(gamePath);
- if (game->looksValid(gameDir)) {
- return selectGame(settings, gameDir, game);
+ if (!gamePath.isEmpty()) {
+ QDir gameDir(gamePath);
+ // Look to see if one of the installed games binary file exists in the current
+ // game directory.
+ for (IPluginGame* const game : plugins.plugins<IPluginGame>()) {
+ if (game->looksValid(gameDir)) {
+ return selectGame(settings, gameDir, game);
+ }
+ }
}
- }
- //gameName wasn't set, or otherwise can't be found. Try looking through all
- //the plugins using the gamePath
- QString gamePath = QString::fromUtf8(settings.value("gamePath", "").toByteArray());
- if (!gamePath.isEmpty()) {
- QDir gameDir(gamePath);
- //Look to see if one of the installed games binary file exists in the current
- //game directory.
+ // The following code would try to determine the right game to mange but it would usually find the wrong one
+ // so it was commented out.
+ /*
+ //OK, we are in a new setup or existing info is useless.
+ //See if MO has been installed inside a game directory
for (IPluginGame * const game : plugins.plugins<IPluginGame>()) {
- if (game->looksValid(gameDir)) {
- return selectGame(settings, gameDir, game);
+ if (game->isInstalled() && moPath.startsWith(game->gameDirectory().absolutePath())) {
+ //Found it.
+ return selectGame(settings, game->gameDirectory(), game);
}
}
- }
-
- //The following code would try to determine the right game to mange but it would usually find the wrong one
- //so it was commented out.
- /*
- //OK, we are in a new setup or existing info is useless.
- //See if MO has been installed inside a game directory
- for (IPluginGame * const game : plugins.plugins<IPluginGame>()) {
- if (game->isInstalled() && moPath.startsWith(game->gameDirectory().absolutePath())) {
- //Found it.
- return selectGame(settings, game->gameDirectory(), game);
- }
- }
- //Try walking up the directory tree to see if MO has been installed inside a game
- {
- QDir gameDir(moPath);
- do {
- //Look to see if one of the installed games binary file exists in the current
- //directory.
- for (IPluginGame * const game : plugins.plugins<IPluginGame>()) {
- if (game->looksValid(gameDir)) {
- return selectGame(settings, gameDir, game);
+ //Try walking up the directory tree to see if MO has been installed inside a game
+ {
+ QDir gameDir(moPath);
+ do {
+ //Look to see if one of the installed games binary file exists in the current
+ //directory.
+ for (IPluginGame * const game : plugins.plugins<IPluginGame>()) {
+ if (game->looksValid(gameDir)) {
+ return selectGame(settings, gameDir, game);
+ }
}
- }
- //OK, chop off the last directory and try again
- } while (gameDir.cdUp());
- }
- */
+ //OK, chop off the last directory and try again
+ } while (gameDir.cdUp());
+ }
+ */
- //Then try a selection dialogue.
- if (!gamePath.isEmpty() || !gameName.isEmpty()) {
- reportError(QObject::tr("Could not use configuration settings for game \"%1\", path \"%2\".").
- arg(gameName).arg(gamePath));
- }
+ // Then try a selection dialogue.
+ if (!gamePath.isEmpty() || !gameName.isEmpty()) {
+ reportError(QObject::tr("Could not use configuration settings for game \"%1\", path \"%2\".")
+ .arg(gameName)
+ .arg(gamePath));
+ }
- SelectionDialog selection(QObject::tr("Please select the game to manage"), nullptr, QSize(32, 32));
+ SelectionDialog selection(QObject::tr("Please select the game to manage"), nullptr, QSize(32, 32));
- for (IPluginGame *game : plugins.plugins<IPluginGame>()) {
- if (game->isInstalled()) {
- QString path = game->gameDirectory().absolutePath();
- selection.addChoice(game->gameIcon(), game->gameName(), path, QVariant::fromValue(game));
+ for (IPluginGame* game : plugins.plugins<IPluginGame>()) {
+ if (game->isInstalled()) {
+ QString path = game->gameDirectory().absolutePath();
+ selection.addChoice(game->gameIcon(), game->gameName(), path, QVariant::fromValue(game));
+ }
}
- }
- selection.addChoice(QString("Browse..."), QString(), QVariant::fromValue(static_cast<IPluginGame *>(nullptr)));
+ selection.addChoice(QString("Browse..."), QString(), QVariant::fromValue(static_cast<IPluginGame*>(nullptr)));
- while (selection.exec() != QDialog::Rejected) {
- IPluginGame * game = selection.getChoiceData().value<IPluginGame *>();
- if (game != nullptr) {
- return selectGame(settings, game->gameDirectory(), game);
- }
+ while (selection.exec() != QDialog::Rejected) {
+ IPluginGame* game = selection.getChoiceData().value<IPluginGame*>();
+ if (game != nullptr) {
+ return selectGame(settings, game->gameDirectory(), game);
+ }
- gamePath = QFileDialog::getExistingDirectory(
- nullptr, QObject::tr("Please select the game to manage"), QString(),
- QFileDialog::ShowDirsOnly);
+ gamePath = QFileDialog::getExistingDirectory(nullptr, QObject::tr("Please select the game to manage"),
+ QString(), QFileDialog::ShowDirsOnly);
- if (!gamePath.isEmpty()) {
- QDir gameDir(gamePath);
- for (IPluginGame * const game : plugins.plugins<IPluginGame>()) {
- if (game->looksValid(gameDir)) {
- return selectGame(settings, gameDir, game);
+ if (!gamePath.isEmpty()) {
+ QDir gameDir(gamePath);
+ for (IPluginGame* const game : plugins.plugins<IPluginGame>()) {
+ if (game->looksValid(gameDir)) {
+ return selectGame(settings, gameDir, game);
+ }
+ }
+ reportError(QObject::tr("No game identified in \"%1\". The directory is required to contain "
+ "the game binary and its launcher.")
+ .arg(gamePath));
}
- }
- reportError(QObject::tr("No game identified in \"%1\". The directory is required to contain "
- "the game binary and its launcher.").arg(gamePath));
}
- }
- return nullptr;
+ return nullptr;
}
-
// extend path to include dll directory so plugins don't need a manifest
// (using AddDllDirectory would be an alternative to this but it seems fairly
// complicated esp.
// since it isn't easily accessible on Windows < 8
// SetDllDirectory replaces other search directories and this seems to
// propagate to child processes)
-void setupPath()
-{
- static const int BUFSIZE = 4096;
+void setupPath() {
+ static const int BUFSIZE = 4096;
- qDebug("MO at: %s", qPrintable(QDir::toNativeSeparators(
- QCoreApplication::applicationDirPath())));
+ qDebug("MO at: %s", qPrintable(QDir::toNativeSeparators(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> 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);
+ }
- std::wstring newPath(oldPath.get());
- newPath += L";";
- newPath += ToWString(QDir::toNativeSeparators(
- QCoreApplication::applicationDirPath()))
- .c_str();
- newPath += L"\\dlls";
+ std::wstring newPath(oldPath.get());
+ newPath += L";";
+ newPath += ToWString(QDir::toNativeSeparators(QCoreApplication::applicationDirPath())).c_str();
+ newPath += L"\\dlls";
- ::SetEnvironmentVariableW(L"PATH", newPath.c_str());
+ ::SetEnvironmentVariableW(L"PATH", newPath.c_str());
}
-static void preloadSsl()
-{
- QString appPath = QDir::toNativeSeparators(QCoreApplication::applicationDirPath());
- if (GetModuleHandleA("libeay32.dll"))
- qWarning("libeay32.dll already loaded?!");
- else {
- QString libeay32 = appPath + "\\libeay32.dll";
- if (!QFile::exists(libeay32))
- qWarning("libeay32.dll not found: %s", qPrintable(libeay32));
- else if (!LoadLibraryW(libeay32.toStdWString().c_str()))
- qWarning("failed to load: %s, %d", qPrintable(libeay32), GetLastError());
- }
- if (GetModuleHandleA("ssleay32.dll"))
- qWarning("ssleay32.dll already loaded?!");
- else {
- QString ssleay32 = appPath + "\\ssleay32.dll";
- if (!QFile::exists(ssleay32))
- qWarning("ssleay32.dll not found: %s", qPrintable(ssleay32));
- else if (!LoadLibraryW(ssleay32.toStdWString().c_str()))
- qWarning("failed to load: %s, %d", qPrintable(ssleay32), GetLastError());
- }
+static void preloadSsl() {
+ QString appPath = QDir::toNativeSeparators(QCoreApplication::applicationDirPath());
+ if (GetModuleHandleA("libeay32.dll"))
+ qWarning("libeay32.dll already loaded?!");
+ else {
+ QString libeay32 = appPath + "\\libeay32.dll";
+ if (!QFile::exists(libeay32))
+ qWarning("libeay32.dll not found: %s", qPrintable(libeay32));
+ else if (!LoadLibraryW(libeay32.toStdWString().c_str()))
+ qWarning("failed to load: %s, %d", qPrintable(libeay32), GetLastError());
+ }
+ if (GetModuleHandleA("ssleay32.dll"))
+ qWarning("ssleay32.dll already loaded?!");
+ else {
+ QString ssleay32 = appPath + "\\ssleay32.dll";
+ if (!QFile::exists(ssleay32))
+ qWarning("ssleay32.dll not found: %s", qPrintable(ssleay32));
+ else if (!LoadLibraryW(ssleay32.toStdWString().c_str()))
+ qWarning("failed to load: %s, %d", qPrintable(ssleay32), GetLastError());
+ }
}
-static QString getVersionDisplayString()
-{
- VS_FIXEDFILEINFO version = GetFileVersion(ToWString(QApplication::applicationFilePath()));
- return VersionInfo(version.dwFileVersionMS >> 16,
- version.dwFileVersionMS & 0xFFFF,
- version.dwFileVersionLS >> 16,
- version.dwFileVersionLS & 0xFFFF).displayString();
+static QString getVersionDisplayString() {
+ VS_FIXEDFILEINFO version = GetFileVersion(ToWString(QApplication::applicationFilePath()));
+ return VersionInfo(version.dwFileVersionMS >> 16, version.dwFileVersionMS & 0xFFFF, version.dwFileVersionLS >> 16,
+ version.dwFileVersionLS & 0xFFFF)
+ .displayString();
}
-int runApplication(MOApplication &application, SingleInstance &instance,
- const QString &splashPath)
-{
+int runApplication(MOApplication& application, SingleInstance& instance, const QString& splashPath) {
- qDebug("Starting Mod Organizer version %s revision %s", qPrintable(getVersionDisplayString()),
+ qDebug("Starting Mod Organizer version %s revision %s", qPrintable(getVersionDisplayString()),
#if defined(HGID)
- HGID
+ HGID
#elif defined(GITID)
- GITID
+ GITID
#else
- "unknown"
+ "unknown"
#endif
- );
+ );
#if !defined(QT_NO_SSL)
- preloadSsl();
- qDebug("ssl support: %d", QSslSocket::supportsSsl());
+ preloadSsl();
+ qDebug("ssl support: %d", QSslSocket::supportsSsl());
#else
- qDebug("non-ssl build");
+ qDebug("non-ssl build");
#endif
- QString dataPath = application.property("dataPath").toString();
- qDebug("data path: %s", qPrintable(dataPath));
-
- if (!bootstrap()) {
- reportError("failed to set up data paths");
- return 1;
- }
+ QString dataPath = application.property("dataPath").toString();
+ qDebug("data path: %s", qPrintable(dataPath));
- QStringList arguments = application.arguments();
+ if (!bootstrap()) {
+ reportError("failed to set up data paths");
+ return 1;
+ }
- try {
- qDebug("Working directory: %s", qPrintable(QDir::toNativeSeparators(QDir::currentPath())));
+ QStringList arguments = application.arguments();
- QSettings settings(dataPath + "/"
- + QString::fromStdWString(AppConfig::iniFileName()),
- QSettings::IniFormat);
+ try {
+ qDebug("Working directory: %s", qPrintable(QDir::toNativeSeparators(QDir::currentPath())));
- // global crashDumpType sits in OrganizerCore to make a bit less ugly to update it when the settings are changed during runtime
- OrganizerCore::setGlobalCrashDumpsType(settings.value("Settings/crash_dumps_type", static_cast<int>(CrashDumpsType::Mini)).toInt());
+ QSettings settings(dataPath + "/" + QString::fromStdWString(AppConfig::iniFileName()), QSettings::IniFormat);
- qDebug("Loaded settings:");
- settings.beginGroup("Settings");
- for (auto k : settings.allKeys())
- if (!k.contains("username") && !k.contains("password"))
- qDebug(" %s=%s", k.toUtf8().data(), settings.value(k).toString().toUtf8().data());
- settings.endGroup();
+ // global crashDumpType sits in OrganizerCore to make a bit less ugly to update it when the settings are changed
+ // during runtime
+ OrganizerCore::setGlobalCrashDumpsType(
+ settings.value("Settings/crash_dumps_type", static_cast<int>(CrashDumpsType::Mini)).toInt());
+ qDebug("Loaded settings:");
+ settings.beginGroup("Settings");
+ for (auto k : settings.allKeys())
+ if (!k.contains("username") && !k.contains("password"))
+ qDebug(" %s=%s", k.toUtf8().data(), settings.value(k).toString().toUtf8().data());
+ settings.endGroup();
- qDebug("initializing core");
- OrganizerCore organizer(settings);
- if (!organizer.bootstrap()) {
- reportError("failed to set up data paths");
- return 1;
- }
- qDebug("initialize plugins");
- PluginContainer pluginContainer(&organizer);
- pluginContainer.loadPlugins();
+ qDebug("initializing core");
+ OrganizerCore organizer(settings);
+ if (!organizer.bootstrap()) {
+ reportError("failed to set up data paths");
+ return 1;
+ }
+ qDebug("initialize plugins");
+ PluginContainer pluginContainer(&organizer);
+ pluginContainer.loadPlugins();
- MOBase::IPluginGame *game = determineCurrentGame(
- application.applicationDirPath(), settings, pluginContainer);
- if (game == nullptr) {
- return 1;
- }
- if (splashPath.startsWith(':')) {
- // currently using MO splash, see if the plugin contains one
- QString pluginSplash
- = QString(":/%1/splash").arg(game->gameShortName());
- QImage image(pluginSplash);
- if (!image.isNull()) {
- image.save(dataPath + "/splash.png");
- } else {
- qDebug("no plugin splash");
- }
- }
+ MOBase::IPluginGame* game = determineCurrentGame(application.applicationDirPath(), settings, pluginContainer);
+ if (game == nullptr) {
+ return 1;
+ }
+ if (splashPath.startsWith(':')) {
+ // currently using MO splash, see if the plugin contains one
+ QString pluginSplash = QString(":/%1/splash").arg(game->gameShortName());
+ QImage image(pluginSplash);
+ if (!image.isNull()) {
+ image.save(dataPath + "/splash.png");
+ } else {
+ qDebug("no plugin splash");
+ }
+ }
- organizer.setManagedGame(game);
- organizer.createDefaultProfile();
+ organizer.setManagedGame(game);
+ organizer.createDefaultProfile();
- if (!settings.contains("game_edition")) {
- QStringList editions = game->gameVariants();
- if (editions.size() > 1) {
- SelectionDialog selection(
- QObject::tr("Please select the game edition you have (MO can't "
- "start the game correctly if this is set "
- "incorrectly!)"),
- nullptr);
- int index = 0;
- for (const QString &edition : editions) {
- selection.addChoice(edition, "", index++);
+ if (!settings.contains("game_edition")) {
+ QStringList editions = game->gameVariants();
+ if (editions.size() > 1) {
+ SelectionDialog selection(QObject::tr("Please select the game edition you have (MO can't "
+ "start the game correctly if this is set "
+ "incorrectly!)"),
+ nullptr);
+ int index = 0;
+ for (const QString& edition : editions) {
+ selection.addChoice(edition, "", index++);
+ }
+ if (selection.exec() == QDialog::Rejected) {
+ return 1;
+ } else {
+ settings.setValue("game_edition", selection.getChoiceString());
+ }
+ }
}
- if (selection.exec() == QDialog::Rejected) {
- return 1;
- } else {
- settings.setValue("game_edition", selection.getChoiceString());
- }
- }
- }
- game->setGameVariant(settings.value("game_edition").toString());
+ game->setGameVariant(settings.value("game_edition").toString());
- qDebug("managing game at %s", qPrintable(QDir::toNativeSeparators(
- game->gameDirectory().absolutePath())));
+ qDebug("managing game at %s", qPrintable(QDir::toNativeSeparators(game->gameDirectory().absolutePath())));
- organizer.updateExecutablesList(settings);
+ organizer.updateExecutablesList(settings);
- QString selectedProfileName = determineProfile(arguments, settings);
- organizer.setCurrentProfile(selectedProfileName);
+ QString selectedProfileName = determineProfile(arguments, settings);
+ organizer.setCurrentProfile(selectedProfileName);
- // if we have a command line parameter, it is either a nxm link or
- // a binary to start
- if (arguments.size() > 1) {
- if (MOShortcut shortcut{ arguments.at(1) }) {
- try {
- organizer.runShortcut(shortcut);
- return 0;
- } catch (const std::exception &e) {
- reportError(
- QObject::tr("failed to start shortcut: %1").arg(e.what()));
- return 1;
+ // if we have a command line parameter, it is either a nxm link or
+ // a binary to start
+ if (arguments.size() > 1) {
+ if (MOShortcut shortcut{arguments.at(1)}) {
+ try {
+ organizer.runShortcut(shortcut);
+ return 0;
+ } catch (const std::exception& e) {
+ reportError(QObject::tr("failed to start shortcut: %1").arg(e.what()));
+ return 1;
+ }
+ } else if (OrganizerCore::isNxmLink(arguments.at(1))) {
+ qDebug("starting download from command line: %s", qPrintable(arguments.at(1)));
+ organizer.externalMessage(arguments.at(1));
+ } else {
+ QString exeName = arguments.at(1);
+ qDebug("starting %s from command line", qPrintable(exeName));
+ arguments.removeFirst(); // remove application name (ModOrganizer.exe)
+ arguments.removeFirst(); // remove binary name
+ // pass the remaining parameters to the binary
+ try {
+ organizer.startApplication(exeName, arguments, QString(), QString());
+ return 0;
+ } catch (const std::exception& e) {
+ reportError(QObject::tr("failed to start application: %1").arg(e.what()));
+ return 1;
+ }
+ }
}
- } else if (OrganizerCore::isNxmLink(arguments.at(1))) {
- qDebug("starting download from command line: %s",
- qPrintable(arguments.at(1)));
- organizer.externalMessage(arguments.at(1));
- } else {
- QString exeName = arguments.at(1);
- qDebug("starting %s from command line", qPrintable(exeName));
- arguments.removeFirst(); // remove application name (ModOrganizer.exe)
- arguments.removeFirst(); // remove binary name
- // pass the remaining parameters to the binary
- try {
- organizer.startApplication(exeName, arguments, QString(), QString());
- return 0;
- } catch (const std::exception &e) {
- reportError(
- QObject::tr("failed to start application: %1").arg(e.what()));
- return 1;
- }
- }
- }
- QPixmap pixmap(splashPath);
- QSplashScreen splash(pixmap);
- splash.show();
+ QPixmap pixmap(splashPath);
+ QSplashScreen splash(pixmap);
+ splash.show();
- NexusInterface::instance()->getAccessManager()->startLoginCheck();
+ NexusInterface::instance()->getAccessManager()->startLoginCheck();
- qDebug("initializing tutorials");
- TutorialManager::init(
- qApp->applicationDirPath() + "/"
- + QString::fromStdWString(AppConfig::tutorialsPath()) + "/",
- &organizer);
+ qDebug("initializing tutorials");
+ TutorialManager::init(
+ qApp->applicationDirPath() + "/" + QString::fromStdWString(AppConfig::tutorialsPath()) + "/", &organizer);
- if (!application.setStyleFile(settings.value("Settings/style", "").toString())) {
- // disable invalid stylesheet
- settings.setValue("Settings/style", "");
- }
+ if (!application.setStyleFile(settings.value("Settings/style", "").toString())) {
+ // disable invalid stylesheet
+ settings.setValue("Settings/style", "");
+ }
- int res = 1;
- { // scope to control lifetime of mainwindow
- // set up main window and its data structures
- MainWindow mainWindow(settings, organizer, pluginContainer);
+ int res = 1;
+ { // scope to control lifetime of mainwindow
+ // set up main window and its data structures
+ MainWindow mainWindow(settings, organizer, pluginContainer);
- QObject::connect(&mainWindow, SIGNAL(styleChanged(QString)), &application,
- SLOT(setStyleFile(QString)));
- QObject::connect(&instance, SIGNAL(messageSent(QString)), &organizer,
- SLOT(externalMessage(QString)));
+ QObject::connect(&mainWindow, SIGNAL(styleChanged(QString)), &application, SLOT(setStyleFile(QString)));
+ QObject::connect(&instance, SIGNAL(messageSent(QString)), &organizer, SLOT(externalMessage(QString)));
- mainWindow.readSettings();
+ mainWindow.readSettings();
- qDebug("displaying main window");
- mainWindow.show();
+ qDebug("displaying main window");
+ mainWindow.show();
- splash.finish(&mainWindow);
- return application.exec();
+ splash.finish(&mainWindow);
+ return application.exec();
+ }
+ } catch (const std::exception& e) {
+ reportError(e.what());
+ return 1;
}
- } catch (const std::exception &e) {
- reportError(e.what());
- return 1;
- }
}
+int main(int argc, char* argv[]) {
+ // Should allow for better scaling of ui with higher resolution displays
+ QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
-int main(int argc, char *argv[])
-{
- //Should allow for better scaling of ui with higher resolution displays
- QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
-
- if (argc >= 4) {
- std::vector<std::wstring> arg;
- auto args = UntouchedCommandLineArguments(2, arg);
- if (arg[0] == L"launch")
- return SpawnWaitProcess(arg[1].c_str(), args);
- }
+ if (argc >= 4) {
+ std::vector<std::wstring> arg;
+ auto args = UntouchedCommandLineArguments(2, arg);
+ if (arg[0] == L"launch")
+ return SpawnWaitProcess(arg[1].c_str(), args);
+ }
- MOApplication application(argc, argv);
- QStringList arguments = application.arguments();
+ MOApplication application(argc, argv);
+ QStringList arguments = application.arguments();
- setupPath();
+ setupPath();
- bool forcePrimary = false;
- if (arguments.contains("update")) {
- arguments.removeAll("update");
- forcePrimary = true;
- }
+ bool forcePrimary = false;
+ if (arguments.contains("update")) {
+ arguments.removeAll("update");
+ forcePrimary = true;
+ }
- MOShortcut moshortcut{ arguments.size() > 1 ? arguments.at(1) : "" };
+ MOShortcut moshortcut{arguments.size() > 1 ? arguments.at(1) : ""};
- SingleInstance instance(forcePrimary);
- if (!instance.primaryInstance()) {
- if (moshortcut ||
- arguments.size() > 1 && OrganizerCore::isNxmLink(arguments.at(1)))
- {
- qDebug("not primary instance, sending shortcut/download message");
- instance.sendMessage(arguments.at(1));
- return 0;
- } else if (arguments.size() == 1) {
- QMessageBox::information(
- nullptr, QObject::tr("Mod Organizer"),
- QObject::tr("An instance of Mod Organizer is already running"));
- return 0;
- }
- } // we continue for the primary instance OR if MO was called with parameters
+ SingleInstance instance(forcePrimary);
+ if (!instance.primaryInstance()) {
+ if (moshortcut || arguments.size() > 1 && OrganizerCore::isNxmLink(arguments.at(1))) {
+ qDebug("not primary instance, sending shortcut/download message");
+ instance.sendMessage(arguments.at(1));
+ return 0;
+ } else if (arguments.size() == 1) {
+ QMessageBox::information(nullptr, QObject::tr("Mod Organizer"),
+ QObject::tr("An instance of Mod Organizer is already running"));
+ return 0;
+ }
+ } // we continue for the primary instance OR if MO was called with parameters
- do {
- QString dataPath;
+ do {
+ QString dataPath;
- try {
- InstanceManager& instanceManager = InstanceManager::instance();
- if (moshortcut && moshortcut.hasInstance())
- instanceManager.overrideInstance(moshortcut.instance());
- dataPath = instanceManager.determineDataPath();
- } catch (const std::exception &e) {
- if (strcmp(e.what(),"Canceled"))
- QMessageBox::critical(nullptr, QObject::tr("Failed to set up instance"), e.what());
- return 1;
- }
- application.setProperty("dataPath", dataPath);
+ try {
+ InstanceManager& instanceManager = InstanceManager::instance();
+ if (moshortcut && moshortcut.hasInstance())
+ instanceManager.overrideInstance(moshortcut.instance());
+ dataPath = instanceManager.determineDataPath();
+ } catch (const std::exception& e) {
+ if (strcmp(e.what(), "Canceled"))
+ QMessageBox::critical(nullptr, QObject::tr("Failed to set up instance"), e.what());
+ return 1;
+ }
+ application.setProperty("dataPath", dataPath);
- // initialize dump collection only after "dataPath" since the crashes are stored under it
- prevUnhandledExceptionFilter = SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
+ // initialize dump collection only after "dataPath" since the crashes are stored under it
+ prevUnhandledExceptionFilter = SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
- LogBuffer::init(1000, QtDebugMsg, qApp->property("dataPath").toString() + "/logs/mo_interface.log");
+ LogBuffer::init(1000, QtDebugMsg, qApp->property("dataPath").toString() + "/logs/mo_interface.log");
- QString splash = dataPath + "/splash.png";
- if (!QFile::exists(dataPath + "/splash.png")) {
- splash = ":/MO/gui/splash";
- }
+ QString splash = dataPath + "/splash.png";
+ if (!QFile::exists(dataPath + "/splash.png")) {
+ splash = ":/MO/gui/splash";
+ }
- int result = runApplication(application, instance, splash);
- if (result != INT_MAX) {
- return result;
- }
- argc = 1;
- } while (true);
+ int result = runApplication(application, instance, splash);
+ if (result != INT_MAX) {
+ return result;
+ }
+ argc = 1;
+ } while (true);
}
|
