From 16efa6e5b5f407f5000aa598792b18e4961b2c69 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 18 Dec 2025 16:30:06 +0000 Subject: [PATCH 1/3] Support long paths on Windows Apparently we'd never bothered opting in, despite nearly everything in all out apps being entirely compatible and designed with long paths in mind. GetModuleFileNameW is a bit awkward as it's just about the only Win32 function that returns the minimum of the buffer size and the string size - nearly everything else returns the full size even if it won't fit, so you can pass it a null pointer and a size of zero, and it'll tell you how much space you need to allocate. I pretty much just copied the mostly-working long-path-friendly call site in the crash catcher to windowspath.cpp, but I also noticed that if the function failed and returned zero, the original implementation would loop forever, so I fixed that. There was some code that could be ditched from the catch monitor as \\?\ is a prefix you can use to opt into long paths for a single API call instead of using the manifest to set it everywhere. --- apps/benchmarks/detournavigator/CMakeLists.txt | 4 ++++ apps/benchmarks/esm/CMakeLists.txt | 4 ++++ apps/benchmarks/settings/CMakeLists.txt | 4 ++++ apps/bsatool/CMakeLists.txt | 4 ++++ apps/bulletobjecttool/CMakeLists.txt | 4 ++++ apps/components_tests/CMakeLists.txt | 4 ++++ apps/esmtool/CMakeLists.txt | 4 ++++ apps/essimporter/CMakeLists.txt | 4 ++++ apps/launcher/CMakeLists.txt | 4 ++++ apps/mwiniimporter/CMakeLists.txt | 4 ++++ apps/navmeshtool/CMakeLists.txt | 4 ++++ apps/niftest/CMakeLists.txt | 4 ++++ apps/opencs/CMakeLists.txt | 2 +- apps/opencs_tests/CMakeLists.txt | 4 ++++ apps/openmw_tests/CMakeLists.txt | 4 ++++ apps/wizard/CMakeLists.txt | 4 ++++ components/crashcatcher/windowscrashcatcher.cpp | 2 +- components/crashcatcher/windowscrashmonitor.cpp | 3 --- files/windows/openmw.exe.manifest | 5 +++-- .../windows/{openmw-cs.exe.manifest => other-apps.manifest} | 1 + 20 files changed, 66 insertions(+), 7 deletions(-) rename files/windows/{openmw-cs.exe.manifest => other-apps.manifest} (82%) diff --git a/apps/benchmarks/detournavigator/CMakeLists.txt b/apps/benchmarks/detournavigator/CMakeLists.txt index ffe7818a5a..626eaa38bc 100644 --- a/apps/benchmarks/detournavigator/CMakeLists.txt +++ b/apps/benchmarks/detournavigator/CMakeLists.txt @@ -13,3 +13,7 @@ if (BUILD_WITH_CODE_COVERAGE) target_compile_options(openmw_detournavigator_navmeshtilescache_benchmark PRIVATE --coverage) target_link_libraries(openmw_detournavigator_navmeshtilescache_benchmark gcov) endif() + +if (WIN32) + target_sources(openmw_detournavigator_navmeshtilescache_benchmark PRIVATE ${CMAKE_SOURCE_DIR}/files/windows/other-apps.manifest) +endif() diff --git a/apps/benchmarks/esm/CMakeLists.txt b/apps/benchmarks/esm/CMakeLists.txt index 9b5afd649d..b7dccad2de 100644 --- a/apps/benchmarks/esm/CMakeLists.txt +++ b/apps/benchmarks/esm/CMakeLists.txt @@ -13,3 +13,7 @@ if (BUILD_WITH_CODE_COVERAGE) target_compile_options(openmw_esm_refid_benchmark PRIVATE --coverage) target_link_libraries(openmw_esm_refid_benchmark gcov) endif() + +if (WIN32) + target_sources(openmw_esm_refid_benchmark PRIVATE ${CMAKE_SOURCE_DIR}/files/windows/other-apps.manifest) +endif() diff --git a/apps/benchmarks/settings/CMakeLists.txt b/apps/benchmarks/settings/CMakeLists.txt index 51e2d2b0fd..54a06b8fbc 100644 --- a/apps/benchmarks/settings/CMakeLists.txt +++ b/apps/benchmarks/settings/CMakeLists.txt @@ -16,3 +16,7 @@ if (BUILD_WITH_CODE_COVERAGE) target_compile_options(openmw_settings_access_benchmark PRIVATE --coverage) target_link_libraries(openmw_settings_access_benchmark gcov) endif() + +if (WIN32) + target_sources(openmw_settings_access_benchmark PRIVATE ${CMAKE_SOURCE_DIR}/files/windows/other-apps.manifest) +endif() diff --git a/apps/bsatool/CMakeLists.txt b/apps/bsatool/CMakeLists.txt index 39065f1410..e7e1eb5e14 100644 --- a/apps/bsatool/CMakeLists.txt +++ b/apps/bsatool/CMakeLists.txt @@ -13,6 +13,10 @@ target_link_libraries(bsatool components ) +if (WIN32) + target_sources(bsatool PRIVATE ${CMAKE_SOURCE_DIR}/files/windows/other-apps.manifest) +endif() + if (BUILD_WITH_CODE_COVERAGE) target_compile_options(bsatool PRIVATE --coverage) target_link_libraries(bsatool gcov) diff --git a/apps/bulletobjecttool/CMakeLists.txt b/apps/bulletobjecttool/CMakeLists.txt index c29915b139..05612dbfd6 100644 --- a/apps/bulletobjecttool/CMakeLists.txt +++ b/apps/bulletobjecttool/CMakeLists.txt @@ -10,6 +10,10 @@ target_link_libraries(openmw-bulletobjecttool components ) +if (WIN32) + target_sources(openmw-bulletobjecttool PRIVATE ${CMAKE_SOURCE_DIR}/files/windows/other-apps.manifest) +endif() + if (BUILD_WITH_CODE_COVERAGE) target_compile_options(openmw-bulletobjecttool PRIVATE --coverage) target_link_libraries(openmw-bulletobjecttool gcov) diff --git a/apps/components_tests/CMakeLists.txt b/apps/components_tests/CMakeLists.txt index 96bee650ae..9372846970 100644 --- a/apps/components_tests/CMakeLists.txt +++ b/apps/components_tests/CMakeLists.txt @@ -107,6 +107,10 @@ target_link_libraries(components-tests components ) +if (WIN32) + target_sources(components-tests PRIVATE ${CMAKE_SOURCE_DIR}/files/windows/other-apps.manifest) +endif() + # Fix for not visible pthreads functions for linker with glibc 2.15 if (UNIX AND NOT APPLE) target_link_libraries(components-tests ${CMAKE_THREAD_LIBS_INIT}) diff --git a/apps/esmtool/CMakeLists.txt b/apps/esmtool/CMakeLists.txt index 963f4f5508..aaed20e062 100644 --- a/apps/esmtool/CMakeLists.txt +++ b/apps/esmtool/CMakeLists.txt @@ -20,6 +20,10 @@ target_link_libraries(esmtool components ) +if (WIN32) + target_sources(esmtool PRIVATE ${CMAKE_SOURCE_DIR}/files/windows/other-apps.manifest) +endif() + if (BUILD_WITH_CODE_COVERAGE) target_compile_options(esmtool PRIVATE --coverage) target_link_libraries(esmtool gcov) diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index d53b48cf96..32f9e98796 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -37,6 +37,10 @@ target_link_libraries(openmw-essimporter components ) +if (WIN32) + target_sources(openmw-essimporter PRIVATE ${CMAKE_SOURCE_DIR}/files/windows/other-apps.manifest) +endif() + if (BUILD_WITH_CODE_COVERAGE) target_compile_options(openmw-essimporter PRIVATE --coverage) target_link_libraries(openmw-essimporter gcov) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 3d9fc6edde..3b37b88102 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -74,6 +74,10 @@ target_link_libraries(openmw-launcher target_link_libraries(openmw-launcher Qt::Widgets Qt::Core Qt::Svg) +if (WIN32) + target_sources(openmw-launcher PRIVATE ${CMAKE_SOURCE_DIR}/files/windows/other-apps.manifest) +endif() + if (BUILD_WITH_CODE_COVERAGE) target_compile_options(openmw-launcher PRIVATE --coverage) target_link_libraries(openmw-launcher gcov) diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index ed88ac0bc4..09aab424a8 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -18,6 +18,10 @@ target_link_libraries(openmw-iniimporter components ) +if (WIN32) + target_sources(openmw-iniimporter PRIVATE ${CMAKE_SOURCE_DIR}/files/windows/other-apps.manifest) +endif() + if (WIN32) INSTALL(TARGETS openmw-iniimporter RUNTIME DESTINATION ".") endif(WIN32) diff --git a/apps/navmeshtool/CMakeLists.txt b/apps/navmeshtool/CMakeLists.txt index f056c93685..8e94b33003 100644 --- a/apps/navmeshtool/CMakeLists.txt +++ b/apps/navmeshtool/CMakeLists.txt @@ -20,6 +20,10 @@ target_link_libraries(openmw-navmeshtool-lib components ) +if (WIN32) + target_sources(openmw-navmeshtool PRIVATE ${CMAKE_SOURCE_DIR}/files/windows/other-apps.manifest) +endif() + if (BUILD_WITH_CODE_COVERAGE) target_compile_options(openmw-navmeshtool PRIVATE --coverage) target_link_libraries(openmw-navmeshtool gcov) diff --git a/apps/niftest/CMakeLists.txt b/apps/niftest/CMakeLists.txt index da2cfac785..42c43242e9 100644 --- a/apps/niftest/CMakeLists.txt +++ b/apps/niftest/CMakeLists.txt @@ -12,6 +12,10 @@ target_link_libraries(niftest components ) +if (WIN32) + target_sources(niftest PRIVATE ${CMAKE_SOURCE_DIR}/files/windows/other-apps.manifest) +endif() + if (BUILD_WITH_CODE_COVERAGE) target_compile_options(niftest PRIVATE --coverage) target_link_libraries(niftest gcov) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 35838970ff..63e5e08a98 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -247,7 +247,7 @@ target_link_libraries(openmw-cs-lib target_link_libraries(openmw-cs-lib Qt::Widgets Qt::Core Qt::Network Qt::OpenGL Qt::OpenGLWidgets Qt::Svg) if (WIN32) - target_sources(openmw-cs PRIVATE ${CMAKE_SOURCE_DIR}/files/windows/openmw-cs.exe.manifest) + target_sources(openmw-cs PRIVATE ${CMAKE_SOURCE_DIR}/files/windows/other-apps.manifest) endif() if (WIN32 AND BUILD_OPENCS) diff --git a/apps/opencs_tests/CMakeLists.txt b/apps/opencs_tests/CMakeLists.txt index 3bf783bb68..0e4e8d5baa 100644 --- a/apps/opencs_tests/CMakeLists.txt +++ b/apps/opencs_tests/CMakeLists.txt @@ -17,6 +17,10 @@ target_link_libraries(openmw-cs-tests PRIVATE GMock::GMock ) +if (WIN32) + target_sources(openmw-cs-tests PRIVATE ${CMAKE_SOURCE_DIR}/files/windows/other-apps.manifest) +endif() + if (UNIX AND NOT APPLE) target_link_libraries(openmw-cs-tests PRIVATE ${CMAKE_THREAD_LIBS_INIT}) endif() diff --git a/apps/openmw_tests/CMakeLists.txt b/apps/openmw_tests/CMakeLists.txt index e9a1aa0f29..31fd812dcd 100644 --- a/apps/openmw_tests/CMakeLists.txt +++ b/apps/openmw_tests/CMakeLists.txt @@ -35,6 +35,10 @@ if (UNIX AND NOT APPLE) target_link_libraries(openmw-tests ${CMAKE_THREAD_LIBS_INIT}) endif() +if (WIN32) + target_sources(openmw-tests PRIVATE ${CMAKE_SOURCE_DIR}/files/windows/other-apps.manifest) +endif() + if (BUILD_WITH_CODE_COVERAGE) target_compile_options(openmw-tests PRIVATE --coverage) target_link_libraries(openmw-tests gcov) diff --git a/apps/wizard/CMakeLists.txt b/apps/wizard/CMakeLists.txt index f19ed0e489..faab1e69e8 100644 --- a/apps/wizard/CMakeLists.txt +++ b/apps/wizard/CMakeLists.txt @@ -78,6 +78,10 @@ if (OPENMW_USE_UNSHIELD) target_link_libraries(openmw-wizard ${LIBUNSHIELD_LIBRARIES}) endif() +if (WIN32) + target_sources(openmw-wizard PRIVATE ${CMAKE_SOURCE_DIR}/files/windows/other-apps.manifest) +endif() + if(DPKG_PROGRAM) INSTALL(TARGETS openmw-wizard RUNTIME DESTINATION games COMPONENT openmw-wizard) endif() diff --git a/components/crashcatcher/windowscrashcatcher.cpp b/components/crashcatcher/windowscrashcatcher.cpp index c89ab9c335..8769f5076d 100644 --- a/components/crashcatcher/windowscrashcatcher.cpp +++ b/components/crashcatcher/windowscrashcatcher.cpp @@ -178,7 +178,7 @@ namespace Crash { executablePath.resize(executablePath.size() + MAX_PATH); copied = GetModuleFileNameW(nullptr, executablePath.data(), static_cast(executablePath.size())); - } while (copied >= executablePath.size()); + } while (GetLastError() == ERROR_INSUFFICIENT_BUFFER); executablePath.resize(copied); writePathToShm(mShm->mStartup.mDumpDirectoryPath, dumpPath); diff --git a/components/crashcatcher/windowscrashmonitor.cpp b/components/crashcatcher/windowscrashmonitor.cpp index de66e20b61..4b2537046c 100644 --- a/components/crashcatcher/windowscrashmonitor.cpp +++ b/components/crashcatcher/windowscrashmonitor.cpp @@ -275,9 +275,6 @@ namespace Crash return; } - if (utf16Path.length() > MAX_PATH) - utf16Path = LR"(\\?\)" + utf16Path; - HANDLE hCrashLog = CreateFileW(utf16Path.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); if (hCrashLog == NULL || hCrashLog == INVALID_HANDLE_VALUE) diff --git a/files/windows/openmw.exe.manifest b/files/windows/openmw.exe.manifest index 4c5d4d2e46..683b6ec708 100644 --- a/files/windows/openmw.exe.manifest +++ b/files/windows/openmw.exe.manifest @@ -10,8 +10,9 @@ - - True + + true + true diff --git a/files/windows/openmw-cs.exe.manifest b/files/windows/other-apps.manifest similarity index 82% rename from files/windows/openmw-cs.exe.manifest rename to files/windows/other-apps.manifest index 3107f64706..f71e5648ab 100644 --- a/files/windows/openmw-cs.exe.manifest +++ b/files/windows/other-apps.manifest @@ -4,6 +4,7 @@ true PerMonitorV2 + true \ No newline at end of file From 18cc753517c9787a3f131aefd05d2be429342a47 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 20 Dec 2025 17:20:18 +0000 Subject: [PATCH 2/3] Add comment highlighting known fragile code We know we can't make the struct bigger as everything caught fire when we gave freeze dumps their own path, and was fixed when we switched to a common directory and just separate filenames. Switching to wchar_t and stopping using UTF-8 here would cause a similar size increase, so similar problems are to be expected. --- components/crashcatcher/windowscrashshm.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/crashcatcher/windowscrashshm.hpp b/components/crashcatcher/windowscrashshm.hpp index 6ac09234ba..1a88f05662 100644 --- a/components/crashcatcher/windowscrashshm.hpp +++ b/components/crashcatcher/windowscrashshm.hpp @@ -40,6 +40,8 @@ namespace Crash HANDLE mSignalApp; HANDLE mSignalMonitor; HANDLE mShmMutex; + // the size defines are in UTF-16 code units, and lots of things use more UTF-8 code units, so this may explode with really long non-ASCII paths + // we can't switch to wchar_t as when we've made this struct bigger in the past, things exploded char mDumpDirectoryPath[MAX_LONG_PATH]; char mCrashDumpFileName[MAX_FILENAME]; char mFreezeDumpFileName[MAX_FILENAME]; From 115ee7a35317d839e62cbb4da4d58a2cd2f6c028 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 20 Dec 2025 17:26:47 +0000 Subject: [PATCH 3/3] c a p i t u l a t e --- components/crashcatcher/windowscrashshm.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/crashcatcher/windowscrashshm.hpp b/components/crashcatcher/windowscrashshm.hpp index 1a88f05662..6b1ea6b816 100644 --- a/components/crashcatcher/windowscrashshm.hpp +++ b/components/crashcatcher/windowscrashshm.hpp @@ -40,7 +40,8 @@ namespace Crash HANDLE mSignalApp; HANDLE mSignalMonitor; HANDLE mShmMutex; - // the size defines are in UTF-16 code units, and lots of things use more UTF-8 code units, so this may explode with really long non-ASCII paths + // the size defines are in UTF-16 code units, and lots of things use more UTF-8 code units, so this may + // explode with really long non-ASCII paths // we can't switch to wchar_t as when we've made this struct bigger in the past, things exploded char mDumpDirectoryPath[MAX_LONG_PATH]; char mCrashDumpFileName[MAX_FILENAME];