CrashReport,BugReport的核心--创建dump文件

// minidmp.h
#pragma once

#include <windows h="">
#include <imagehlp h="">
#include <stdlib h="">
#include <strsafe 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);
			
			break;
					
		case IncludeModuleCallback:
		case IncludeThreadCallback:
		case ThreadCallback:
		case ThreadExCallback:
			return TRUE;
			
		default:
			break;
	}
	
	return FALSE;
}

//创建Dump文件
inline void CreateMiniDump(EXCEPTION_POINTERS *pep, LPCWSTR strFileName)
{
	HANDLE hFile = CreateFileW(strFileName, 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)0x0000ffff;
		MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &mdei, NULL, &mci);
		CloseHandle(hFile);
	}
}

LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
{
	return NULL;
}

BOOL PreventSetUnhandledExceptionFilter()
{
	HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll"));
	if (hKernel32 ==   NULL)
		return FALSE;
		
	void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter");
	if(pOrgEntry == NULL)
		return FALSE;
		
	unsigned char newJump[ 100 ];
	DWORD dwOrgEntryAddr = (DWORD) pOrgEntry;
	dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp far
	
	void *pNewFunc = &MyDummySetUnhandledExceptionFilter;
	DWORD dwNewEntryAddr = (DWORD) pNewFunc;
	DWORD dwRelativeAddr = dwNewEntryAddr -  dwOrgEntryAddr;
	
	newJump[ 0 ] = 0xE9;  // JMP absolute
	memcpy(&newJump[ 1 ], &dwRelativeAddr, sizeof(pNewFunc));
	SIZE_T bytesWritten;
	BOOL bRet = WriteProcessMemory(GetCurrentProcess(),    pOrgEntry, newJump, sizeof(pNewFunc) + 1, &bytesWritten);
	return bRet;
}


LONG WINAPI UnhandledExceptionFilterEx(struct _EXCEPTION_POINTERS *pException)
{
	WCHAR szPath[MAX_PATH];
	WCHAR szFileName[MAX_PATH];
	WCHAR *szAppName = L"DumpFile";
	HANDLE hDumpFile;
	SYSTEMTIME stLocalTime;
	MINIDUMP_EXCEPTION_INFORMATION ExpParam;
	GetLocalTime( &stLocalTime );
	//GetTempPath( dwBufferSize, szPath );
	GetModuleFileNameW(NULL, szPath, MAX_PATH);
	wchar_t *pstr = wcsrchr(szPath, '\\');
	memset(pstr + 1, 0, 2);
	
	StringCchPrintfW( szFileName, MAX_PATH, L"%s%s", szPath, szAppName );
	CreateDirectoryW( szFileName, NULL );
	StringCchPrintfW( szFileName, MAX_PATH, L"%s%s\\%04d%02d%02d-%02d%02d%02d.dmp", szPath, szAppName,
	                  stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
	                  stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond);
	                  
	CreateMiniDump(pException, szFileName);
	// TODO: 这里可以将dump文件通过邮件发送给开发者,也可以通过http发送给服务端,服务端管理dump文件
	FatalAppExit(-1,  _T("*** Unhandled Exception! ***"));
	
	return EXCEPTION_CONTINUE_SEARCH;
}

//运行异常处理
void RunCrashHandler()
{
	SetUnhandledExceptionFilter(UnhandledExceptionFilterEx);
	PreventSetUnhandledExceptionFilter();
}
// Test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "minidmp.h"

void CrashTest()
{
	strcpy(NULL,"adfadfg");
}

int _tmain(int argc, _TCHAR* argv[])
{
	//设置异常处理回调函数
	RunCrashHandler();

	CrashTest();

	getchar();
	return 0;
}

核心就是这样了,注意点:程序发布时记得带上dbghelp.dll,这个是系统dll,开发机上肯定都会有。剩下的就是把dump文件上传到服务器或者直接使用邮件发到指定邮箱了。

有了dump文件,结合发布版本的pdb文件以及源代码就能很快定位到崩溃点了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值