diff --git a/CMakeLists.txt b/CMakeLists.txt index 736b519..aa8babf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,7 @@ if(NOT STEAMWORKS_SDK_DIR) endif() if (MSVC) - add_compile_options(/W4 /EHa /DNOMINMAX /D_CRT_SECURE_NO_WARNINGS /J) + add_compile_options(/W4 /EHsc /DNOMINMAX /D_CRT_SECURE_NO_WARNINGS /J) set(STANDARD_LIBRARIES "") else() add_compile_options(-Wall -Wextra -Werror -Wno-unused-result -Wno-unused-parameter -Wno-unused-value -Wno-extern-c-compat -funsigned-char) diff --git a/game/console.c b/game/console.c index dc68777..8a0942c 100644 --- a/game/console.c +++ b/game/console.c @@ -5,6 +5,7 @@ #include "../platform/error.h" #include "../platform/platform.h" + #include #define console_max_characters 120 #define console_max_lines 300 @@ -89,6 +90,8 @@ void show_flags(int number,char **flags,char nums) } } + + void spell_group_invis() { int i; @@ -245,6 +248,11 @@ static void console_add_line(const char *line) { console_add_line_s(line, strlen(line)); } +static void crash_task(va_list lst) { + char *c = (char *)0x1; + *c = 1; +} + typedef struct { char *cmd_buffer; const char *command; @@ -645,6 +653,13 @@ static int process_with_params(const char *cmd, const char *args) { return 1; } if (istrcmp(cmd, "crash") == 0) { + if (istrcmp(args,"seh") == 0) { + char *c = (char *)(args - (uintptr_t)args); + *c = 'x'; + } + else if (istrcmp(args, "task") == 0) { + add_task(65536,crash_task); + } throw_exception(args); return 1; } diff --git a/platform/CMakeLists.txt b/platform/CMakeLists.txt index d9daadb..d1216e1 100644 --- a/platform/CMakeLists.txt +++ b/platform/CMakeLists.txt @@ -27,6 +27,7 @@ if(WIN32) target_sources(skeldal_platform PRIVATE windows/save_folder.cpp windows/map_file.cpp + windows/minidump.cpp ) add_executable(skeldal WIN32) target_sources(skeldal PRIVATE diff --git a/platform/legacy_coroutines.cpp b/platform/legacy_coroutines.cpp index 2d76fbd..3520abd 100644 --- a/platform/legacy_coroutines.cpp +++ b/platform/legacy_coroutines.cpp @@ -1,5 +1,6 @@ #include "legacy_coroutines.h" #include "error.h" +#include "seh.h" #include #include @@ -116,7 +117,7 @@ static void broadcast_message(EVENT_MSG *msg) { clean_task_table(); } -static void crash_task_exception() { +/*static void crash_task_exception() { try { throw; } catch (std::exception &e) { @@ -125,7 +126,7 @@ static void crash_task_exception() { display_error("Unhandled exception in task %d: unknown/crash",q_current_task()); } abort(); -} +}*/ int add_task(int stack,TaskerFunctionName fcname,...) { @@ -135,14 +136,12 @@ int add_task(int stack,TaskerFunctionName fcname,...) { va_list args; va_start(args, fcname); new_task->thr = std::thread([&]{ - new_task->resume_flag.wait(false); - new_task->resume_flag = false; - try { + SEH_MONITOR_BEGIN { + new_task->resume_flag.wait(false); + new_task->resume_flag = false; fcname(args); clean_up_current_task(); - } catch (...) { - crash_task_exception(); - } + }SEH_MONITOR_END; }); switch_to_task(new_task); return id; diff --git a/platform/platform.h b/platform/platform.h index 63660d6..3e7c24d 100644 --- a/platform/platform.h +++ b/platform/platform.h @@ -2,9 +2,11 @@ #include #include + #ifndef _SKELDAL_PLATFORM_HEADER_ #define _SKELDAL_PLATFORM_HEADER_ + #define BGSWITCHBIT 0x8000 #ifdef _MSC_VER @@ -124,6 +126,16 @@ typedef int (*LIST_FILES_CALLBACK)(const char *, LIST_FILE_TYPE , size_t, void * int list_files(const char *directory, int type, LIST_FILES_CALLBACK cb, void *ctx); +#define WM_RELOADMAP (WM_APP+215) +#define E_RELOADMAP 40 + +typedef struct _ReloadMapInfo { + const char *fname; + int sektor; + } ReloadMapInfo; + + + #ifdef __cplusplus } #endif @@ -135,14 +147,4 @@ void init_joystick(const INI_CONFIG_SECTION *section); char is_joystick_used(); char is_joystick_enabled(); -#define WM_RELOADMAP (WM_APP+215) -#define E_RELOADMAP 40 - -typedef struct _ReloadMapInfo { - const char *fname; - int sektor; - } ReloadMapInfo; - - - -#endif +#endif \ No newline at end of file diff --git a/platform/seh.h b/platform/seh.h new file mode 100644 index 0000000..ca92af0 --- /dev/null +++ b/platform/seh.h @@ -0,0 +1,10 @@ + +#ifdef _WIN32 + #include "windows/minidump.h" + #define SEH_MONITOR_BEGIN __try + #define SEH_MONITOR_END __except(GenerateMinidumpAndExit(GetExceptionInformation())) {} +#else + #define SEH_TRY + #define SEH_CATCH +#endif + diff --git a/platform/windows/app_start.cpp b/platform/windows/app_start.cpp index 0149e4e..76fc68f 100644 --- a/platform/windows/app_start.cpp +++ b/platform/windows/app_start.cpp @@ -2,6 +2,7 @@ #include "../getopt.h" #include "../platform.h" #include "../error.h" +#include "../seh.h" #include #include #include @@ -108,6 +109,10 @@ int __stdcall WinMain(HINSTANCE,HINSTANCE ,LPSTR, INT) { argv[i][need-1] = 0; } GlobalFree(szArglist); - return main(argc, argv); + int r = -256; + SEH_MONITOR_BEGIN { + r = main(argc, argv); + } SEH_MONITOR_END; + return r; } diff --git a/platform/windows/minidump.cpp b/platform/windows/minidump.cpp new file mode 100644 index 0000000..465b5ca --- /dev/null +++ b/platform/windows/minidump.cpp @@ -0,0 +1,73 @@ +#include "minidump.h" +#include +#include +#include + +#include +#pragma comment(lib, "dbghelp.lib") + + +DWORD WINAPI MessageBoxThread(LPVOID ptr) { + const wchar_t *txt = reinterpret_cast(ptr); + return MessageBoxW(NULL, txt, L"SKELDAL", MB_OK|MB_ICONEXCLAMATION|MB_SYSTEMMODAL|MB_APPLMODAL); +} + +static void MessageBoxAndExit(const wchar_t *msg, const wchar_t *fname) { + DWORD tid; + HANDLE h = CreateThread(NULL, 0, MessageBoxThread, const_cast(msg), 0, &tid); + WaitForSingleObject(h, INFINITE); + if (fname != nullptr) { + STARTUPINFOW si = { sizeof(si) }; + PROCESS_INFORMATION pi; + + wchar_t command[MAX_PATH + 20]; + swprintf_s(command, L"explorer.exe /select,\"%s\"", fname); + if (CreateProcessW(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + } + ExitProcess(256); +} + + +LONG WINAPI GenerateMinidumpAndExit(EXCEPTION_POINTERS* pExceptionInfo) { + wchar_t path[MAX_PATH]; + _wfullpath(path, L"crash-" SKELDAL_VERSION ".dmp", _countof(path)); + HANDLE hFile = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE)) { + MINIDUMP_EXCEPTION_INFORMATION mdei; + mdei.ThreadId = GetCurrentThreadId(); + mdei.ExceptionPointers = pExceptionInfo; + mdei.ClientPointers = FALSE; + + BOOL ret = MiniDumpWriteDump( + GetCurrentProcess(), + GetCurrentProcessId(), + hFile, + static_cast(MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory), + &mdei, + NULL, + NULL); + + CloseHandle(hFile); + if (ret) { + wchar_t msg[MAX_PATH*2]; + swprintf_s(msg,L"Application crashed. The crash report has been stored to the file:\r\n\r\n%s\r\n\r\nPress OK to browse file in explorer",path); + MessageBoxAndExit(msg,path); + return 0; + } + } + { + DWORD error = GetLastError(); + wchar_t msg[MAX_PATH*2]; + swprintf_s(msg,L"Application crashed. Failed to write crash report to the file:\r\n\r\n%s\r\nError: %X", path, error); + MessageBoxAndExit(msg,path); + } + + + + return 0; + +} \ No newline at end of file diff --git a/platform/windows/minidump.h b/platform/windows/minidump.h new file mode 100644 index 0000000..c35b311 --- /dev/null +++ b/platform/windows/minidump.h @@ -0,0 +1,4 @@ +#define WIN32_LEAN_AND_MEAN +#include + +LONG WINAPI GenerateMinidumpAndExit(EXCEPTION_POINTERS* pExceptionInfo); \ No newline at end of file