zoukankan      html  css  js  c++  java
  • [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
    }
    



  • 相关阅读:
    MySql控制台命令
    MySql笔记
    Unity打包android时会出的一些问题
    Unity3D2017.3.0基于Vuforia 开发AR流程(1)
    基于Unity开发广州幻境的Handy结合HTC Tracker的开发坑
    基于Unity 关于SteamVR中 手柄/Tracker不显示的问题
    使用Socket对序列化数据进行传输(基于C#)
    7. 整数反转
    6. Z 字形变换
    53. 最大子序和
  • 原文地址:https://www.cnblogs.com/mfmdaoyou/p/7132446.html
Copyright © 2011-2022 走看看