MFC程序自动生成dump Windbg文件
在客户机器上如何得到应该程序的详细出错信息, 这里使用drwtsn32,在应用程序崩溃的时候自动将调用栈的信息以文件形式保存在磁盘。
生成dump有drwtsn32, NTSD,CDB等多种工具,drwtsn32 于系统自带。
在项目中使用以下几个步骤:
1. 创建minidmp.h
minidmp.h
#pragma once
#include <windows.h>
#include <imagehlp.h>
#include <stdlib.h>
#pragma comment(lib, "dbghelp.lib")
inline BOOL IsDataSectionNeeded(const WCHAR* pModuleName)
{
if(pModuleName == 0)
{
return FALSE;
}
WCHAR szFileName[_MAX_FNAME] = L"";
_wsplitpath(pModuleName, NULL, NULL, szFileName, NULL);
if(wcsicmp(szFileName, L"ntdll") == 0)
return TRUE;
return FALSE;
}
inline BOOL CALLBACK MiniDumpCallback(PVOID pParam,
const PMINIDUMP_CALLBACK_INPUT pInput,
PMINIDUMP_CALLBACK_OUTPUT pOutput)
{
if(pInput == 0 || pOutput == 0)
return FALSE;
switch(pInput->CallbackType)
{
case ModuleCallback:
if(pOutput->ModuleWriteFlags & ModuleWriteDataSeg)
if(!IsDataSectionNeeded(pInput->Module.FullPath))
pOutput->ModuleWriteFlags &= (~ModuleWriteDataSeg);
case IncludeModuleCallback:
case IncludeThreadCallback:
case ThreadCallback:
case ThreadExCallback:
return TRUE;
default:;
}
return FALSE;
}
inline void CreateMiniDump(EXCEPTION_POINTERS* pep, LPCTSTR strFileName)
{
HANDLE hFile = CreateFile(strFileName, GENERIC_READ | 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 = pep;
mdei.ClientPointers = FALSE;
MINIDUMP_CALLBACK_INFORMATION mci;
mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;
mci.CallbackParam = 0;
MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)(MiniDumpWithPrivateReadWriteMemory |
MiniDumpWithDataSegs |
MiniDumpWithHandleData |
0x00000800 /*MiniDumpWithFullMemoryInfo*/ |
0x00001000 /*MiniDumpWithThreadInfo*/ |
MiniDumpWithUnloadedModules);
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
hFile, mdt, (pep != 0) ? &mdei : 0, 0, &mci);
CloseHandle(hFile);
}
}
#include <windows.h>
#include <imagehlp.h>
#include <stdlib.h>
#pragma comment(lib, "dbghelp.lib")
inline BOOL IsDataSectionNeeded(const WCHAR* pModuleName)
{
if(pModuleName == 0)
{
return FALSE;
}
WCHAR szFileName[_MAX_FNAME] = L"";
_wsplitpath(pModuleName, NULL, NULL, szFileName, NULL);
if(wcsicmp(szFileName, L"ntdll") == 0)
return TRUE;
return FALSE;
}
inline BOOL CALLBACK MiniDumpCallback(PVOID pParam,
const PMINIDUMP_CALLBACK_INPUT pInput,
PMINIDUMP_CALLBACK_OUTPUT pOutput)
{
if(pInput == 0 || pOutput == 0)
return FALSE;
switch(pInput->CallbackType)
{
case ModuleCallback:
if(pOutput->ModuleWriteFlags & ModuleWriteDataSeg)
if(!IsDataSectionNeeded(pInput->Module.FullPath))
pOutput->ModuleWriteFlags &= (~ModuleWriteDataSeg);
case IncludeModuleCallback:
case IncludeThreadCallback:
case ThreadCallback:
case ThreadExCallback:
return TRUE;
default:;
}
return FALSE;
}
inline void CreateMiniDump(EXCEPTION_POINTERS* pep, LPCTSTR strFileName)
{
HANDLE hFile = CreateFile(strFileName, GENERIC_READ | 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 = pep;
mdei.ClientPointers = FALSE;
MINIDUMP_CALLBACK_INFORMATION mci;
mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;
mci.CallbackParam = 0;
MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)(MiniDumpWithPrivateReadWriteMemory |
MiniDumpWithDataSegs |
MiniDumpWithHandleData |
0x00000800 /*MiniDumpWithFullMemoryInfo*/ |
0x00001000 /*MiniDumpWithThreadInfo*/ |
MiniDumpWithUnloadedModules);
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
hFile, mdt, (pep != 0) ? &mdei : 0, 0, &mci);
CloseHandle(hFile);
}
}
2、 实现UnhandledExceptionFilter
GPTUnhandledExceptionFilter
#include "minidmp.h"
LONG WINAPI GPTUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
{
//得到当前时间
SYSTEMTIME st;
::GetLocalTime(&st);
//得到程序所在文件夹
TCHAR exeFullPath[256]; // MAX_PATH
GetModuleFileName(NULL,exeFullPath,256);//得到程序模块名称,全路径
CString strPath;
DWORD nLoc;
strPath.Format("%s",exeFullPath);
nLoc = strPath.ReverseFind('\\');
strPath.Delete(nLoc+1,strPath.GetLength()-nLoc);
LPSTR szFileName;
wsprintf(szFileName, TEXT("%sERLOG_%04d%02d%02d%02d%02d%02d%02d%02d.dmp"),strPath, st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, rand()%100);
CreateMiniDump(pExceptionInfo, szFileName);
std::cerr << "未知错误:" << (*pExceptionInfo->ExceptionRecord) << std::endl;
exit(pExceptionInfo->ExceptionRecord->ExceptionCode);
return EXCEPTION_EXECUTE_HANDLER; // 程序停止运行
}
LONG WINAPI GPTUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
{
//得到当前时间
SYSTEMTIME st;
::GetLocalTime(&st);
//得到程序所在文件夹
TCHAR exeFullPath[256]; // MAX_PATH
GetModuleFileName(NULL,exeFullPath,256);//得到程序模块名称,全路径
CString strPath;
DWORD nLoc;
strPath.Format("%s",exeFullPath);
nLoc = strPath.ReverseFind('\\');
strPath.Delete(nLoc+1,strPath.GetLength()-nLoc);
LPSTR szFileName;
wsprintf(szFileName, TEXT("%sERLOG_%04d%02d%02d%02d%02d%02d%02d%02d.dmp"),strPath, st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, rand()%100);
CreateMiniDump(pExceptionInfo, szFileName);
std::cerr << "未知错误:" << (*pExceptionInfo->ExceptionRecord) << std::endl;
exit(pExceptionInfo->ExceptionRecord->ExceptionCode);
return EXCEPTION_EXECUTE_HANDLER; // 程序停止运行
}
3. 在异常发生之前调用SetUnhandledExceptionFilter(GPTUnhandledExceptionFilter); 通常在Main()函数开始时调用即可。
注:必需有dbghlp.dll