Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion include/Game/MiniDump.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
#define MiniDump_h__

#include <Windows.h>
#include <DbgHelp.h>

void WINAPI Create_Dump(PEXCEPTION_POINTERS pException, BOOL File_Flag, BOOL Show_Flag);
long WINAPI Create_Dump_Immediate(LPEXCEPTION_POINTERS pException);

#endif
167 changes: 79 additions & 88 deletions src/Game/MiniDump.cpp
Original file line number Diff line number Diff line change
@@ -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 <string>
#include <iostream>
#include <ctime>

#include <windows.h>
#include <tlhelp32.h>
//#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 <comdef.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

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;
}

19 changes: 4 additions & 15 deletions src/Game/main.cpp
Original file line number Diff line number Diff line change
@@ -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
}