From f97e40f127441828eb4ffe11841ebf79191ac8a3 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Wed, 22 Jul 2020 22:35:40 -0400
Subject: moved initLogging() to loglist.cpp
---
src/loglist.cpp | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 65 insertions(+)
(limited to 'src/loglist.cpp')
diff --git a/src/loglist.cpp b/src/loglist.cpp
index a4868ed4..7a64ecad 100644
--- a/src/loglist.cpp
+++ b/src/loglist.cpp
@@ -262,3 +262,68 @@ void LogList::onContextMenu(const QPoint& pos)
auto* menu = createMenu(this);
menu->popup(viewport()->mapToGlobal(pos));
}
+
+
+log::Levels convertQtLevel(QtMsgType t)
+{
+ switch (t)
+ {
+ case QtDebugMsg:
+ return log::Debug;
+
+ case QtWarningMsg:
+ return log::Warning;
+
+ case QtCriticalMsg: // fall-through
+ case QtFatalMsg:
+ return log::Error;
+
+ case QtInfoMsg: // fall-through
+ default:
+ return log::Info;
+ }
+}
+
+void qtLogCallback(
+ QtMsgType type, const QMessageLogContext& context, const QString& message)
+{
+ std::string_view file = "";
+
+ if (type != QtDebugMsg) {
+ if (context.file) {
+ file = context.file;
+
+ const auto lastSep = file.find_last_of("/\\");
+ if (lastSep != std::string_view::npos) {
+ file = {context.file + lastSep + 1};
+ }
+ }
+ }
+
+ if (file.empty()) {
+ log::log(
+ convertQtLevel(type), "{}",
+ message.toStdString());
+ } else {
+ log::log(
+ convertQtLevel(type), "[{}:{}] {}",
+ file, context.line, message.toStdString());
+ }
+}
+
+void initLogging()
+{
+ LogModel::create();
+
+ log::LoggerConfiguration conf;
+ conf.maxLevel = MOBase::log::Debug;
+ conf.pattern = "%^[%Y-%m-%d %H:%M:%S.%e %L] %v%$";
+ conf.utc = true;
+
+ log::createDefault(conf);
+
+ log::getDefault().setCallback(
+ [](log::Entry e){ LogModel::instance().add(e); });
+
+ qInstallMessageHandler(qtLogCallback);
+}
--
cgit v1.3.1
From 9435202034cafb05ffc11aed48ff57536bce73f7 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Wed, 22 Jul 2020 23:27:01 -0400
Subject: removed flags from SingleInstance because there's only one left
refactoring in main.cpp: - moved stuff to loglist.cpp and moapplication.cpp
- split main() into a few functions
---
src/env.cpp | 13 ++-
src/env.h | 3 +-
src/loglist.cpp | 26 ++++++
src/loglist.h | 1 +
src/main.cpp | 225 ++++++++++++++++++++++++-------------------------
src/moapplication.cpp | 19 ++---
src/moapplication.h | 20 ++---
src/singleinstance.cpp | 4 +-
src/singleinstance.h | 18 +---
src/spawn.cpp | 2 +-
10 files changed, 174 insertions(+), 157 deletions(-)
(limited to 'src/loglist.cpp')
diff --git a/src/env.cpp b/src/env.cpp
index bf75c9fa..9f0acbbd 100644
--- a/src/env.cpp
+++ b/src/env.cpp
@@ -400,11 +400,18 @@ QString path()
return get("PATH");
}
-QString addPath(const QString& s)
+QString appendToPath(const QString& s)
{
auto old = path();
- set("PATH", get("PATH") + ";" + s);
- return old;
+ set("PATH", old + ";" + s);
+ return old;
+}
+
+QString prependToPath(const QString& s)
+{
+ auto old = path();
+ set("PATH", s + ";" + old);
+ return old;
}
QString setPath(const QString& s)
diff --git a/src/env.h b/src/env.h
index 9bec1713..a563f2c3 100644
--- a/src/env.h
+++ b/src/env.h
@@ -236,7 +236,8 @@ QString get(const QString& name);
QString set(const QString& name, const QString& value);
QString path();
-QString addPath(const QString& s);
+QString appendToPath(const QString& s);
+QString prependToPath(const QString& s);
QString setPath(const QString& s);
diff --git a/src/loglist.cpp b/src/loglist.cpp
index 7a64ecad..167b61ef 100644
--- a/src/loglist.cpp
+++ b/src/loglist.cpp
@@ -327,3 +327,29 @@ void initLogging()
qInstallMessageHandler(qtLogCallback);
}
+
+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;
+ }
+}
+
+bool setLogDirectory(const QString& dir)
+{
+ const auto logFile = dir + "/logs/mo_interface.log";
+
+ if (!createAndMakeWritable(AppConfig::logPath())) {
+ return false;
+ }
+
+ log::getDefault().setFile(MOBase::log::File::single(logFile.toStdWString()));
+}
diff --git a/src/loglist.h b/src/loglist.h
index 7387eb50..0745ed3e 100644
--- a/src/loglist.h
+++ b/src/loglist.h
@@ -84,5 +84,6 @@ private:
void initLogging();
+bool setLogDirectory(const QString& dir);
#endif // LOGBUFFER_H
diff --git a/src/main.cpp b/src/main.cpp
index e52b252b..864d26a1 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -38,7 +38,13 @@ along with Mod Organizer. If not, see .
#include
#include
-#pragma comment(linker, "/manifestDependency:\"name='dlls' processorArchitecture='x86' version='1.0.0.0' type='win32' \"")
+// see addDllsToPath() below
+#pragma comment(linker, "/manifestDependency:\"" \
+ "name='dlls' " \
+ "processorArchitecture='x86' " \
+ "version='1.0.0.0' " \
+ "type='win32' \"")
+
using namespace MOBase;
using namespace MOShared;
@@ -47,21 +53,6 @@ void sanityChecks(const env::Environment& env);
int checkIncompatibleModule(const env::Module& m);
int checkPathsForSanity(MOBase::IPluginGame& game, const Settings& s);
-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;
- }
-}
-
void purgeOldFiles()
{
// remove the temporary backup directory in case we're restarting after an
@@ -305,36 +296,47 @@ MOBase::IPluginGame *determineCurrentGame(
}
-// 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()
+// This adds the `dlls` directory to the path so the dlls can be found. How
+// MO is able to find dlls in there is a bit convoluted:
+//
+// Dependencies on DLLs can be baked into an executable by passing a
+// `manifestdependency` option to the linker. This can be done on the command
+// line or with a pragma. Typically, the dependency will not be a hardcoded
+// filename, but an assembly name, such as Microsoft.Windows.Common-Controls.
+//
+// When Windows loads the exe, it will look for this assembly in a variety of
+// places, such as in the WinSxS folder, but also in the program's folder. It
+// will look for `assemblyname.dll` or `assemblyname/assemblyname.dll` and try
+// to load that.
+//
+// If these files don't exist, then the loader gets creative and looks for
+// `assemblyname.manifest` and `assemblyname/assemblyname.manifest`. A manifest
+// file is just an XML file that can contain a list of DLLs to load for this
+// assembly.
+//
+// In MO's case, there's a `pragma` at the beginning of this file which adds
+// `dlls` as an "assembly" dependency. This is a bit of a hack to just force
+// the loader to eventually find `dlls/dlls.manifest`, which contains the list
+// of all the DLLs MO requires to load.
+//
+// This file was handwritten in `modorganizer/src/dlls.manifest.qt5` and
+// is copied and renamed in CMakeLists.txt into `bin/dlls/dlls.manifest`. Note
+// that the useless and incorrect .qt5 extension is removed.
+//
+void addDllsToPath()
{
- static const int BUFSIZE = 4096;
-
- QCoreApplication::setLibraryPaths(QStringList(QCoreApplication::applicationDirPath() + "/dlls") + QCoreApplication::libraryPaths());
+ const auto dllsPath = QDir::toNativeSeparators(
+ QCoreApplication::applicationDirPath() + "/dlls");
- boost::scoped_array 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(ToWString(QDir::toNativeSeparators(
- QCoreApplication::applicationDirPath())) + L"\\dlls");
- newPath += L";";
- newPath += oldPath.get();
+ QCoreApplication::setLibraryPaths(
+ QStringList(dllsPath) + QCoreApplication::libraryPaths());
- ::SetEnvironmentVariableW(L"PATH", newPath.c_str());
+ env::prependToPath(dllsPath);
}
int runApplication(
MOApplication &application, const cl::CommandLine& cl,
- SingleInstance &instance, const QString &splashPath)
+ SingleInstance &instance, const QString &dataPath)
{
TimeThis tt("runApplication() to exec()");
@@ -343,7 +345,6 @@ int runApplication(
createVersionInfo().displayString(3), GITID,
QCoreApplication::applicationDirPath(), MOShared::getUsvfsVersionString());
- const QString dataPath = application.property("dataPath").toString();
log::info("data path: {}", dataPath);
if (InstanceManager::isPortablePath(dataPath)) {
@@ -429,8 +430,14 @@ int runApplication(
checkPathsForSanity(*game, settings);
bool useSplash = settings.useSplash();
+ QString splashPath;
if (useSplash) {
+ splashPath = dataPath + "/splash.png";
+ if (!QFile::exists(dataPath + "/splash.png")) {
+ splashPath = ":/MO/gui/splash";
+ }
+
if (splashPath.startsWith(':')) {
// currently using MO splash, see if the plugin contains one
QString pluginSplash
@@ -599,111 +606,101 @@ int runApplication(
return 1;
}
-int main(int argc, char *argv[])
+int forwardToPrimary(SingleInstance& instance, const cl::CommandLine& cl)
{
- cl::CommandLine cl;
-
- const auto r = cl.run(GetCommandLineW());
- if (r)
- return *r;
-
- TimeThis tt("main to runApplication()");
-
- // in loglist.cpp
- initLogging();
+ if (cl.shortcut().isValid()) {
+ instance.sendMessage(cl.shortcut().toString());
+ } else if (cl.nxmLink()) {
+ instance.sendMessage(*cl.nxmLink());
+ } else {
+ QMessageBox::information(
+ nullptr, QObject::tr("Mod Organizer"),
+ QObject::tr("An instance of Mod Organizer is already running"));
+ }
- //Make sure the configured temp folder exists
- QDir tempDir = QDir::temp();
- if (!tempDir.exists())
- tempDir.root().mkpath(tempDir.canonicalPath());
+ return 0;
+}
- //Should allow for better scaling of ui with higher resolution displays
- QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+void resetForRestart(cl::CommandLine& cl)
+{
+ LogModel::instance().clear();
+ ResetExitFlag();
- MOApplication application(argc, argv);
- QStringList arguments = application.arguments();
+ // make sure the log file isn't locked in case MO was restarted and
+ // the previous instance gets deleted
+ log::getDefault().setFile({});
- SetThisThreadName("main");
+ // don't reprocess command line
+ cl.clear();
+}
- setupPath();
+QString determineDataPath(const cl::CommandLine& cl)
+{
+ try
+ {
+ InstanceManager& instanceManager = InstanceManager::instance();
+ if (cl.instance())
+ instanceManager.overrideInstance(*cl.instance());
- SingleInstance::Flags siFlags = SingleInstance::NoFlags;
+ return instanceManager.determineDataPath();
+ }
+ catch (const std::exception &e)
+ {
+ if (strcmp(e.what(),"Canceled")) {
+ QMessageBox::critical(nullptr, QObject::tr("Failed to set up instance"), e.what());
+ }
- if (cl.multiple()) {
- arguments.removeAll("--multiple");
- siFlags |= SingleInstance::AllowMultiple;
+ return {};
}
+}
- SingleInstance instance(siFlags);
- if (instance.ephemeral()) {
- if (cl.shortcut().isValid()) {
- instance.sendMessage(cl.shortcut().toString());
- return 0;
- } else if (cl.nxmLink()) {
- instance.sendMessage(*cl.nxmLink());
- 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
+int main(int argc, char *argv[])
+{
+ cl::CommandLine cl;
- do {
- LogModel::instance().clear();
- ResetExitFlag();
+ if (auto r=cl.run(GetCommandLineW())) {
+ return *r;
+ }
- // make sure the log file isn't locked in case MO was restarted and
- // the previous instance gets deleted
- log::getDefault().setFile({});
+ TimeThis tt("main to runApplication()");
+ SetThisThreadName("main");
- QString dataPath;
+ initLogging();
+ auto application = MOApplication::create(argc, argv);
+ addDllsToPath();
- try {
- InstanceManager& instanceManager = InstanceManager::instance();
+ SingleInstance instance(cl.multiple());
+ if (instance.ephemeral()) {
+ return forwardToPrimary(instance, cl);
+ }
- if (cl.instance())
- instanceManager.overrideInstance(*cl.instance());
+ for (;;)
+ {
+ // resets things when MO is "restarted"
+ resetForRestart(cl);
- 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());
+ const QString dataPath = determineDataPath(cl);
+ if (dataPath.isEmpty()) {
return 1;
}
- application.setProperty("dataPath", dataPath);
-
- // initialize dump collection only after "dataPath" since the crashes are stored under it
- setUnhandledExceptionHandler();
- const auto logFile =
- qApp->property("dataPath").toString() + "/logs/mo_interface.log";
+ application.setProperty("dataPath", dataPath);
+ setExceptionHandler();
- if (!createAndMakeWritable(AppConfig::logPath())) {
+ if (!setLogDirectory(dataPath)) {
reportError("Failed to create log folder");
InstanceManager::instance().clearCurrentInstance();
return 1;
}
- log::getDefault().setFile(MOBase::log::File::single(logFile.toStdWString()));
-
log::debug("command line: '{}'", QString::fromWCharArray(GetCommandLineW()));
- QString splash = dataPath + "/splash.png";
- if (!QFile::exists(dataPath + "/splash.png")) {
- splash = ":/MO/gui/splash";
- }
-
tt.stop();
- const int result = runApplication(application, cl, instance, splash);
+ const int result = runApplication(application, cl, instance, dataPath);
if (result != RestartExitCode) {
return result;
}
-
- argc = 1;
- cl.clear();
- } while (true);
+ }
}
diff --git a/src/moapplication.cpp b/src/moapplication.cpp
index dd49bf53..d95d544a 100644
--- a/src/moapplication.cpp
+++ b/src/moapplication.cpp
@@ -24,16 +24,10 @@ along with Mod Organizer. If not, see .
#include "shared/appconfig.h"
#include
#include
-#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
-#include
-#include
-#endif
#include
#include
#include
#include
-
-
#include
@@ -77,7 +71,7 @@ public:
};
-MOApplication::MOApplication(int &argc, char **argv)
+MOApplication::MOApplication(int argc, char** argv)
: QApplication(argc, argv)
{
connect(&m_StyleWatcher, &QFileSystemWatcher::fileChanged, [&](auto&& file){
@@ -89,8 +83,13 @@ MOApplication::MOApplication(int &argc, char **argv)
setStyle(new ProxyStyle(style()));
}
+MOApplication MOApplication::create(int argc, char** argv)
+{
+ QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+ return MOApplication(argc, argv);
+}
-bool MOApplication::setStyleFile(const QString &styleName)
+bool MOApplication::setStyleFile(const QString& styleName)
{
// remove all files from watch
QStringList currentWatch = m_StyleWatcher.files();
@@ -114,7 +113,7 @@ bool MOApplication::setStyleFile(const QString &styleName)
}
-bool MOApplication::notify(QObject *receiver, QEvent *event)
+bool MOApplication::notify(QObject* receiver, QEvent* event)
{
try {
return QApplication::notify(receiver, event);
@@ -134,7 +133,7 @@ bool MOApplication::notify(QObject *receiver, QEvent *event)
}
-void MOApplication::updateStyle(const QString &fileName)
+void MOApplication::updateStyle(const QString& fileName)
{
if (QStyleFactory::keys().contains(fileName)) {
setStyle(QStyleFactory::create(fileName));
diff --git a/src/moapplication.h b/src/moapplication.h
index 9db130af..3ed71fb6 100644
--- a/src/moapplication.h
+++ b/src/moapplication.h
@@ -24,27 +24,25 @@ along with Mod Organizer. If not, see .
#include
-class MOApplication : public QApplication {
-Q_OBJECT
-public:
-
- MOApplication(int &argc, char **argv);
+class MOApplication : public QApplication
+{
+ Q_OBJECT
- virtual bool notify (QObject *receiver, QEvent *event);
+public:
+ static MOApplication create(int argc, char** argv);
+ virtual bool notify (QObject* receiver, QEvent* event);
public slots:
-
- bool setStyleFile(const QString &style);
+ bool setStyleFile(const QString& style);
private slots:
-
- void updateStyle(const QString &fileName);
+ void updateStyle(const QString& fileName);
private:
-
QFileSystemWatcher m_StyleWatcher;
QString m_DefaultStyle;
+ MOApplication(int argc, char** argv);
};
diff --git a/src/singleinstance.cpp b/src/singleinstance.cpp
index e32c8de1..bd7ccc43 100644
--- a/src/singleinstance.cpp
+++ b/src/singleinstance.cpp
@@ -28,14 +28,14 @@ static const int s_Timeout = 5000;
using MOBase::reportError;
-SingleInstance::SingleInstance(Flags flags, QObject *parent) :
+SingleInstance::SingleInstance(bool allowMultiple, QObject *parent) :
QObject(parent), m_Ephemeral(false), m_OwnsSM(false)
{
m_SharedMem.setKey(s_Key);
if (!m_SharedMem.create(1)) {
if (m_SharedMem.error() == QSharedMemory::AlreadyExists) {
- if (!flags.testFlag(AllowMultiple)) {
+ if (!allowMultiple) {
m_SharedMem.attach();
m_Ephemeral = true;
}
diff --git a/src/singleinstance.h b/src/singleinstance.h
index d500a056..5f6c3633 100644
--- a/src/singleinstance.h
+++ b/src/singleinstance.h
@@ -36,19 +36,9 @@ class SingleInstance : public QObject
Q_OBJECT
public:
- enum Flag
- {
- NoFlags = 0x00,
-
- // if another instance is running, run this one disconnected from the
- // shared memory
- AllowMultiple = 0x01
- };
-
- using Flags = QFlags;
-
-
- explicit SingleInstance(Flags flags, QObject *parent = 0);
+ // `allowMultiple`: if another instance is running, run this one
+ // disconnected from the shared memory
+ explicit SingleInstance(bool allowMultiple, QObject *parent = 0);
/**
* @return true if this instance's job is to forward data to the primary
@@ -97,6 +87,4 @@ private:
};
-Q_DECLARE_OPERATORS_FOR_FLAGS(SingleInstance::Flags);
-
#endif // SINGLEINSTANCE_H
diff --git a/src/spawn.cpp b/src/spawn.cpp
index 2016bb23..a9ecb61e 100644
--- a/src/spawn.cpp
+++ b/src/spawn.cpp
@@ -488,7 +488,7 @@ DWORD spawn(const SpawnParameters& sp, HANDLE& processHandle)
}
const QString moPath = QCoreApplication::applicationDirPath();
- const auto oldPath = env::addPath(QDir::toNativeSeparators(moPath));
+ const auto oldPath = env::appendToPath(QDir::toNativeSeparators(moPath));
PROCESS_INFORMATION pi = {};
BOOL success = FALSE;
--
cgit v1.3.1
From ae118153fbedc0240ea183488834a32abe202839 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Thu, 23 Jul 2020 00:38:03 -0400
Subject: more refactoring: - moved splash stuff together - moved stuff in
the main loop into doOneRun()
---
src/loglist.cpp | 2 +
src/main.cpp | 213 ++++++++++++++++++++++++++++----------------------
src/moapplication.cpp | 4 +-
src/moapplication.h | 4 +-
src/organizercore.cpp | 44 +++++++++--
src/settings.cpp | 2 +-
src/settings.h | 2 +-
7 files changed, 164 insertions(+), 107 deletions(-)
(limited to 'src/loglist.cpp')
diff --git a/src/loglist.cpp b/src/loglist.cpp
index 167b61ef..fad4678c 100644
--- a/src/loglist.cpp
+++ b/src/loglist.cpp
@@ -352,4 +352,6 @@ bool setLogDirectory(const QString& dir)
}
log::getDefault().setFile(MOBase::log::File::single(logFile.toStdWString()));
+
+ return true;
}
diff --git a/src/main.cpp b/src/main.cpp
index 864d26a1..52011ef4 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -68,26 +68,31 @@ void purgeOldFiles()
"usvfs*.log", 5, QDir::Name);
}
-thread_local LPTOP_LEVEL_EXCEPTION_FILTER prevUnhandledExceptionFilter = nullptr;
-thread_local std::terminate_handler prevTerminateHandler = nullptr;
+thread_local LPTOP_LEVEL_EXCEPTION_FILTER g_prevExceptionFilter = nullptr;
+thread_local std::terminate_handler g_prevTerminateHandler = nullptr;
-LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionPtrs)
+LONG WINAPI onUnhandledException(_EXCEPTION_POINTERS* ptrs)
{
const std::wstring& dumpPath = OrganizerCore::crashDumpsPath();
- int dumpRes =
- CreateMiniDump(exceptionPtrs, OrganizerCore::getGlobalCrashDumpsType(), dumpPath.c_str());
- if (!dumpRes)
+
+ const int r = CreateMiniDump(
+ ptrs, OrganizerCore::getGlobalCrashDumpsType(), dumpPath.c_str());
+
+ if (r == 0) {
log::error("ModOrganizer has crashed, crash dump created.");
- else
- log::error("ModOrganizer has crashed, CreateMiniDump failed ({}, error {}).", dumpRes, GetLastError());
+ } else {
+ log::error(
+ "ModOrganizer has crashed, CreateMiniDump failed ({}, error {}).",
+ r, GetLastError());
+ }
- if (prevUnhandledExceptionFilter && exceptionPtrs)
- return prevUnhandledExceptionFilter(exceptionPtrs);
+ if (g_prevExceptionFilter && ptrs)
+ return g_prevExceptionFilter(ptrs);
else
return EXCEPTION_CONTINUE_SEARCH;
}
-void terminateHandler() noexcept
+void onTerminate() noexcept
{
__try
{
@@ -96,22 +101,22 @@ void terminateHandler() noexcept
}
__except
(
- MyUnhandledExceptionFilter(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER
+ onUnhandledException(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER
)
{
}
- if (prevTerminateHandler) {
- prevTerminateHandler();
+ if (g_prevTerminateHandler) {
+ g_prevTerminateHandler();
} else {
std::abort();
}
}
-void setUnhandledExceptionHandler()
+void setExceptionHandlers()
{
- prevUnhandledExceptionFilter = SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
- prevTerminateHandler = std::set_terminate(terminateHandler);
+ g_prevExceptionFilter = SetUnhandledExceptionFilter(onUnhandledException);
+ g_prevTerminateHandler = std::set_terminate(onTerminate);
}
QString determineProfile(const cl::CommandLine& cl, const Settings &settings)
@@ -334,6 +339,55 @@ void addDllsToPath()
env::prependToPath(dllsPath);
}
+QString getSplashPath(
+ const Settings& settings, const QString& dataPath,
+ const MOBase::IPluginGame* game)
+{
+ if (!settings.useSplash()) {
+ return {};
+ }
+
+ const QString splashPath = dataPath + "/splash.png";
+ if (QFile::exists(dataPath + "/splash.png")) {
+ return splashPath;
+ }
+
+ // currently using MO splash, see if the plugin contains one
+ QString pluginSplash = QString(":/%1/splash").arg(game->gameShortName());
+ QImage image(pluginSplash);
+
+ if (image.isNull()) {
+ return {};
+ }
+
+ image.save(splashPath);
+ return splashPath;
+}
+
+std::unique_ptr createSplash(
+ const Settings& settings, const QString& dataPath,
+ const MOBase::IPluginGame* game)
+{
+ const auto splashPath = getSplashPath(settings, dataPath, game);
+ if (splashPath.isEmpty()) {
+ return {};
+ }
+
+ QPixmap image(splashPath);
+ if (image.isNull()) {
+ log::error("failed to load splash from {}", splashPath);
+ return {};
+ }
+
+ auto splash = std::make_unique(image);
+ settings.geometry().centerOnMainWindowMonitor(splash.get());
+
+ splash->show();
+ splash->activateWindow();
+
+ return splash;
+}
+
int runApplication(
MOApplication &application, const cl::CommandLine& cl,
SingleInstance &instance, const QString &dataPath)
@@ -351,6 +405,8 @@ int runApplication(
log::debug("this is a portable instance");
}
+ log::info("working directory: {}", QDir::currentPath());
+
if (!instance.secondary()) {
purgeOldFiles();
}
@@ -358,9 +414,8 @@ int runApplication(
QWindowsWindowFunctions::setWindowActivationBehavior(
QWindowsWindowFunctions::AlwaysActivateWindow);
- try {
- log::info("working directory: {}", QDir::currentPath());
-
+ try
+ {
Settings settings(dataPath + "/" + QString::fromStdWString(AppConfig::iniFileName()));
log::getDefault().setLevel(settings.diagnostics().logLevel());
@@ -370,7 +425,6 @@ int runApplication(
log::debug("another instance of MO is running but --multiple was given");
}
-
// global crashDumpType sits in OrganizerCore to make a bit less ugly to
// update it when the settings are changed during runtime
OrganizerCore::setGlobalCrashDumpsType(settings.diagnostics().crashDumpsType());
@@ -385,8 +439,10 @@ int runApplication(
checkIncompatibleModule(m);
});
- log::debug("initializing core");
+ // this must outlive `organizer`
std::unique_ptr pluginContainer;
+
+ log::debug("initializing core");
OrganizerCore organizer(settings);
if (!organizer.bootstrap()) {
reportError("failed to set up data paths");
@@ -394,25 +450,11 @@ int runApplication(
return 1;
}
- {
- // log if there are any dmp files
- const auto hasCrashDumps =
- !QDir(QString::fromStdWString(organizer.crashDumpsPath()))
- .entryList({"*.dmp"}, QDir::Files)
- .empty();
-
- if (hasCrashDumps) {
- log::debug(
- "there are crash dumps in '{}'",
- QString::fromStdWString(organizer.crashDumpsPath()));
- }
- }
-
log::debug("initializing plugins");
pluginContainer = std::make_unique(&organizer);
pluginContainer->loadPlugins();
- MOBase::IPluginGame *game = determineCurrentGame(
+ MOBase::IPluginGame* game = determineCurrentGame(
application.applicationDirPath(), settings, *pluginContainer);
if (game == nullptr) {
@@ -429,25 +471,6 @@ int runApplication(
checkPathsForSanity(*game, settings);
- bool useSplash = settings.useSplash();
- QString splashPath;
-
- if (useSplash) {
- splashPath = dataPath + "/splash.png";
- if (!QFile::exists(dataPath + "/splash.png")) {
- splashPath = ":/MO/gui/splash";
- }
-
- 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");
- }
- }
- }
organizer.setManagedGame(game);
organizer.createDefaultProfile();
@@ -535,18 +558,7 @@ int runApplication(
}
}
- QPixmap pixmap;
-
- QSplashScreen splash;
-
- if (useSplash) {
- pixmap = QPixmap(splashPath);
- splash.setPixmap(pixmap);
-
- settings.geometry().centerOnMainWindowMonitor(&splash);
- splash.show();
- splash.activateWindow();
- }
+ auto splash = createSplash(settings, dataPath, game);
QString apiKey;
if (settings.nexus().apiKey(apiKey)) {
@@ -582,10 +594,10 @@ int runApplication(
mainWindow.show();
mainWindow.activateWindow();
- if (useSplash) {
+ if (splash) {
// don't pass mainwindow as it just waits half a second for it
// instead of proceding
- splash.finish(nullptr);
+ splash->finish(nullptr);
}
tt.stop();
@@ -655,6 +667,35 @@ QString determineDataPath(const cl::CommandLine& cl)
}
}
+int doOneRun(
+ cl::CommandLine& cl, MOApplication& application, SingleInstance& instance)
+{
+ TimeThis tt("doOneRun() to runApplication()");
+
+ // resets things when MO is "restarted"
+ resetForRestart(cl);
+
+ const QString dataPath = determineDataPath(cl);
+ if (dataPath.isEmpty()) {
+ return 1;
+ }
+
+ application.setProperty("dataPath", dataPath);
+ setExceptionHandlers();
+
+ if (!setLogDirectory(dataPath)) {
+ reportError("Failed to create log folder");
+ InstanceManager::instance().clearCurrentInstance();
+ return 1;
+ }
+
+ log::debug("command line: '{}'", QString::fromWCharArray(GetCommandLineW()));
+
+ tt.stop();
+
+ return runApplication(application, cl, instance, dataPath);
+}
+
int main(int argc, char *argv[])
{
cl::CommandLine cl;
@@ -663,7 +704,8 @@ int main(int argc, char *argv[])
return *r;
}
- TimeThis tt("main to runApplication()");
+ TimeThis tt("main() to doOneRun()");
+
SetThisThreadName("main");
initLogging();
@@ -675,32 +717,15 @@ int main(int argc, char *argv[])
return forwardToPrimary(instance, cl);
}
+ tt.stop();
+
for (;;)
{
- // resets things when MO is "restarted"
- resetForRestart(cl);
-
- const QString dataPath = determineDataPath(cl);
- if (dataPath.isEmpty()) {
- return 1;
- }
-
- application.setProperty("dataPath", dataPath);
- setExceptionHandler();
-
- if (!setLogDirectory(dataPath)) {
- reportError("Failed to create log folder");
- InstanceManager::instance().clearCurrentInstance();
- return 1;
+ const auto r = doOneRun(cl, application, instance);
+ if (r == RestartExitCode) {
+ continue;
}
- log::debug("command line: '{}'", QString::fromWCharArray(GetCommandLineW()));
-
- tt.stop();
-
- const int result = runApplication(application, cl, instance, dataPath);
- if (result != RestartExitCode) {
- return result;
- }
+ return r;
}
}
diff --git a/src/moapplication.cpp b/src/moapplication.cpp
index d95d544a..290666af 100644
--- a/src/moapplication.cpp
+++ b/src/moapplication.cpp
@@ -71,7 +71,7 @@ public:
};
-MOApplication::MOApplication(int argc, char** argv)
+MOApplication::MOApplication(int& argc, char** argv)
: QApplication(argc, argv)
{
connect(&m_StyleWatcher, &QFileSystemWatcher::fileChanged, [&](auto&& file){
@@ -83,7 +83,7 @@ MOApplication::MOApplication(int argc, char** argv)
setStyle(new ProxyStyle(style()));
}
-MOApplication MOApplication::create(int argc, char** argv)
+MOApplication MOApplication::create(int& argc, char** argv)
{
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
return MOApplication(argc, argv);
diff --git a/src/moapplication.h b/src/moapplication.h
index 3ed71fb6..c67c4622 100644
--- a/src/moapplication.h
+++ b/src/moapplication.h
@@ -29,7 +29,7 @@ class MOApplication : public QApplication
Q_OBJECT
public:
- static MOApplication create(int argc, char** argv);
+ static MOApplication create(int& argc, char** argv);
virtual bool notify (QObject* receiver, QEvent* event);
public slots:
@@ -42,7 +42,7 @@ private:
QFileSystemWatcher m_StyleWatcher;
QString m_DefaultStyle;
- MOApplication(int argc, char** argv);
+ MOApplication(int& argc, char** argv);
};
diff --git a/src/organizercore.cpp b/src/organizercore.cpp
index a9469e6e..0849d756 100644
--- a/src/organizercore.cpp
+++ b/src/organizercore.cpp
@@ -473,13 +473,43 @@ bool OrganizerCore::checkPathSymlinks() {
return true;
}
-bool OrganizerCore::bootstrap() {
- return createDirectory(m_Settings.paths().profiles()) &&
- createDirectory(m_Settings.paths().mods()) &&
- createDirectory(m_Settings.paths().downloads()) &&
- createDirectory(m_Settings.paths().overwrite()) &&
- createDirectory(QString::fromStdWString(crashDumpsPath())) &&
- checkPathSymlinks() && cycleDiagnostics();
+bool OrganizerCore::bootstrap()
+{
+ const auto dirs = {
+ m_Settings.paths().profiles(),
+ m_Settings.paths().mods(),
+ m_Settings.paths().downloads(),
+ m_Settings.paths().overwrite(),
+ QString::fromStdWString(crashDumpsPath())
+ };
+
+ for (auto&& dir : dirs) {
+ if (!createDirectory(dir)) {
+ return false;
+ }
+ }
+
+ if (!checkPathSymlinks()) {
+ return false;
+ }
+
+ if (!cycleDiagnostics()) {
+ return false;
+ }
+
+ // log if there are any dmp files
+ const auto hasCrashDumps =
+ !QDir(QString::fromStdWString(crashDumpsPath()))
+ .entryList({"*.dmp"}, QDir::Files)
+ .empty();
+
+ if (hasCrashDumps) {
+ log::debug(
+ "there are crash dumps in '{}'",
+ QString::fromStdWString(crashDumpsPath()));
+ }
+
+ return true;
}
void OrganizerCore::createDefaultProfile()
diff --git a/src/settings.cpp b/src/settings.cpp
index 534e67c8..d37f0d99 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -876,7 +876,7 @@ void GeometrySettings::setCenterDialogs(bool b)
set(m_Settings, "Settings", "center_dialogs", b);
}
-void GeometrySettings::centerOnMainWindowMonitor(QWidget* w)
+void GeometrySettings::centerOnMainWindowMonitor(QWidget* w) const
{
const auto monitor = getOptional(
m_Settings, "Geometry", "MainWindow_monitor").value_or(-1);
diff --git a/src/settings.h b/src/settings.h
index 636719bb..a1b30462 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -169,7 +169,7 @@ public:
// assumes the given widget is a top-level
//
- void centerOnMainWindowMonitor(QWidget* w);
+ void centerOnMainWindowMonitor(QWidget* w) const;
// saves the monitor number of the given window
//
--
cgit v1.3.1