[Windows]_[0基础]_[Release程序的崩溃报告minidump解决方式]


场景:

1. Release的程序崩溃时,崩溃报告能够让开发者查明代码哪里出了问题,用处大大的。

2. 仅仅实用VS的编译器才支持,所以MinGW就无缘了。

3. 使用了未处理异常过滤处理函数.

4. 生成的.dmp文件用zlib库压缩, 用到下面的ZipHelper类,编译时还是须要zlib库和dbghelp.lib

http://blog.csdn.net/infoworld/article/details/41290969


5. 使用方式就是把DbgReport作为app类的成员变量,或者文件范围的全局变量初始化后,在程序执行開始前调用

RegisterCrashFilter

6. 更新: 添加VC CRT异常捕抓. 2015-09-25

參考:

http://blog.csdn.net/limiteee/article/details/8472179



bas_dbg_report.h

#ifndef __BAS_DBG_REPORT
#define __BAS_DBG_REPORT

#include "bas_exp.h"

//1.能够自己改动參数,加入额外信息.
typedef void (*BASReportCallbackFunc)(const wchar_t* dump_zip_path);

class LIB_BASIC BASDbgReport
{
public:
	void RegisterCrashFilter(const wchar_t* dump_path,BASReportCallbackFunc func);

};

#endif


bas_dbg_report.cpp

#include "basic/bas_dbg_report.h"
#include <Windows.h>
#include <DbgHelp.h>

#include "basic/bas_utility_string.h"
#include "basic/bas_wrap_object.h"
#include "basic/bas_utility_zip.h"

static std::wstring gDumpPath;
static std::wstring gDumpZipPath;

static BASReportCallbackFunc gReportCallbackFunc = NULL;

static BOOL IsDataSectionNeeded(const WCHAR* pModuleName)  
{  
    if(pModuleName == NULL)  
    {  
        return FALSE;  
    }  
  
    WCHAR szFileName[_MAX_FNAME] = L"";  
    _wsplitpath(pModuleName, NULL, NULL, szFileName, NULL);  
  
    if(wcsicmp(szFileName, L"ntdll") == 0)  
        return TRUE;  
  
    return FALSE;  
} 

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

static LONG WINAPI TopLevelUnhandledExceptionFilter(PEXCEPTION_POINTERS pExInfo)
{
	HANDLE hFile = ::CreateFile( gDumpPath.c_str(), GENERIC_WRITE, 0, NULL,
			CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if( hFile != INVALID_HANDLE_VALUE)
	{
		MINIDUMP_EXCEPTION_INFORMATION einfo;
		einfo.ThreadId = ::GetCurrentThreadId();
		einfo.ExceptionPointers = pExInfo;
		einfo.ClientPointers = FALSE;

		MINIDUMP_CALLBACK_INFORMATION mci;  
		mci.CallbackRoutine     = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;  
		mci.CallbackParam       = NULL;  

		::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile,MiniDumpNormal,&einfo, NULL, &mci);
		::CloseHandle(hFile);
	}
	//1.压缩dmp文件和其它
	char* utf8 = BASUtilityString::ConvertUnicodeToUtf8(gDumpPath.c_str());
	BASWrapMalloc wm1(utf8);

	BASUtilityZip z;
	z.AddFile(utf8);
	std::string output(utf8);
	output.append(".zip");

	wchar_t* unicode = BASUtilityString::ConvertUtf8ToUnicode(output.c_str());
	BASWrapMalloc wm2(unicode);

	gDumpZipPath.append(unicode);

	z.ToZip(output.c_str());
	if(gReportCallbackFunc)
	{
		gReportCallbackFunc(gDumpZipPath.c_str());
	}
	return EXCEPTION_EXECUTE_HANDLER;
}

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

static BOOL PreventSetUnhandledExceptionFilter()
{
    HMODULE hKernel32 = LoadLibrary(L"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;
  }

void BASDbgReport::RegisterCrashFilter(const wchar_t* dump_path,BASReportCallbackFunc func)
{
#ifndef _DEBUG
	gDumpPath.append(dump_path);
	gReportCallbackFunc = func;
	SetUnhandledExceptionFilter(TopLevelUnhandledExceptionFilter);
	//BOOL bRet = PreventSetUnhandledExceptionFilter(); //这个部分系统会崩溃,临时不使用.
#endif
}



原文地址:https://www.cnblogs.com/mfmdaoyou/p/7132446.html