From ee06e79a2898c1c916fc9b70c06f64dd5cb8b97b Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 10 Feb 2017 09:50:08 +0100 Subject: [PATCH] [Exception] Destroy windows and suspend threads --- src/Components/Modules/Console.cpp | 11 ++++++++--- src/Components/Modules/Console.hpp | 2 ++ src/Components/Modules/Exception.cpp | 27 ++++++++++++++++++++++++--- src/Components/Modules/Exception.hpp | 3 ++- src/Components/Modules/Logger.cpp | 2 +- src/Components/Modules/Window.cpp | 5 +++++ src/Components/Modules/Window.hpp | 2 ++ src/Game/Functions.cpp | 1 + src/Game/Functions.hpp | 3 +++ src/Utils/Utils.cpp | 9 +-------- 10 files changed, 49 insertions(+), 16 deletions(-) diff --git a/src/Components/Modules/Console.cpp b/src/Components/Modules/Console.cpp index 178544fc..2e9881ee 100644 --- a/src/Components/Modules/Console.cpp +++ b/src/Components/Modules/Console.cpp @@ -75,9 +75,9 @@ namespace Components wprintw(Console::InfoWindow, "%s : %d/%d players : map %s", hostname.data(), clientCount, maxclientCount, (mapname.size() ? mapname.data() : "none")); wnoutrefresh(Console::InfoWindow); } - else if(IsWindow(*reinterpret_cast(0x64A3288)) != FALSE) + else if(IsWindow(Console::GetWindow()) != FALSE) { - SetWindowTextA(*reinterpret_cast(0x64A3288), Utils::String::VA("IW4x(" VERSION ") : %s", hostname.data())); + SetWindowTextA(Console::GetWindow(), Utils::String::VA("IW4x(" VERSION ") : %s", hostname.data())); } } @@ -389,7 +389,7 @@ namespace Components Game::Sys_ShowConsole(); MSG message; - while (IsWindow(*reinterpret_cast(0x64A3288)) != FALSE && GetMessageA(&message, nullptr, 0, 0)) + while (IsWindow(Console::GetWindow()) != FALSE && GetMessageA(&message, nullptr, 0, 0)) { TranslateMessage(&message); DispatchMessageA(&message); @@ -494,6 +494,11 @@ namespace Components } } + HWND Console::GetWindow() + { + return *reinterpret_cast(0x64A3288); + } + Game::dvar_t* Console::RegisterConColor(const char* name, float r, float g, float b, float a, float min, float max, int flags, const char* description) { static struct diff --git a/src/Components/Modules/Console.hpp b/src/Components/Modules/Console.hpp index e74bea0c..97a3ed6b 100644 --- a/src/Components/Modules/Console.hpp +++ b/src/Components/Modules/Console.hpp @@ -19,6 +19,8 @@ namespace Components static void FreeNativeConsole(); + static HWND GetWindow(); + private: // Text-based console stuff static WINDOW* OutputWindow; diff --git a/src/Components/Modules/Exception.cpp b/src/Components/Modules/Exception.cpp index 43730a8c..6826babb 100644 --- a/src/Components/Modules/Exception.cpp +++ b/src/Components/Modules/Exception.cpp @@ -15,6 +15,25 @@ namespace Components longjmp(_Buf, _Value); } + void Exception::SuspendProcess() + { + FreeConsole(); + + if (IsWindow(Console::GetWindow()) != FALSE) DestroyWindow(Console::GetWindow()); + if (IsWindow(Window::GetWindow()) != FALSE) DestroyWindow(Window::GetWindow()); + + // This makes sure we either destroy the windows or wait till they are destroyed + MSG msg; + while ((IsWindow(Window::GetWindow()) != FALSE || IsWindow(Console::GetWindow()) != FALSE) && GetMessage(&msg, nullptr, NULL, NULL)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + // This only suspends the main game threads, which is enough for us + Game::Sys_SuspendOtherThreads(); + } + LONG WINAPI Exception::ExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo) { // Pass on harmless errors @@ -34,10 +53,12 @@ namespace Components errorStr = Utils::String::VA("Fatal error (0x%08X) at 0x%08X.", ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo->ExceptionRecord->ExceptionAddress); } + Exception::SuspendProcess(); + bool doFullDump = Flags::HasFlag("bigdumps") || Flags::HasFlag("reallybigdumps"); if (!doFullDump) { - if (MessageBoxA(NULL, + if (MessageBoxA(nullptr, Utils::String::VA("IW4x has encountered an exception and needs to close.\n" "%s\n" // errorStr "Would you like to create a full crash dump for the developers? (this can be almost 100mb)", errorStr), @@ -55,8 +76,8 @@ namespace Components auto minidump = MinidumpUpload::CreateQueuedMinidump(ExceptionInfo, Exception::MiniDumpType); if (!minidump) { - MessageBoxA(NULL, "Minidump Error", - Utils::String::VA("There was an error creating the minidump (%s)! Hit OK to close the program.", Utils::GetLastWindowsError()), MB_OK | MB_ICONERROR); + MessageBoxA(nullptr, "Minidump Error", + Utils::String::VA("There was an error creating the minidump (%s)! Hit OK to close the program.", Utils::GetLastWindowsError().data()), MB_OK | MB_ICONERROR); OutputDebugStringA("Failed to create new minidump!"); Utils::OutputDebugLastError(); TerminateProcess(GetCurrentProcess(), ExceptionInfo->ExceptionRecord->ExceptionCode); diff --git a/src/Components/Modules/Exception.hpp b/src/Components/Modules/Exception.hpp index 3ebdf764..6be64efa 100644 --- a/src/Components/Modules/Exception.hpp +++ b/src/Components/Modules/Exception.hpp @@ -13,14 +13,15 @@ namespace Components #endif static LPTOP_LEVEL_EXCEPTION_FILTER Hook(); - static int MiniDumpType; static void SetMiniDumpType(bool codeseg, bool dataseg); private: + static void SuspendProcess(); static LONG WINAPI ExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo); static LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilterStub(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); static __declspec(noreturn) void ErrorLongJmp(jmp_buf _Buf, int _Value); + static int MiniDumpType; static Utils::Hook SetFilterHook; }; } diff --git a/src/Components/Modules/Logger.cpp b/src/Components/Modules/Logger.cpp index 18b7c06c..f632a6c3 100644 --- a/src/Components/Modules/Logger.cpp +++ b/src/Components/Modules/Logger.cpp @@ -9,7 +9,7 @@ namespace Components bool Logger::IsConsoleReady() { - return (IsWindow(*reinterpret_cast(0x64A3288)) != FALSE || (Dedicated::IsEnabled() && !Flags::HasFlag("console"))); + return (IsWindow(Console::GetWindow()) != FALSE || (Dedicated::IsEnabled() && !Flags::HasFlag("console"))); } void Logger::PrintStub(int channel, const char* message, ...) diff --git a/src/Components/Modules/Window.cpp b/src/Components/Modules/Window.cpp index 05a06d6b..d35eadfa 100644 --- a/src/Components/Modules/Window.cpp +++ b/src/Components/Modules/Window.cpp @@ -61,6 +61,11 @@ namespace Components return ((point.x - rect.left) > 0 && (point.y - rect.top) > 0 && (rect.right - point.x) > 0 && (rect.bottom - point.y) > 0); } + HWND Window::GetWindow() + { + return Window::MainWindow; + } + int Window::IsNoBorder() { return Window::NoBorder.get(); diff --git a/src/Components/Modules/Window.hpp b/src/Components/Modules/Window.hpp index d3e52308..8a9872b3 100644 --- a/src/Components/Modules/Window.hpp +++ b/src/Components/Modules/Window.hpp @@ -20,6 +20,8 @@ namespace Components static bool IsCursorWithin(HWND window); + static HWND GetWindow(); + private: static BOOL CursorVisible; static Dvar::Var NoBorder; diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 2a6a364d..849d26b4 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -244,6 +244,7 @@ namespace Game Sys_IsDatabaseThread_t Sys_IsDatabaseThread = Sys_IsDatabaseThread_t(0x4C6020); Sys_SendPacket_t Sys_SendPacket = Sys_SendPacket_t(0x60FDC0); Sys_ShowConsole_t Sys_ShowConsole = Sys_ShowConsole_t(0x4305E0); + Sys_SuspendOtherThreads_t Sys_SuspendOtherThreads = Sys_SuspendOtherThreads_t(0x45A190); Sys_ListFiles_t Sys_ListFiles = Sys_ListFiles_t(0x45A660); Sys_Milliseconds_t Sys_Milliseconds = Sys_Milliseconds_t(0x42A660); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index cdf1b52d..998f3738 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -598,6 +598,9 @@ namespace Game typedef void(__cdecl * Sys_ShowConsole_t)(); extern Sys_ShowConsole_t Sys_ShowConsole; + typedef void(__cdecl * Sys_SuspendOtherThreads_t)(); + extern Sys_SuspendOtherThreads_t Sys_SuspendOtherThreads; + typedef void(__cdecl * UI_AddMenuList_t)(UiContext *dc, MenuList *menuList, int close); extern UI_AddMenuList_t UI_AddMenuList; diff --git a/src/Utils/Utils.cpp b/src/Utils/Utils.cpp index e0fcfd8b..136a9f7a 100644 --- a/src/Utils/Utils.cpp +++ b/src/Utils/Utils.cpp @@ -26,14 +26,7 @@ namespace Utils void OutputDebugLastError() { DWORD errorMessageID = ::GetLastError(); - LPSTR messageBuffer = nullptr; - size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast(&messageBuffer), 0, nullptr); - std::string message(messageBuffer, size); - - OutputDebugStringA(Utils::String::VA("Last error code: 0x%08X (%s)\n", errorMessageID, message)); - - LocalFree(messageBuffer); + OutputDebugStringA(Utils::String::VA("Last error code: 0x%08X (%s)\n", errorMessageID, GetLastWindowsError().data())); } std::string GetLastWindowsError()