diff --git a/openloco.common.props b/openloco.common.props index c8013b39..55f048fb 100644 --- a/openloco.common.props +++ b/openloco.common.props @@ -50,7 +50,7 @@ C4549: 'operator': operator before comma has no effect; did you intend 'operator'? C4555: expression has no effect; expected expression with side-effect --> - _CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_USE_MATH_DEFINES;SDL_MAIN_HANDLED;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_USE_MATH_DEFINES;SDL_MAIN_HANDLED;_WINSOCK_DEPRECATED_NO_WARNINGS;USE_BREAKPAD;%(PreprocessorDefinitions) true true /utf-8 /std:c++17 /permissive- diff --git a/src/OpenLoco/OpenLoco.cpp b/src/OpenLoco/OpenLoco.cpp index 4fb4df72..e1c5e34f 100644 --- a/src/OpenLoco/OpenLoco.cpp +++ b/src/OpenLoco/OpenLoco.cpp @@ -46,6 +46,7 @@ #include "MultiPlayer.h" #include "Objects/ObjectManager.h" #include "OpenLoco.h" +#include "Platform/Crash.h" #include "Platform/Platform.h" #include "S5/S5.h" #include "Scenario.h" @@ -1158,6 +1159,7 @@ namespace OpenLoco // 0x00406D13 void main() { + crash_init(); auto versionInfo = OpenLoco::getVersionInfo(); std::cout << versionInfo << std::endl; try diff --git a/src/OpenLoco/Platform/Crash.cpp b/src/OpenLoco/Platform/Crash.cpp new file mode 100644 index 00000000..9571b7e1 --- /dev/null +++ b/src/OpenLoco/Platform/Crash.cpp @@ -0,0 +1,79 @@ +#include "Crash.h" +#if defined(USE_BREAKPAD) +#include "../Utility/String.hpp" +#include "Platform.h" +#include +#include + +#if defined(OPENLOCO_COMMIT_SHA1_SHORT) +const wchar_t* _wszCommitSha1Short = L"" OPENLOCO_COMMIT_SHA1_SHORT; +#else +const wchar_t* _wszCommitSha1Short = L"Unknown"; +#endif + +static bool OnCrash( + const wchar_t* dumpPath, const wchar_t* miniDumpId, void* context, EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion, bool succeeded) +{ + if (!succeeded) + { + constexpr const char* DumpFailedMessage = "Failed to create the dump. Please file an issue with OpenLoco on GitHub and " + "provide latest save, and provide " + "information about what you did before the crash occurred."; + printf("%s\n", DumpFailedMessage); + MessageBoxA(nullptr, DumpFailedMessage, "OpenLoco", MB_OK | MB_ICONERROR); + return succeeded; + } + wchar_t dumpFilePath[MAX_PATH]; + swprintf_s(dumpFilePath, std::size(dumpFilePath), L"%s\\%s.dmp", dumpPath, miniDumpId); + constexpr const wchar_t* MessageFormat = L"A crash has occurred and a dump was created at\n%s.\n\nPlease file an issue " + L"with OpenLoco on GitHub and provide " + L"the dump and saved game there.\n\n\nCommit: %s\n\n"; + wchar_t message[MAX_PATH * 2]; + swprintf_s(message, MessageFormat, dumpFilePath, _wszCommitSha1Short); + MessageBoxW(nullptr, message, L"OpenLoco", MB_OK | MB_ICONERROR); + + HRESULT coInitializeResult = CoInitialize(nullptr); + if (SUCCEEDED(coInitializeResult)) + { + LPITEMIDLIST pidl = ILCreateFromPathW(dumpPath); + LPITEMIDLIST files[6]; + uint32_t numFiles = 0; + + files[numFiles++] = ILCreateFromPathW(dumpFilePath); + if (pidl != nullptr) + { + SHOpenFolderAndSelectItems(pidl, numFiles, (LPCITEMIDLIST*)files, 0); + ILFree(pidl); + for (uint32_t i = 0; i < numFiles; i++) + { + ILFree(files[i]); + } + } + CoUninitialize(); + } + return succeeded; +} + +static std::wstring GetDumpDirectory() +{ + auto user_dir = OpenLoco::platform::getUserDirectory(); + auto result = OpenLoco::Utility::toUtf16(user_dir.string()); + return result; +} +#endif // USE_BREAKPAD + +// Using non-null pipe name here lets breakpad try setting OOP crash handling +constexpr const wchar_t* PipeName = L"openloco-bpad"; + +CExceptionHandler crash_init() +{ +#if defined(USE_BREAKPAD) + // Path must exist and be RW! + auto exHandler = new google_breakpad::ExceptionHandler( + GetDumpDirectory(), 0, OnCrash, 0, google_breakpad::ExceptionHandler::HANDLER_ALL, MiniDumpWithDataSegs, PipeName, 0); + return reinterpret_cast(exHandler); +#else // USE_BREAKPAD + return nullptr; +#endif // USE_BREAKPAD +} diff --git a/src/OpenLoco/Platform/Crash.h b/src/OpenLoco/Platform/Crash.h new file mode 100644 index 00000000..496d5a49 --- /dev/null +++ b/src/OpenLoco/Platform/Crash.h @@ -0,0 +1,3 @@ +#pragma once +using CExceptionHandler = void*; +CExceptionHandler crash_init(); diff --git a/src/OpenLoco/openloco.vcxproj b/src/OpenLoco/openloco.vcxproj index cd5c5ff4..6005840c 100644 --- a/src/OpenLoco/openloco.vcxproj +++ b/src/OpenLoco/openloco.vcxproj @@ -100,6 +100,7 @@ +