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 @@
+