[Windows]_[初级]_[Release程序的崩溃报告minidump解决方案]

本文介绍了一种在Release版本程序中实现崩溃报告的机制,该机制可在程序崩溃时收集必要的信息并生成压缩后的崩溃报告文件,帮助开发者快速定位问题。支持未处理异常过滤处理,并通过MiniDumpWriteDump API创建内存转储文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


场景:

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
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Peter(阿斯拉达)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值