. .pdb .dmp - , .
, , /, .
.dmp, Windows ( , Windows), - :
MiniDumper::Install(
true,
filename,
"Please send a copy of this file, along with a brief description of the problem, to [insert your email address here] so that we might fix this issue."
);
MiniDumper, , :
#pragma once
#include <dbghelp.h>
#include "DynamicLinkLibrary.h"
#include "FileName.h"
class MiniDumper
{
public:
static bool Install(bool bHookUnhandledExceptionFilter, const CFilename & filenameMiniDump, const CString & strCustomizedMessage, DWORD dwMiniDumpType = MiniDumpNormal)
{
return GetSingleton().Initialize(bHookUnhandledExceptionFilter, filenameMiniDump, strCustomizedMessage, dwMiniDumpType);
}
static bool IsInitialized() { return g_bInstalled; }
static bool IsUnhandledExceptionHooked() { return g_bInstalled && GetSingleton().m_bHookedUnhandledExceptionFilter; }
static CFilename GetMiniDumpFilename() { return g_bInstalled ? GetSingleton().m_filenameMiniDump : ""; }
static bool GenerateMiniDump(EXCEPTION_POINTERS * pExceptionPointers);
private:
typedef BOOL (WINAPI * MINIDUMPWRITEDUMP_FUNC_PTR)(
HANDLE hProcess,
DWORD dwPid,
HANDLE hFile,
MINIDUMP_TYPE DumpType,
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);
struct ExceptionThreadData
{
ExceptionThreadData(EXCEPTION_POINTERS * exceptionPointers, bool bUnhandled, DWORD threadID = ::GetCurrentThreadId())
: pExceptionPointers(exceptionPointers)
, dwThreadID(threadID)
, bUnhandledException(bUnhandled)
{
}
EXCEPTION_POINTERS * pExceptionPointers;
DWORD dwThreadID;
bool bUnhandledException;
};
static LONG CALLBACK UnhandledExceptionFilter(EXCEPTION_POINTERS * pExceptionPointers);
static bool ExecuteMiniDumpThread(EXCEPTION_POINTERS * pExceptionPointers, bool bUnhandledException);
static DWORD WINAPI MiniDumpThreadProc(LPVOID lpParam);
static MiniDumper & GetSingleton();
static bool g_bInstalled;
MiniDumper()
: m_pPreviousFilter(NULL)
, m_pWriteMiniDumpFunction(NULL)
, m_bHookedUnhandledExceptionFilter(false)
{
}
bool Initialize(bool bHookUnhandledExceptionFilter, const CFilename & filenameMiniDump, const CString & strCustomizedMessage, DWORD dwMiniDumpType);
bool GenerateMiniDumpFile(ExceptionThreadData * pData);
bool HandleUnhandledException(ExceptionThreadData * pData);
bool m_bHookedUnhandledExceptionFilter;
CFilename m_filenameMiniDump;
CString m_strCustomizedMessage;
DWORD m_dwMiniDumpType;
MINIDUMPWRITEDUMP_FUNC_PTR m_pWriteMiniDumpFunction;
LPTOP_LEVEL_EXCEPTION_FILTER m_pPreviousFilter;
};
:
#include "StdAfx.h"
#include "MiniDumper.h"
using namespace Toolbox;
bool MiniDumper::g_bInstalled = false;
bool MiniDumper::GenerateMiniDump(EXCEPTION_POINTERS * pExceptionPointers)
{
return ExecuteMiniDumpThread(pExceptionPointers, false);
}
LONG CALLBACK MiniDumper::UnhandledExceptionFilter(EXCEPTION_POINTERS * pExceptionPointers)
{
ExecuteMiniDumpThread(pExceptionPointers, true);
::TerminateProcess(GetCurrentProcess(), 0xFFFFFFFF);
return EXCEPTION_CONTINUE_SEARCH;
}
bool MiniDumper::ExecuteMiniDumpThread(EXCEPTION_POINTERS * pExceptionPointers, bool bUnhandledException)
{
ExceptionThreadData data(pExceptionPointers, bUnhandledException);
DWORD dwScratch;
HANDLE hMiniDumpThread = ::CreateThread(NULL, 0, MiniDumpThreadProc, &data, 0, &dwScratch);
if (hMiniDumpThread)
{
VERIFY(::WaitForSingleObject(hMiniDumpThread, INFINITE) == WAIT_OBJECT_0);
VERIFY(::GetExitCodeThread(hMiniDumpThread, &dwScratch));
VERIFY(::CloseHandle(hMiniDumpThread));
return AsBool(dwScratch);
}
return false;
}
DWORD WINAPI MiniDumper::MiniDumpThreadProc(LPVOID lpParam)
{
ExceptionThreadData * pData = (ExceptionThreadData *)lpParam;
if (pData->bUnhandledException)
return GetSingleton().HandleUnhandledException(pData);
else
return GetSingleton().GenerateMiniDumpFile(pData);
}
bool MiniDumper::HandleUnhandledException(ExceptionThreadData * pData)
{
const bool bMiniDumpSucceeded = GenerateMiniDumpFile(pData);
CString strMessage = FString("An Unhandled Exception occurred in %s\n\nUnfortunately, this requires that the application be terminated.", CFilename::GetModuleFilename());
if (bMiniDumpSucceeded)
{
strMessage.AppendFormat("\n\nOn a higher note, we have saved some diagnostic information in %s", m_filenameMiniDump.c_str());
}
if (!IsEmpty(m_strCustomizedMessage))
strMessage.AppendFormat("\n\n%s", m_strCustomizedMessage);
strMessage.Append("\n\nThis application must be terminated now. All unsaved data will be lost. We are deeply sorry for the inconvenience.");
::MessageBox(GetAppWindow(), strMessage, "Internal Error - Unhandled Exception", MB_ICONERROR);
return bMiniDumpSucceeded;
}
MiniDumper & MiniDumper::GetSingleton()
{
static std::auto_ptr<MiniDumper> g_pSingleton(new MiniDumper);
return *g_pSingleton.get();
}
bool MiniDumper::Initialize(bool bHookUnhandledExceptionFilter, const CFilename & filenameMiniDump, const CString & strCustomizedMessage, DWORD dwMiniDumpType)
{
if (!m_pWriteMiniDumpFunction)
{
try
{
DynamicLinkLibrary dll("DBGHelp.dll", true);
m_pWriteMiniDumpFunction = (MINIDUMPWRITEDUMP_FUNC_PTR)dll.GetProcAddress("MiniDumpWriteDump", false);
}
catch (CCustomException &)
{
ASSERT(m_pWriteMiniDumpFunction == NULL);
return false;
}
}
if (!IsEmpty(filenameMiniDump))
m_filenameMiniDump = filenameMiniDump;
m_strCustomizedMessage = strCustomizedMessage;
if (bHookUnhandledExceptionFilter && !m_bHookedUnhandledExceptionFilter)
{
m_pPreviousFilter = ::SetUnhandledExceptionFilter(&MiniDumper::UnhandledExceptionFilter);
}
else if (!bHookUnhandledExceptionFilter && m_bHookedUnhandledExceptionFilter)
{
VERIFY(&MiniDumper::UnhandledExceptionFilter == ::SetUnhandledExceptionFilter(m_pPreviousFilter));
}
m_dwMiniDumpType = dwMiniDumpType;
g_bInstalled = true;
return true;
}
bool MiniDumper::GenerateMiniDumpFile(ExceptionThreadData * pData)
{
ASSERT(g_bInstalled);
if (!g_bInstalled)
return false;
HANDLE hFile = ::CreateFile(m_filenameMiniDump.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return false;
}
else
{
Initialized<_MINIDUMP_EXCEPTION_INFORMATION> ex_info;
ex_info.ThreadId = pData->dwThreadID;
ex_info.ExceptionPointers = pData->pExceptionPointers;
bool bStatus = FALSE != ((*m_pWriteMiniDumpFunction)(GetCurrentProcess(), GetCurrentProcessId(), hFile, (MINIDUMP_TYPE)m_dwMiniDumpType, &ex_info, NULL, NULL));
::CloseHandle(hFile);
return bStatus;
}
}
, . Toolbox. , , , " -" , .dsp, - , .dmp, .pdb ( !), .
- , MSDN .. .. , . , , , .