2016-05-04 19:24:41 +02:00
|
|
|
/*****************************************************************************
|
2020-07-21 15:04:34 +02:00
|
|
|
* Copyright (c) 2014-2020 OpenRCT2 developers
|
2016-05-04 19:24:41 +02:00
|
|
|
*
|
2018-06-15 14:07:34 +02:00
|
|
|
* For a complete list of all authors, please refer to contributors.md
|
|
|
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
2016-05-04 19:24:41 +02:00
|
|
|
*
|
2018-06-15 14:07:34 +02:00
|
|
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
2016-05-04 19:24:41 +02:00
|
|
|
*****************************************************************************/
|
|
|
|
|
2018-01-18 13:55:34 +01:00
|
|
|
#include "Crash.h"
|
2016-04-07 00:10:12 +02:00
|
|
|
|
|
|
|
#ifdef USE_BREAKPAD
|
2019-06-27 19:46:03 +02:00
|
|
|
# include <iterator>
|
2018-10-09 23:18:15 +02:00
|
|
|
# include <map>
|
2018-07-21 16:17:06 +02:00
|
|
|
# include <memory>
|
|
|
|
# include <stdio.h>
|
|
|
|
|
|
|
|
# if defined(_WIN32)
|
|
|
|
# include <ShlObj.h>
|
2018-07-17 19:19:53 +02:00
|
|
|
# include <client/windows/handler/exception_handler.h>
|
2018-10-09 23:18:15 +02:00
|
|
|
# include <common/windows/http_upload.h>
|
2018-07-21 16:17:06 +02:00
|
|
|
# include <string>
|
|
|
|
# else
|
|
|
|
# error Breakpad support not implemented yet for this platform
|
|
|
|
# endif
|
|
|
|
|
2020-10-22 04:15:29 +02:00
|
|
|
# include "../Context.h"
|
2020-03-31 23:12:35 +02:00
|
|
|
# include "../Game.h"
|
|
|
|
# include "../OpenRCT2.h"
|
2021-07-25 23:40:19 +02:00
|
|
|
# include "../PlatformEnvironment.h"
|
2018-07-21 16:17:06 +02:00
|
|
|
# include "../Version.h"
|
2018-11-30 12:42:53 +01:00
|
|
|
# include "../config/Config.h"
|
2018-07-21 16:17:06 +02:00
|
|
|
# include "../core/Console.hpp"
|
2020-01-13 19:22:45 +01:00
|
|
|
# include "../core/Guard.hpp"
|
2021-07-25 23:40:19 +02:00
|
|
|
# include "../core/Path.hpp"
|
2018-10-09 23:18:15 +02:00
|
|
|
# include "../core/String.hpp"
|
2019-01-31 23:24:07 +01:00
|
|
|
# include "../interface/Screenshot.h"
|
2018-07-21 16:17:06 +02:00
|
|
|
# include "../localisation/Language.h"
|
2020-10-22 04:15:29 +02:00
|
|
|
# include "../object/ObjectManager.h"
|
2021-11-26 17:08:48 +01:00
|
|
|
# include "../park/ParkFile.h"
|
2018-07-21 16:17:06 +02:00
|
|
|
# include "../scenario/Scenario.h"
|
2020-10-22 04:15:29 +02:00
|
|
|
# include "../util/SawyerCoding.h"
|
2018-10-20 23:54:59 +02:00
|
|
|
# include "../util/Util.h"
|
2022-02-18 21:57:00 +01:00
|
|
|
# include "Platform.h"
|
2018-07-21 16:17:06 +02:00
|
|
|
|
|
|
|
# define WSZ(x) L"" x
|
|
|
|
|
|
|
|
# ifdef OPENRCT2_COMMIT_SHA1_SHORT
|
2018-06-22 23:04:38 +02:00
|
|
|
const wchar_t* _wszCommitSha1Short = WSZ(OPENRCT2_COMMIT_SHA1_SHORT);
|
2018-07-21 16:17:06 +02:00
|
|
|
# else
|
2018-06-22 23:04:38 +02:00
|
|
|
const wchar_t* _wszCommitSha1Short = WSZ("");
|
2018-07-21 16:17:06 +02:00
|
|
|
# endif
|
2016-08-28 18:17:20 +02:00
|
|
|
|
2016-10-18 13:25:57 +02:00
|
|
|
// OPENRCT2_ARCHITECTURE is required to be defined in version.h
|
2018-06-22 23:04:38 +02:00
|
|
|
const wchar_t* _wszArchitecture = WSZ(OPENRCT2_ARCHITECTURE);
|
|
|
|
|
2022-04-25 20:25:09 +02:00
|
|
|
# define BACKTRACE_TOKEN L"0ca992e20aca116b5e090fd2eaff6e7b5c8225f778fd8f4e77cb077d70329324"
|
2021-03-13 14:11:58 +01:00
|
|
|
|
2021-07-25 23:40:19 +02:00
|
|
|
using namespace OpenRCT2;
|
|
|
|
|
2018-10-20 23:54:59 +02:00
|
|
|
// Note: uploading gzipped crash dumps manually requires specifying
|
|
|
|
// 'Content-Encoding: gzip' header in HTTP request, but we cannot do that,
|
|
|
|
// so just hope the file name with '.gz' suffix is enough.
|
2021-01-10 19:23:35 +01:00
|
|
|
// For docs on uploading to backtrace.io check
|
2018-10-20 23:54:59 +02:00
|
|
|
// https://documentation.backtrace.io/product_integration_minidump_breakpad/
|
2018-11-02 23:34:23 +01:00
|
|
|
static bool UploadMinidump(const std::map<std::wstring, std::wstring>& files, int& error, std::wstring& response)
|
2018-10-09 23:18:15 +02:00
|
|
|
{
|
2021-01-11 22:14:15 +01:00
|
|
|
for (const auto& file : files)
|
2018-11-02 23:34:23 +01:00
|
|
|
{
|
|
|
|
wprintf(L"files[%s] = %s\n", file.first.c_str(), file.second.c_str());
|
|
|
|
}
|
2018-10-20 23:54:59 +02:00
|
|
|
std::wstring url(L"https://openrct2.sp.backtrace.io:6098/"
|
2021-03-13 14:11:58 +01:00
|
|
|
L"post?format=minidump&token=" BACKTRACE_TOKEN);
|
2018-10-09 23:18:15 +02:00
|
|
|
std::map<std::wstring, std::wstring> parameters;
|
|
|
|
parameters[L"product_name"] = L"openrct2";
|
2021-07-25 23:39:39 +02:00
|
|
|
parameters[L"version"] = String::ToWideChar(gVersionInfoFull);
|
2018-10-09 23:18:15 +02:00
|
|
|
// In case of releases this can be empty
|
|
|
|
if (wcslen(_wszCommitSha1Short) > 0)
|
|
|
|
{
|
2018-10-20 23:54:59 +02:00
|
|
|
parameters[L"commit"] = _wszCommitSha1Short;
|
2018-10-09 23:18:15 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-07-23 00:11:12 +02:00
|
|
|
parameters[L"commit"] = String::ToWideChar(gVersionInfoFull);
|
2018-10-09 23:18:15 +02:00
|
|
|
}
|
2020-01-13 19:22:45 +01:00
|
|
|
|
|
|
|
auto assertMsg = Guard::GetLastAssertMessage();
|
2021-09-13 18:47:13 +02:00
|
|
|
if (assertMsg.has_value())
|
2020-01-13 19:22:45 +01:00
|
|
|
{
|
2021-09-13 18:47:13 +02:00
|
|
|
parameters[L"assert_failure"] = String::ToWideChar(assertMsg.value());
|
2020-01-13 19:22:45 +01:00
|
|
|
}
|
|
|
|
|
2018-10-09 23:18:15 +02:00
|
|
|
int timeout = 10000;
|
2020-02-01 22:38:07 +01:00
|
|
|
bool success = google_breakpad::HTTPUpload::SendMultipartPostRequest(url, parameters, files, &timeout, &response, &error);
|
2018-10-09 23:18:15 +02:00
|
|
|
wprintf(L"Success = %d, error = %d, response = %s\n", success, error, response.c_str());
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:04:38 +02:00
|
|
|
static bool OnCrash(
|
2018-07-21 13:51:54 +02:00
|
|
|
const wchar_t* dumpPath, const wchar_t* miniDumpId, void* context, EXCEPTION_POINTERS* exinfo,
|
|
|
|
MDRawAssertionInfo* assertion, bool succeeded)
|
2016-04-10 00:30:10 +02:00
|
|
|
{
|
|
|
|
if (!succeeded)
|
|
|
|
{
|
2018-07-21 11:50:45 +02:00
|
|
|
constexpr const char* DumpFailedMessage = "Failed to create the dump. Please file an issue with OpenRCT2 on GitHub and "
|
|
|
|
"provide latest save, and provide "
|
|
|
|
"information about what you did before the crash occurred.";
|
2016-04-10 00:30:10 +02:00
|
|
|
printf("%s\n", DumpFailedMessage);
|
2016-05-11 13:25:21 +02:00
|
|
|
if (!gOpenRCT2SilentBreakpad)
|
|
|
|
{
|
2017-08-15 10:07:44 +02:00
|
|
|
MessageBoxA(nullptr, DumpFailedMessage, OPENRCT2_NAME, MB_OK | MB_ICONERROR);
|
2016-05-11 13:25:21 +02:00
|
|
|
}
|
2016-04-10 00:30:10 +02:00
|
|
|
return succeeded;
|
|
|
|
}
|
|
|
|
|
2018-11-02 23:34:23 +01:00
|
|
|
std::map<std::wstring, std::wstring> uploadFiles;
|
|
|
|
|
2016-05-02 23:20:36 +02:00
|
|
|
// Get filenames
|
2016-04-10 00:30:10 +02:00
|
|
|
wchar_t dumpFilePath[MAX_PATH];
|
|
|
|
wchar_t saveFilePath[MAX_PATH];
|
2018-11-30 12:42:53 +01:00
|
|
|
wchar_t configFilePath[MAX_PATH];
|
2020-03-31 23:12:35 +02:00
|
|
|
wchar_t recordFilePathNew[MAX_PATH];
|
2019-06-27 19:46:03 +02:00
|
|
|
swprintf_s(dumpFilePath, std::size(dumpFilePath), L"%s\\%s.dmp", dumpPath, miniDumpId);
|
2021-10-27 14:21:14 +02:00
|
|
|
swprintf_s(saveFilePath, std::size(saveFilePath), L"%s\\%s.park", dumpPath, miniDumpId);
|
2019-06-27 19:46:03 +02:00
|
|
|
swprintf_s(configFilePath, std::size(configFilePath), L"%s\\%s.ini", dumpPath, miniDumpId);
|
2021-10-27 14:21:14 +02:00
|
|
|
swprintf_s(recordFilePathNew, std::size(recordFilePathNew), L"%s\\%s.parkrep", dumpPath, miniDumpId);
|
2016-04-10 00:30:10 +02:00
|
|
|
|
2016-05-02 23:20:36 +02:00
|
|
|
wchar_t dumpFilePathNew[MAX_PATH];
|
2018-06-22 23:04:38 +02:00
|
|
|
swprintf_s(
|
2019-06-27 19:46:03 +02:00
|
|
|
dumpFilePathNew, std::size(dumpFilePathNew), L"%s\\%s(%s_%s).dmp", dumpPath, miniDumpId, _wszCommitSha1Short,
|
2018-06-22 23:04:38 +02:00
|
|
|
_wszArchitecture);
|
2018-10-20 23:54:59 +02:00
|
|
|
|
|
|
|
wchar_t dumpFilePathGZIP[MAX_PATH];
|
2019-06-27 19:46:03 +02:00
|
|
|
swprintf_s(dumpFilePathGZIP, std::size(dumpFilePathGZIP), L"%s.gz", dumpFilePathNew);
|
2018-10-20 23:54:59 +02:00
|
|
|
|
2018-11-02 23:34:23 +01:00
|
|
|
// Compress the dump
|
2018-10-20 23:54:59 +02:00
|
|
|
{
|
2018-11-02 23:34:23 +01:00
|
|
|
FILE* input = _wfopen(dumpFilePath, L"rb");
|
|
|
|
FILE* dest = _wfopen(dumpFilePathGZIP, L"wb");
|
|
|
|
|
|
|
|
if (util_gzip_compress(input, dest))
|
|
|
|
{
|
|
|
|
// TODO: enable upload of gzip-compressed dumps once supported on
|
|
|
|
// backtrace.io (uncomment the line below). For now leave compression
|
|
|
|
// on, as GitHub will accept .gz files, even though it does not
|
|
|
|
// advertise it officially.
|
|
|
|
|
|
|
|
/*
|
|
|
|
uploadFiles[L"upload_file_minidump"] = dumpFilePathGZIP;
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
fclose(input);
|
|
|
|
fclose(dest);
|
2018-10-20 23:54:59 +02:00
|
|
|
}
|
|
|
|
|
2020-03-31 23:12:35 +02:00
|
|
|
bool with_record = stop_silent_record();
|
|
|
|
|
2018-10-20 23:54:59 +02:00
|
|
|
// Try to rename the files
|
2016-05-02 23:20:36 +02:00
|
|
|
if (_wrename(dumpFilePath, dumpFilePathNew) == 0)
|
|
|
|
{
|
|
|
|
std::wcscpy(dumpFilePath, dumpFilePathNew);
|
|
|
|
}
|
2018-11-02 23:34:23 +01:00
|
|
|
uploadFiles[L"upload_file_minidump"] = dumpFilePath;
|
2016-05-02 23:20:36 +02:00
|
|
|
|
2018-10-20 23:54:59 +02:00
|
|
|
// Compress to gzip-compatible stream
|
|
|
|
|
2016-05-02 23:20:36 +02:00
|
|
|
// Log information to output
|
2016-05-02 23:50:43 +02:00
|
|
|
wprintf(L"Dump Path: %s\n", dumpPath);
|
|
|
|
wprintf(L"Dump File Path: %s\n", dumpFilePath);
|
2016-04-10 00:30:10 +02:00
|
|
|
wprintf(L"Dump Id: %s\n", miniDumpId);
|
|
|
|
wprintf(L"Version: %s\n", WSZ(OPENRCT2_VERSION));
|
2016-08-28 18:17:20 +02:00
|
|
|
wprintf(L"Commit: %s\n", _wszCommitSha1Short);
|
2016-04-10 00:30:10 +02:00
|
|
|
|
|
|
|
bool savedGameDumped = false;
|
2019-07-22 23:13:08 +02:00
|
|
|
auto saveFilePathUTF8 = String::ToUtf8(saveFilePath);
|
2017-02-08 23:17:01 +01:00
|
|
|
try
|
|
|
|
{
|
2022-03-07 21:40:48 +01:00
|
|
|
PrepareMapForSave();
|
2020-10-22 04:15:29 +02:00
|
|
|
|
|
|
|
// Export all loaded objects to avoid having custom objects missing in the reports.
|
2022-03-07 21:40:48 +01:00
|
|
|
auto exporter = std::make_unique<ParkFileExporter>();
|
2020-10-22 04:15:29 +02:00
|
|
|
auto ctx = OpenRCT2::GetContext();
|
|
|
|
auto& objManager = ctx->GetObjectManager();
|
|
|
|
exporter->ExportObjectsList = objManager.GetPackableObjects();
|
|
|
|
|
2021-10-27 14:21:14 +02:00
|
|
|
exporter->Export(saveFilePathUTF8.c_str());
|
2016-04-10 00:30:10 +02:00
|
|
|
savedGameDumped = true;
|
|
|
|
}
|
2018-06-22 23:04:38 +02:00
|
|
|
catch (const std::exception&)
|
2017-02-08 23:17:01 +01:00
|
|
|
{
|
|
|
|
}
|
2016-04-10 00:30:10 +02:00
|
|
|
|
2018-11-02 23:34:23 +01:00
|
|
|
// Compress the save
|
|
|
|
if (savedGameDumped)
|
|
|
|
{
|
2021-10-27 14:21:14 +02:00
|
|
|
uploadFiles[L"attachment_park.park"] = saveFilePath;
|
2018-11-02 23:34:23 +01:00
|
|
|
}
|
|
|
|
|
2019-07-22 23:13:08 +02:00
|
|
|
auto configFilePathUTF8 = String::ToUtf8(configFilePath);
|
2022-01-29 03:57:31 +01:00
|
|
|
if (config_save(configFilePathUTF8))
|
2018-11-30 12:42:53 +01:00
|
|
|
{
|
|
|
|
uploadFiles[L"attachment_config.ini"] = configFilePath;
|
|
|
|
}
|
|
|
|
|
2019-01-31 23:24:07 +01:00
|
|
|
std::string screenshotPath = screenshot_dump();
|
|
|
|
if (!screenshotPath.empty())
|
|
|
|
{
|
2019-07-23 00:11:12 +02:00
|
|
|
auto screenshotPathW = String::ToWideChar(screenshotPath.c_str());
|
2019-01-31 23:24:07 +01:00
|
|
|
uploadFiles[L"attachment_screenshot.png"] = screenshotPathW;
|
|
|
|
}
|
|
|
|
|
2020-03-31 23:12:35 +02:00
|
|
|
if (with_record)
|
|
|
|
{
|
2021-10-27 14:21:14 +02:00
|
|
|
auto parkReplayPathW = String::ToWideChar(gSilentRecordingName);
|
|
|
|
bool record_copied = CopyFileW(parkReplayPathW.c_str(), recordFilePathNew, true);
|
2020-03-31 23:12:35 +02:00
|
|
|
if (record_copied)
|
|
|
|
{
|
2021-10-27 14:21:14 +02:00
|
|
|
uploadFiles[L"attachment_replay.parkrep"] = recordFilePathNew;
|
2020-03-31 23:12:35 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
with_record = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-11 13:25:21 +02:00
|
|
|
if (gOpenRCT2SilentBreakpad)
|
|
|
|
{
|
2018-10-24 23:50:03 +02:00
|
|
|
int error;
|
|
|
|
std::wstring response;
|
2018-11-02 23:34:23 +01:00
|
|
|
UploadMinidump(uploadFiles, error, response);
|
2016-05-11 13:25:21 +02:00
|
|
|
return succeeded;
|
|
|
|
}
|
2017-02-08 23:17:01 +01:00
|
|
|
|
2018-07-21 11:50:45 +02:00
|
|
|
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 OpenRCT2 on GitHub, and provide "
|
2018-10-09 23:18:15 +02:00
|
|
|
L"the dump and saved game there.\n\nVersion: %s\nCommit: %s\n\n"
|
|
|
|
L"We would like to upload the crash dump for automated analysis, do you agree?\n"
|
|
|
|
L"The automated analysis is done by courtesy of https://backtrace.io/";
|
2016-04-10 00:30:10 +02:00
|
|
|
wchar_t message[MAX_PATH * 2];
|
2018-06-22 23:04:38 +02:00
|
|
|
swprintf_s(message, MessageFormat, dumpFilePath, WSZ(OPENRCT2_VERSION), _wszCommitSha1Short);
|
2016-04-10 00:30:10 +02:00
|
|
|
|
|
|
|
// Cannot use platform_show_messagebox here, it tries to set parent window already dead.
|
2018-10-25 23:18:19 +02:00
|
|
|
int answer = MessageBoxW(nullptr, message, WSZ(OPENRCT2_NAME), MB_YESNO | MB_ICONERROR);
|
2018-10-09 23:18:15 +02:00
|
|
|
if (answer == IDYES)
|
|
|
|
{
|
2018-10-24 23:50:03 +02:00
|
|
|
int error;
|
|
|
|
std::wstring response;
|
2018-11-02 23:34:23 +01:00
|
|
|
bool ok = UploadMinidump(uploadFiles, error, response);
|
2018-10-24 23:50:03 +02:00
|
|
|
if (!ok)
|
|
|
|
{
|
|
|
|
const wchar_t* MessageFormat2 = L"There was a problem while uploading the dump. Please upload it manually to "
|
|
|
|
L"GitHub. It should be highlighted for you once you close this message.\n"
|
2020-04-03 22:48:27 +02:00
|
|
|
L"It might be because you are using outdated build and we have disabled its "
|
|
|
|
L"access token. Make sure you are running recent version.\n"
|
|
|
|
L"Dump file = %s\n"
|
2018-10-24 23:50:03 +02:00
|
|
|
L"Please provide following information as well:\n"
|
|
|
|
L"Error code = %d\n"
|
|
|
|
L"Response = %s";
|
2020-04-03 22:48:27 +02:00
|
|
|
swprintf_s(message, MessageFormat2, dumpFilePath, error, response.c_str());
|
2018-10-25 23:18:19 +02:00
|
|
|
MessageBoxW(nullptr, message, WSZ(OPENRCT2_NAME), MB_OK | MB_ICONERROR);
|
2018-10-24 23:50:03 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-01-10 19:23:35 +01:00
|
|
|
MessageBoxW(nullptr, L"Dump uploaded successfully.", WSZ(OPENRCT2_NAME), MB_OK | MB_ICONINFORMATION);
|
2018-10-24 23:50:03 +02:00
|
|
|
}
|
2018-10-09 23:18:15 +02:00
|
|
|
}
|
2017-08-15 10:07:44 +02:00
|
|
|
HRESULT coInitializeResult = CoInitialize(nullptr);
|
2016-04-10 00:30:10 +02:00
|
|
|
if (SUCCEEDED(coInitializeResult))
|
|
|
|
{
|
2016-08-28 18:19:13 +02:00
|
|
|
LPITEMIDLIST pidl = ILCreateFromPathW(dumpPath);
|
2020-04-08 20:00:02 +02:00
|
|
|
LPITEMIDLIST files[6];
|
2018-06-20 17:28:51 +02:00
|
|
|
uint32_t numFiles = 0;
|
2016-04-10 00:30:10 +02:00
|
|
|
|
|
|
|
files[numFiles++] = ILCreateFromPathW(dumpFilePath);
|
2018-10-20 23:54:59 +02:00
|
|
|
// There should be no need to check if this file exists, if it doesn't
|
|
|
|
// it simply shouldn't get selected.
|
|
|
|
files[numFiles++] = ILCreateFromPathW(dumpFilePathGZIP);
|
2020-04-08 20:00:02 +02:00
|
|
|
files[numFiles++] = ILCreateFromPathW(configFilePath);
|
2016-04-10 00:30:10 +02:00
|
|
|
if (savedGameDumped)
|
|
|
|
{
|
|
|
|
files[numFiles++] = ILCreateFromPathW(saveFilePath);
|
|
|
|
}
|
2020-03-31 23:12:35 +02:00
|
|
|
if (with_record)
|
|
|
|
{
|
|
|
|
files[numFiles++] = ILCreateFromPathW(recordFilePathNew);
|
|
|
|
}
|
2018-06-22 23:04:38 +02:00
|
|
|
if (pidl != nullptr)
|
|
|
|
{
|
|
|
|
SHOpenFolderAndSelectItems(pidl, numFiles, (LPCITEMIDLIST*)files, 0);
|
2016-04-10 00:30:10 +02:00
|
|
|
ILFree(pidl);
|
2018-06-20 17:28:51 +02:00
|
|
|
for (uint32_t i = 0; i < numFiles; i++)
|
2016-04-10 00:30:10 +02:00
|
|
|
{
|
|
|
|
ILFree(files[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CoUninitialize();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return whether the dump was successful
|
|
|
|
return succeeded;
|
2016-04-09 19:21:40 +02:00
|
|
|
}
|
|
|
|
|
2016-04-10 00:30:10 +02:00
|
|
|
static std::wstring GetDumpDirectory()
|
|
|
|
{
|
2021-07-25 23:40:19 +02:00
|
|
|
auto env = GetContext()->GetPlatformEnvironment();
|
2021-10-05 18:23:06 +02:00
|
|
|
auto crashPath = env->GetDirectoryPath(DIRBASE::USER, DIRID::CRASH);
|
2021-07-25 23:40:19 +02:00
|
|
|
|
2021-10-05 18:23:06 +02:00
|
|
|
auto result = String::ToWideChar(crashPath);
|
2016-04-10 00:30:10 +02:00
|
|
|
return result;
|
2016-04-07 00:10:12 +02:00
|
|
|
}
|
2016-04-10 00:30:10 +02:00
|
|
|
|
|
|
|
// Using non-null pipe name here lets breakpad try setting OOP crash handling
|
2018-06-22 23:04:38 +02:00
|
|
|
constexpr const wchar_t* PipeName = L"openrct2-bpad";
|
2016-04-10 00:30:10 +02:00
|
|
|
|
2016-10-06 23:32:10 +02:00
|
|
|
#endif // USE_BREAKPAD
|
|
|
|
|
2018-02-01 18:49:14 +01:00
|
|
|
CExceptionHandler crash_init()
|
2016-04-07 00:10:12 +02:00
|
|
|
{
|
|
|
|
#ifdef USE_BREAKPAD
|
2016-04-10 00:30:10 +02:00
|
|
|
// Path must exist and be RW!
|
|
|
|
auto exHandler = new google_breakpad::ExceptionHandler(
|
2018-06-22 23:04:38 +02:00
|
|
|
GetDumpDirectory(), 0, OnCrash, 0, google_breakpad::ExceptionHandler::HANDLER_ALL, MiniDumpWithDataSegs, PipeName, 0);
|
2016-04-10 00:30:10 +02:00
|
|
|
return reinterpret_cast<CExceptionHandler>(exHandler);
|
2021-07-25 23:40:19 +02:00
|
|
|
#else // USE_BREAKPAD
|
2016-04-10 00:30:10 +02:00
|
|
|
return nullptr;
|
2016-04-07 00:10:12 +02:00
|
|
|
#endif // USE_BREAKPAD
|
|
|
|
}
|