From 2eeaa0e31a0d74ccd7cada9e478db27263ce4532 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 31 Jul 2020 09:17:22 -0400 Subject: fixed warning when trying to get the file type of files without extensions --- src/filetreeitem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/filetreeitem.cpp b/src/filetreeitem.cpp index 49bc65ac..7997974f 100644 --- a/src/filetreeitem.cpp +++ b/src/filetreeitem.cpp @@ -40,7 +40,7 @@ const QString& directoryFileType() const QString& cachedFileTypeNoExtension() { static const QString name = [] { - const DWORD flags = SHGFI_TYPENAME; + const DWORD flags = SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES; SHFILEINFOW sfi = {}; // dummy filename with no extension -- cgit v1.3.1 From 777229f28f8f5de19376459e85b434576af8e010 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 31 Jul 2020 09:56:19 -0400 Subject: added startSafeThread() to get core dumps for threads other than the main thread added terminate handler --- src/envfs.h | 3 ++- src/iconfetcher.cpp | 3 ++- src/main.cpp | 30 ++++++++++++++++++++++++++---- src/organizercore.cpp | 8 ++++---- src/thread_utils.h | 25 ++++++++++++++++++++++--- 5 files changed, 56 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/envfs.h b/src/envfs.h index bbc27005..e4d98d71 100644 --- a/src/envfs.h +++ b/src/envfs.h @@ -1,6 +1,7 @@ #ifndef ENV_ENVFS_H #define ENV_ENVFS_H +#include "thread_utils.h" #include namespace env @@ -125,7 +126,7 @@ private: ThreadInfo() : busy(true), ready(false), stop(false) { - thread = std::thread([&]{ run(); }); + thread = MOShared::startSafeThread([&]{ run(); }); } ~ThreadInfo() diff --git a/src/iconfetcher.cpp b/src/iconfetcher.cpp index 129be50e..c10adc8d 100644 --- a/src/iconfetcher.cpp +++ b/src/iconfetcher.cpp @@ -1,4 +1,5 @@ #include "iconfetcher.h" +#include "thread_utils.h" #include "shared/util.h" void IconFetcher::Waiter::wait() @@ -25,7 +26,7 @@ IconFetcher::IconFetcher() m_quickCache.file = getPixmapIcon(QFileIconProvider::File); m_quickCache.directory = getPixmapIcon(QFileIconProvider::Folder); - m_thread = std::thread([&]{ threadFun(); }); + m_thread = MOShared::startSafeThread([&]{ threadFun(); }); } IconFetcher::~IconFetcher() diff --git a/src/main.cpp b/src/main.cpp index 46f2f0aa..f008896b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -127,9 +127,9 @@ bool bootstrap() return true; } -LPTOP_LEVEL_EXCEPTION_FILTER prevUnhandledExceptionFilter = nullptr; +thread_local LPTOP_LEVEL_EXCEPTION_FILTER prevUnhandledExceptionFilter = nullptr; -static LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionPtrs) +LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionPtrs) { const std::wstring& dumpPath = OrganizerCore::crashDumpsPath(); int dumpRes = @@ -139,12 +139,33 @@ static LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *except else log::error("ModOrganizer has crashed, CreateMiniDump failed ({}, error {}).", dumpRes, GetLastError()); - if (prevUnhandledExceptionFilter) + if (prevUnhandledExceptionFilter && exceptionPtrs) return prevUnhandledExceptionFilter(exceptionPtrs); else return EXCEPTION_CONTINUE_SEARCH; } +void terminateHandler() noexcept +{ + __try + { + // force an exception to get a valid stack trace for this thread + *(int*)0 = 42; + } + __except + ( + MyUnhandledExceptionFilter(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER + ) + { + } +} + +void setUnhandledExceptionHandler() +{ + prevUnhandledExceptionFilter = SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); + std::set_terminate(terminateHandler); +} + // 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& parsedArgs) @@ -171,6 +192,7 @@ LPCWSTR UntouchedCommandLineArguments(int parseArgCount, std::vectorproperty("dataPath").toString() + "/logs/mo_interface.log"; diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 062369d6..1e2a0aa1 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -221,7 +221,7 @@ void OrganizerCore::updateExecutablesList() void OrganizerCore::updateModInfoFromDisc() { ModInfo::updateFromDisc( m_Settings.paths().mods(), &m_DirectoryStructure, - m_PluginContainer, m_Settings.interface().displayForeign(), + m_PluginContainer, m_Settings.interface().displayForeign(), m_Settings.refreshThreadCount(), managedGame()); } @@ -371,7 +371,7 @@ void OrganizerCore::downloadRequestedNXM(const QString &url) } } -void OrganizerCore::userInterfaceInitialized() +void OrganizerCore::userInterfaceInitialized() { m_UserInterfaceInitialized(m_UserInterface->mainWindow()); } @@ -1139,7 +1139,7 @@ void OrganizerCore::refreshModList(bool saveChanges) ModInfo::updateFromDisc( m_Settings.paths().mods(), &m_DirectoryStructure, - m_PluginContainer, m_Settings.interface().displayForeign(), + m_PluginContainer, m_Settings.interface().displayForeign(), m_Settings.refreshThreadCount(), managedGame()); m_CurrentProfile->refreshModStatus(); @@ -1473,7 +1473,7 @@ void OrganizerCore::directory_refreshed() m_StructureDeleter.join(); } - m_StructureDeleter = std::thread([=]{ + m_StructureDeleter = MOShared::startSafeThread([=]{ log::debug("structure deleter thread start"); delete newStructure; log::debug("structure deleter thread done"); diff --git a/src/thread_utils.h b/src/thread_utils.h index f0067b6a..607d73a9 100644 --- a/src/thread_utils.h +++ b/src/thread_utils.h @@ -1,12 +1,31 @@ #ifndef MO2_THREAD_UTILS_H #define MO2_THREAD_UTILS_H +#include #include #include #include +// in main.cpp +void setUnhandledExceptionHandler(); +LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionPtrs); + + namespace MOShared { +// starts an std::thread with an unhandled exception handler for core dumps +// and a top-level catch +// +template +std::thread startSafeThread(F&& f) +{ + return std::thread([f=std::forward(f)] { + setUnhandledExceptionHandler(); + f(); + }); +} + + /** * Class that can be used to perform thread-safe memoization. * @@ -26,7 +45,7 @@ struct MemoizedLocked { template MemoizedLocked(Callable &&callable, T value = {}) : m_Fn{ std::forward(callable) }, m_Value{ std::move(value) } { } - + template T& value(Args&&... args) const { if (m_NeedUpdating) { @@ -66,7 +85,7 @@ private: * */ template -void parallelMap(It begin, It end, Callable callable, std::size_t nThreads) +void parallelMap(It begin, It end, Callable callable, std::size_t nThreads) { std::mutex m; std::vector threads(nThreads); @@ -75,7 +94,7 @@ void parallelMap(It begin, It end, Callable callable, std::size_t nThreads) // - The mutex is only used to fetch/increment the iterator. // - The callable is copied in each thread to avoid conflicts. for (auto &thread: threads) { - thread = std::thread([&m, &begin, end, callable]() { + thread = startSafeThread([&m, &begin, end, callable]() { while (true) { decltype(begin) it; { -- cgit v1.3.1 From 6a1d57fe0c3d84f363cd687c7b6813eb947a6050 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 31 Jul 2020 10:01:00 -0400 Subject: fixed bad font scaling --- src/main.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index f008896b..08889018 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -905,9 +905,20 @@ int main(int argc, char *argv[]) if (!tempDir.exists()) tempDir.root().mkpath(tempDir.canonicalPath()); - //Should allow for better scaling of ui with higher resolution displays + + // qt 5.14 changed how fraction font scaling works; by default 125% is + // rounded to 100% and 150% is rounded to 200%, which doesn't make any sense + // + // force qt to use the exact scaling value by change the policy to + // PassThrough + // + QGuiApplication::setHighDpiScaleFactorRoundingPolicy( + Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); + + // MO is somewhat high dpi aware QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + if (argc >= 4) { std::vector arg; auto args = UntouchedCommandLineArguments(2, arg); -- cgit v1.3.1 From 44332c778d326230cb0e45662571de4d0299c9c1 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 31 Jul 2020 11:08:32 -0400 Subject: possible fix for "Network access is disabled" start a timer and change NotAccessible back to UnknownAccessibility --- src/nxmaccessmanager.cpp | 44 ++++++++++++++++++++++++++++++++++++++++---- src/nxmaccessmanager.h | 2 ++ 2 files changed, 42 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp index 2fe676ba..9fe00f88 100644 --- a/src/nxmaccessmanager.cpp +++ b/src/nxmaccessmanager.cpp @@ -772,10 +772,46 @@ NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion) setCookieJar(new PersistentCookieJar(QDir::fromNativeSeparators( Settings::instance().paths().cache() + "/nexus_cookies.dat"))); - if (networkAccessible() == QNetworkAccessManager::UnknownAccessibility) { - // why is this necessary all of a sudden? - setNetworkAccessible(QNetworkAccessManager::Accessible); - } + networkAccessibleFix(); +} + +void NXMAccessManager::networkAccessibleFix() +{ + // Qt 5.14 seems to have introduced a regression with network accessibility + // where some users say MO can't access the network at all + // + // some users use a vpn, one other had a dns resolver + // + // it looks like networkAccessible() is sometimes set to NotAccessible, + // which prevents all network requests from even reaching the OS + // + // there are some events that seem like they should be fired, like + // QNetworkAccessManager::networkAccessibleChanged, but they're not + // + // the only solution that seems to kinda work is just to start a timer, + // check when networkAccessible() is changed to NotAccessible and revert it + // to UnknownAccessibility + // + // see also: + // https://github.com/ModOrganizer2/modorganizer/issues/1173 + // https://bugreports.qt.io/browse/QTBUG-55180 + + // check first + if (networkAccessible() == QNetworkAccessManager::NotAccessible) { + log::debug("network is not accessible, forcing to unknown"); + setNetworkAccessible(QNetworkAccessManager::UnknownAccessibility); + } + + auto* t = new QTimer(this); + + connect(t, &QTimer::timeout, [&]{ + if (networkAccessible() == QNetworkAccessManager::NotAccessible) { + log::debug("network is not accessible, forcing to unknown"); + setNetworkAccessible(QNetworkAccessManager::UnknownAccessibility); + } + }); + + t->start(std::chrono::seconds(1)); } void NXMAccessManager::setTopLevelWidget(QWidget* w) diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h index 6a45d880..f200f595 100644 --- a/src/nxmaccessmanager.h +++ b/src/nxmaccessmanager.h @@ -269,6 +269,8 @@ private: NexusKeyValidator m_validator; States m_validationState; + void networkAccessibleFix(); + void startValidationCheck(const QString& key); void onValidatorFinished( -- cgit v1.3.1 From f71accc1ad4bf2b1de91dfa0c3921fbf6c829191 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 31 Jul 2020 11:09:20 -0400 Subject: bump to 2.3.1 --- src/version.rc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/version.rc b/src/version.rc index b4dff388..8e2000ed 100644 --- a/src/version.rc +++ b/src/version.rc @@ -3,8 +3,8 @@ // If VS_FF_PRERELEASE is not set, MO labels the build as a release and uses VER_FILEVERSION to determine version number. // Otherwise, if letters are used in VER_FILEVERSION_STR, uses the full MOBase::VersionInfo parser // Otherwise, uses the numbers from VER_FILEVERSION and sets the release type as pre-alpha -#define VER_FILEVERSION 2,3,0 -#define VER_FILEVERSION_STR "2.3.0\0" +#define VER_FILEVERSION 2,3,1 +#define VER_FILEVERSION_STR "2.3.1\0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION -- cgit v1.3.1 From 64ba6cae1e6b74929d88de628bb2915cb9c6f2d2 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sat, 1 Aug 2020 11:03:09 -0400 Subject: revert font scaling: - users report low quality splash screen - sticking with qt's default is better in the long run - can still use the environment variable revert network timer: - users report error in log every second - was a blind fix anyway, can't reliably reproduce it --- src/main.cpp | 13 +------------ src/nxmaccessmanager.cpp | 44 ++++---------------------------------------- src/nxmaccessmanager.h | 2 -- 3 files changed, 5 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index 08889018..f008896b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -905,20 +905,9 @@ int main(int argc, char *argv[]) if (!tempDir.exists()) tempDir.root().mkpath(tempDir.canonicalPath()); - - // qt 5.14 changed how fraction font scaling works; by default 125% is - // rounded to 100% and 150% is rounded to 200%, which doesn't make any sense - // - // force qt to use the exact scaling value by change the policy to - // PassThrough - // - QGuiApplication::setHighDpiScaleFactorRoundingPolicy( - Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); - - // MO is somewhat high dpi aware + //Should allow for better scaling of ui with higher resolution displays QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); - if (argc >= 4) { std::vector arg; auto args = UntouchedCommandLineArguments(2, arg); diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp index 9fe00f88..2fe676ba 100644 --- a/src/nxmaccessmanager.cpp +++ b/src/nxmaccessmanager.cpp @@ -772,46 +772,10 @@ NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion) setCookieJar(new PersistentCookieJar(QDir::fromNativeSeparators( Settings::instance().paths().cache() + "/nexus_cookies.dat"))); - networkAccessibleFix(); -} - -void NXMAccessManager::networkAccessibleFix() -{ - // Qt 5.14 seems to have introduced a regression with network accessibility - // where some users say MO can't access the network at all - // - // some users use a vpn, one other had a dns resolver - // - // it looks like networkAccessible() is sometimes set to NotAccessible, - // which prevents all network requests from even reaching the OS - // - // there are some events that seem like they should be fired, like - // QNetworkAccessManager::networkAccessibleChanged, but they're not - // - // the only solution that seems to kinda work is just to start a timer, - // check when networkAccessible() is changed to NotAccessible and revert it - // to UnknownAccessibility - // - // see also: - // https://github.com/ModOrganizer2/modorganizer/issues/1173 - // https://bugreports.qt.io/browse/QTBUG-55180 - - // check first - if (networkAccessible() == QNetworkAccessManager::NotAccessible) { - log::debug("network is not accessible, forcing to unknown"); - setNetworkAccessible(QNetworkAccessManager::UnknownAccessibility); - } - - auto* t = new QTimer(this); - - connect(t, &QTimer::timeout, [&]{ - if (networkAccessible() == QNetworkAccessManager::NotAccessible) { - log::debug("network is not accessible, forcing to unknown"); - setNetworkAccessible(QNetworkAccessManager::UnknownAccessibility); - } - }); - - t->start(std::chrono::seconds(1)); + if (networkAccessible() == QNetworkAccessManager::UnknownAccessibility) { + // why is this necessary all of a sudden? + setNetworkAccessible(QNetworkAccessManager::Accessible); + } } void NXMAccessManager::setTopLevelWidget(QWidget* w) diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h index f200f595..6a45d880 100644 --- a/src/nxmaccessmanager.h +++ b/src/nxmaccessmanager.h @@ -269,8 +269,6 @@ private: NexusKeyValidator m_validator; States m_validationState; - void networkAccessibleFix(); - void startValidationCheck(const QString& key); void onValidatorFinished( -- cgit v1.3.1