implement custom window for showing crashlog instead of messagebox

very cool :-)
This commit is contained in:
matcool 2024-07-20 16:28:03 -03:00
parent f86d4db20f
commit 4f321973ac
5 changed files with 230 additions and 4 deletions

View file

@ -335,7 +335,9 @@ if (APPLE)
elseif (WIN32)
add_subdirectory(launcher/windows)
target_link_libraries(${PROJECT_NAME} dbghelp)
target_link_libraries(${PROJECT_NAME} dbghelp comctl32 uxtheme Winmm)
target_compile_definitions(${PROJECT_NAME} PUBLIC ISOLATION_AWARE_ENABLED=1)
if (MSVC)
# disable warnings about CCNode::setID

View file

@ -53,6 +53,11 @@ void crashlog::printMods(std::stringstream& stream) {
}
std::string crashlog::writeCrashlog(geode::Mod* faultyMod, std::string const& info, std::string const& stacktrace, std::string const& registers) {
std::filesystem::path outPath;
return writeCrashlog(faultyMod, info, stacktrace, registers, outPath);
}
std::string crashlog::writeCrashlog(geode::Mod* faultyMod, std::string const& info, std::string const& stacktrace, std::string const& registers, std::filesystem::path& outPath) {
// make sure crashlog directory exists
(void)utils::file::createDirectoryAll(crashlog::getCrashLogDirectory());
@ -94,9 +99,10 @@ std::string crashlog::writeCrashlog(geode::Mod* faultyMod, std::string const& in
printMods(file);
// save actual file
outPath = crashlog::getCrashLogDirectory() / (getDateString(true) + ".log");
std::ofstream actualFile;
actualFile.open(
crashlog::getCrashLogDirectory() / (getDateString(true) + ".log"), std::ios::app
outPath, std::ios::app
);
actualFile << file.rdbuf() << std::flush;
actualFile.close();

View file

@ -33,6 +33,8 @@ namespace crashlog {
std::string GEODE_DLL writeCrashlog(geode::Mod* faultyMod, std::string const& info, std::string const& stacktrace, std::string const& registers);
std::string writeCrashlog(geode::Mod* faultyMod, std::string const& info, std::string const& stacktrace, std::string const& registers, std::filesystem::path& outCrashlogPath);
std::string getDateString(bool filesafe);
void GEODE_DLL printGeodeInfo(std::stringstream& stream);

View file

@ -464,6 +464,7 @@ static std::string getInfo(LPEXCEPTION_POINTERS info, Mod* faultyMod, Mod* suspe
static void handleException(LPEXCEPTION_POINTERS info) {
std::string text;
std::filesystem::path crashlogPath;
// calling SymInitialize from multiple threads can have unexpected behavior, so synchronize this part
static std::mutex symMutex;
@ -492,7 +493,8 @@ static void handleException(LPEXCEPTION_POINTERS info) {
faultyMod,
crashInfo,
stacktrace,
getRegisters(info->ContextRecord)
getRegisters(info->ContextRecord),
crashlogPath
);
if (g_symbolsInitialized) {
@ -500,7 +502,13 @@ static void handleException(LPEXCEPTION_POINTERS info) {
}
}
MessageBoxA(nullptr, text.c_str(), "Geometry Dash Crashed", MB_ICONERROR);
// defined in crashlogWindow.cpp
extern bool showCustomCrashlogWindow(std::string text, std::filesystem::path const& crashlogPath);
if (!showCustomCrashlogWindow(text, crashlogPath)) {
// if the window fails to show, we show a message box instead
MessageBoxA(nullptr, text.c_str(), "Geometry Dash Crashed", MB_ICONERROR);
}
}
static LONG WINAPI exceptionHandler(LPEXCEPTION_POINTERS info) {

View file

@ -0,0 +1,208 @@
#define ISOLATION_AWARE_ENABLED 1
#include <Windows.h>
#include <CommCtrl.h>
#include <Uxtheme.h>
#include <vsstyle.h>
#include <Geode/loader/Log.hpp>
#include <Geode/utils/file.hpp>
#include <Geode/utils/general.hpp>
#include <string>
#include <filesystem>
// comctl32 v6
#pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
enum {
ID_CRASHLOG_TEXT = 101,
ID_BUTTON_CLOSE = 102,
ID_BUTTON_OPEN_FOLDER = 103,
ID_BUTTON_COPY_CLIPBOARD = 104,
};
#define TO_HMENU(x) reinterpret_cast<HMENU>(static_cast<size_t>(x))
namespace layout {
static constexpr int CRASHLOG_FONT_SIZE = 16;
static constexpr int BUTTON_HEIGHT = 30;
static constexpr int BUTTON_WIDTH = 120;
static constexpr int BUTTON_SPACING = 10;
static constexpr int PADDING = 10;
}
// dont judge
std::filesystem::path g_crashlogPath;
std::string g_crashlogText;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_CREATE: {
{
// center the window
RECT desktopRect;
GetClientRect(GetDesktopWindow(), &desktopRect);
RECT windowRect;
GetWindowRect(hwnd, &windowRect);
auto x = desktopRect.right / 2 - (windowRect.right - windowRect.left) / 2;
auto y = desktopRect.bottom / 2 - (windowRect.bottom - windowRect.top) / 2;
SetWindowPos(hwnd, NULL, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
}
auto monoFont = CreateFontA(layout::CRASHLOG_FONT_SIZE, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET,
OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH | FF_DONTCARE, TEXT("Consolas"));
auto guiFont = static_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT));
auto handleText = CreateWindowA(
"EDIT", "Crashlog text goes here", WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | ES_READONLY | ES_AUTOVSCROLL | WS_BORDER,
0, 0, 100, 100,
hwnd, TO_HMENU(ID_CRASHLOG_TEXT), NULL, NULL
);
SendMessage(handleText, WM_SETFONT, WPARAM(monoFont), TRUE);
// does nothing :(
Edit_SetEndOfLine(handleText, EC_ENDOFLINE_LF);
auto button = CreateWindowA(
"BUTTON", "Close",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
0, 0, layout::BUTTON_WIDTH, layout::BUTTON_HEIGHT,
hwnd, TO_HMENU(ID_BUTTON_CLOSE), NULL, NULL
);
SendMessage(button, WM_SETFONT, WPARAM(guiFont), TRUE);
button = CreateWindowA(
"BUTTON", "Open crashlog folder",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
0, 0, layout::BUTTON_WIDTH, layout::BUTTON_HEIGHT,
hwnd, TO_HMENU(ID_BUTTON_OPEN_FOLDER), NULL, NULL
);
SendMessage(button, WM_SETFONT, WPARAM(guiFont), TRUE);
button = CreateWindowA(
"BUTTON", "Copy to clipboard",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
0, 0, layout::BUTTON_WIDTH, layout::BUTTON_HEIGHT,
hwnd, TO_HMENU(ID_BUTTON_COPY_CLIPBOARD), NULL, NULL
);
SendMessage(button, WM_SETFONT, WPARAM(guiFont), TRUE);
} break;
case WM_SIZE: {
RECT clientRect;
GetClientRect(hwnd, &clientRect);
SetWindowPos(
GetDlgItem(hwnd, ID_CRASHLOG_TEXT), NULL,
layout::PADDING, layout::PADDING,
clientRect.right - layout::PADDING * 2, clientRect.bottom - layout::BUTTON_HEIGHT - layout::PADDING * 3,
SWP_NOZORDER
);
auto buttonY = clientRect.bottom - layout::BUTTON_HEIGHT - layout::PADDING;
SetWindowPos(
GetDlgItem(hwnd, ID_BUTTON_COPY_CLIPBOARD), NULL,
layout::PADDING, buttonY,
0, 0,
SWP_NOZORDER | SWP_NOSIZE
);
SetWindowPos(
GetDlgItem(hwnd, ID_BUTTON_CLOSE), NULL,
clientRect.right - layout::BUTTON_WIDTH - layout::PADDING, buttonY,
0, 0,
SWP_NOZORDER | SWP_NOSIZE
);
SetWindowPos(
GetDlgItem(hwnd, ID_BUTTON_OPEN_FOLDER), NULL,
clientRect.right - layout::BUTTON_WIDTH * 2 - layout::BUTTON_SPACING - layout::PADDING, buttonY,
0, 0,
SWP_NOZORDER | SWP_NOSIZE
);
} break;
case WM_CTLCOLORSTATIC: {
return (LRESULT)(COLOR_WINDOWFRAME);
} break;
case WM_COMMAND: {
auto id = LOWORD(wParam);
if (id == ID_BUTTON_CLOSE) {
DestroyWindow(hwnd);
} else if (id == ID_BUTTON_OPEN_FOLDER) {
geode::utils::file::openFolder(g_crashlogPath);
} else if (id == ID_BUTTON_COPY_CLIPBOARD) {
geode::utils::clipboard::write(g_crashlogText);
}
} break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
bool showCustomCrashlogWindow(std::string text, std::filesystem::path const& crashlogPath) {
static constexpr auto WINDOW_CLASS_NAME = "GeodeCrashHandlerWindow";
g_crashlogPath = crashlogPath;
g_crashlogText = text;
// i cant get the edit control to use LF, so just replace them myself :-)
for (int i = 0; i < text.size(); ++i) {
auto c = text[i];
if (c == '\n') {
text.insert(text.begin() + i, '\r');
++i;
}
}
WNDCLASS wc = {0};
wc.lpfnWndProc = &WndProc;
wc.hInstance = GetModuleHandleA(NULL);
wc.lpszClassName = WINDOW_CLASS_NAME;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
if (!RegisterClass(&wc)) {
return false;
}
auto hwnd = CreateWindowExA(
0,
WINDOW_CLASS_NAME,
"Geode Crash Handler",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,
NULL, NULL, wc.hInstance, NULL
);
if (hwnd == NULL) {
return false;
}
SetWindowTextA(GetDlgItem(hwnd, ID_CRASHLOG_TEXT), text.c_str());
ShowWindow(hwnd, SW_SHOWNORMAL);
PlaySound((LPCTSTR)SND_ALIAS_SYSTEMDEFAULT, NULL, SND_ASYNC | SND_ALIAS_ID);
UpdateWindow(hwnd);
MSG message;
while (GetMessage(&message, NULL, 0, 0) > 0) {
TranslateMessage(&message);
DispatchMessage(&message);
}
return true;
}