diff --git a/include/Game/MiniDump.h b/include/Game/MiniDump.h index 4ad4548d..022622a7 100644 --- a/include/Game/MiniDump.h +++ b/include/Game/MiniDump.h @@ -2,7 +2,8 @@ #define MiniDump_h__ #include +#include -void WINAPI Create_Dump(PEXCEPTION_POINTERS pException, BOOL File_Flag, BOOL Show_Flag); +long WINAPI Create_Dump_Immediate(LPEXCEPTION_POINTERS pException); #endif diff --git a/src/Game/MiniDump.cpp b/src/Game/MiniDump.cpp index bd8ee2de..01ed4c90 100644 --- a/src/Game/MiniDump.cpp +++ b/src/Game/MiniDump.cpp @@ -1,110 +1,101 @@ /* - Author: Vladimir Sedach. +Inspired by Original Author: Vladimir Sedach. - Purpose: demo of Call Stack creation by our own means, - and with MiniDumpWriteDump() function of DbgHelp.dll. +Purpose: demo of Call Stack creation by our own means, +and with MiniDumpWriteDump() function of DbgHelp.dll. */ +#include "MiniDump.h" + +#include #include #include - -#include -#include -//#include "dbghelp.h" - -//#define DEBUG_DPRINTF 1 //allow d() -//#include "wfun.h" - -#pragma optimize("y", off) //generate stack frame pointers for all functions - same as /Oy- in the project -#pragma warning(disable: 4200) //nonstandard extension used : zero-sized array in struct/union -#pragma warning(disable: 4100) //unreferenced formal parameter - -// In case you don't have dbghelp.h. -#ifndef _DBGHELP_ - -typedef struct _MINIDUMP_EXCEPTION_INFORMATION { - DWORD ThreadId; - PEXCEPTION_POINTERS ExceptionPointers; - BOOL ClientPointers; -} MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION; - -typedef enum _MINIDUMP_TYPE { - MiniDumpNormal = 0x00000000, - MiniDumpWithDataSegs = 0x00000001, -} MINIDUMP_TYPE; - -typedef BOOL (WINAPI * MINIDUMP_WRITE_DUMP)( - IN HANDLE hProcess, - IN DWORD ProcessId, - IN HANDLE hFile, - IN MINIDUMP_TYPE DumpType, - IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL - IN PVOID UserStreamParam, OPTIONAL - IN PVOID CallbackParam OPTIONAL - ); - -#else - -typedef BOOL (WINAPI * MINIDUMP_WRITE_DUMP)( - IN HANDLE hProcess, - IN DWORD ProcessId, - IN HANDLE hFile, - IN MINIDUMP_TYPE DumpType, - IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL - IN PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL - IN PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL - ); -#endif //#ifndef _DBGHELP_ - -HMODULE hDbgHelp; -MINIDUMP_WRITE_DUMP MiniDumpWriteDump_; - -// Tool Help functions. -typedef HANDLE (WINAPI * CREATE_TOOL_HELP32_SNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID); +#include + +#pragma optimize("y", off) //generate stack frame pointers for all functions - same as /Oy- in the project +#pragma warning(disable: 4200) //nonstandard extension used : zero-sized array in struct/union +#pragma warning(disable: 4100) //unreferenced formal parameter + +typedef BOOL(WINAPI * MINIDUMP_WRITE_DUMP)( + IN HANDLE hProcess, + IN DWORD ProcessId, + IN HANDLE hFile, + IN MINIDUMP_TYPE DumpType, + IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL + IN PVOID UserStreamParam, OPTIONAL + IN PVOID CallbackParam OPTIONAL + ); //************************************************************************************* -void WINAPI Create_Dump(PEXCEPTION_POINTERS pException, BOOL File_Flag, BOOL Show_Flag) +long WINAPI Create_Dump_Immediate(LPEXCEPTION_POINTERS pException) //************************************************************************************* // Create dump. // pException can be either GetExceptionInformation() or NULL. -// If File_Flag = TRUE - write dump files (.dmz and .dmp) with the name of the current process. -// If Show_Flag = TRUE - show message with Get_Exception_Info() dump. { // Try to get MiniDumpWriteDump() address. - hDbgHelp = LoadLibrary("DBGHELP.DLL"); - MiniDumpWriteDump_ = (MINIDUMP_WRITE_DUMP)GetProcAddress(hDbgHelp, "MiniDumpWriteDump"); - - // If MiniDumpWriteDump() of DbgHelp.dll available. - if (MiniDumpWriteDump_) - { - HANDLE hDump_File; - CHAR Dump_Path[MAX_PATH]; + HMODULE hDbgHelp = LoadLibrary("DBGHELP.DLL"); + MINIDUMP_WRITE_DUMP MiniDumpWriteDump_ = (MINIDUMP_WRITE_DUMP)GetProcAddress(hDbgHelp, "MiniDumpWriteDump"); + + // If MiniDumpWriteDump() of DbgHelp.dll available. + if (MiniDumpWriteDump_) { + // Get absolute path of current process: C:/ ... /name.exe + CHAR Dump_Path[MAX_PATH]; + GetModuleFileName(NULL, Dump_Path, sizeof(Dump_Path)); + std::string path(Dump_Path); - GetModuleFileName(NULL, Dump_Path, sizeof(Dump_Path)); //path of current process + // Get current time in a string. std::time_t t = std::time(NULL); char tStr[16]; - std::strftime(tStr, 32, " %a %H-%M-%S", std::localtime(&t)); + std::strftime(tStr, ARRAYSIZE(tStr), " %a %H-%M-%S", std::localtime(&t)); std::string time(tStr); - std::string path(Dump_Path); + // Remove the .exe from path path = path.substr(0, path.length() - 4); - path += time + ".dmp"; - - MINIDUMP_EXCEPTION_INFORMATION M; - M.ThreadId = GetCurrentThreadId(); - M.ExceptionPointers = pException; - M.ClientPointers = 0; - - hDump_File = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - - MiniDumpWriteDump_(GetCurrentProcess(), GetCurrentProcessId(), hDump_File, - MiniDumpNormal, (pException) ? &M : NULL, NULL, NULL); - - CloseHandle(hDump_File); - - std::cout << "Memory dumped to: \"" << path.c_str() << "\""; - MessageBox(NULL, ("Application crashed, memory dumped to: " + path).c_str(), "MiniDump", MB_ICONHAND | MB_OK); + // Add the current time and .dmp + path += "dump" + time + ".dmp"; + + DWORD procId = GetCurrentProcessId(); + DWORD threadId = GetCurrentThreadId(); + + MINIDUMP_EXCEPTION_INFORMATION M; + M.ThreadId = threadId; + M.ExceptionPointers = pException; + M.ClientPointers = TRUE; + + HANDLE hDump_File = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + HANDLE process = GetCurrentProcess(); + + BOOL result = MiniDumpWriteDump_(process, procId, hDump_File + , (MINIDUMP_TYPE)(MiniDumpWithDataSegs | + MiniDumpWithHandleData | + MiniDumpScanMemory | + MiniDumpWithUnloadedModules | + MiniDumpWithIndirectlyReferencedMemory | + MiniDumpWithPrivateReadWriteMemory | + MiniDumpWithFullMemoryInfo | + MiniDumpWithThreadInfo | + MiniDumpIgnoreInaccessibleMemory) + , &M, NULL, NULL); + HRESULT error = (HRESULT)GetLastError(); + + CloseHandle(hDump_File); + if (!result) { + _com_error cErr(error); + HRESULT actualErrorCode = error & 0xFFFF; + char hexErrBuf[16]; + std::sprintf(hexErrBuf, "0x%x", actualErrorCode); + std::cout << "Bad memory dump at: \"" << path.c_str() << "\"" << std::endl + << "because MiniDumpWriteDump failed with error #" << actualErrorCode << " (" << hexErrBuf << "): \"" << cErr.ErrorMessage() << "\"" << std::endl; + MessageBox(NULL, "Application crashed, memory dump failed, but file was created.", "MiniDump", MB_ICONHAND | MB_OK); + } else { + std::cout << "Memory dumped to: \"" << path.c_str() << "\"" << std::endl; + MessageBox(NULL, ("Application crashed, memory dumped to: " + path).c_str(), "MiniDump", MB_ICONHAND | MB_OK); + } } else { - MessageBox(NULL, "Application crashed, memory dump failed.", "MiniDump", MB_ICONHAND | MB_OK); + std::cout << "Memory dump failed because MiniDumpWriteDump is not available." << std::endl; + MessageBox(NULL, "Application crashed, could not create a memory dump.", "MiniDump", MB_ICONHAND | MB_OK); } + + // Basically, terminate the application. + return EXCEPTION_EXECUTE_HANDLER; } diff --git a/src/Game/main.cpp b/src/Game/main.cpp index 3c9b6d38..b94f0b97 100644 --- a/src/Game/main.cpp +++ b/src/Game/main.cpp @@ -1,27 +1,16 @@ #include "Game.h" #include "MiniDump.h" -LONG WINAPI CrashHandler(EXCEPTION_POINTERS* pException); - int main(int argc, char* argv[]) { - ::SetUnhandledExceptionFilter(CrashHandler); + SetUnhandledExceptionFilter(Create_Dump_Immediate); Game game(argc, argv); while (game.Running()) { - PerformanceTimer::StartTimer("Game-Tick"); + PerformanceTimer::StartTimer("Game-Tick"); game.Tick(); - PerformanceTimer::StopTimer("Game-Tick"); + PerformanceTimer::StopTimer("Game-Tick"); } - return 0; + return 0; } - -LONG WINAPI CrashHandler(EXCEPTION_POINTERS* pException) -{ - //Take minidump. path should be bin/TacticalZ.dmp - //Then show MessageBox, and exit application. - Create_Dump(pException, 1, 1); - - return EXCEPTION_EXECUTE_HANDLER;// EXCEPTION_CONTINUE_SEARCH -} \ No newline at end of file