Windows程序意外崩溃自动生成Minidump文件


//crash_dumper_w32.h
#ifndef _CRASH_DUMPER_H_ #define _CRASH_DUMPER_H_ #include <windows.h>

class CrashDumper { public: CrashDumper(); ~CrashDumper(); static bool _PlaceHolder(); private: LPTOP_LEVEL_EXCEPTION_FILTER m_OriginalFilter; static LONG WINAPI ExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo); }; //这个技巧是为了解决当crash_dumper_w32.cpp文件被编译成单独的静态库在程序中使用不起作用的问题
namespace { const bool bPlaceHolder = CrashDumper::_PlaceHolder(); } #endif
//crash_dumper_w32.cpp
#include <windows.h> #include <tchar.h> #include <dbghelp.h> #include <string> #include "crash_dumper_w32.h" #ifdef UNICODE #define tstring wstring     
#else       
#define tstring string 
#endif

#pragma comment(lib, "dbghelp.lib") CrashDumper dumper; CrashDumper::CrashDumper() {
    //调用SetUnhandledExceptionFilter注册一个自定义的异常处理回调函数 m_OriginalFilter
= SetUnhandledExceptionFilter(ExceptionFilter); } CrashDumper::~CrashDumper() { SetUnhandledExceptionFilter(m_OriginalFilter); } LONG WINAPI CrashDumper::ExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo) { bool bDumpOK = false; DWORD dwProcess = GetCurrentProcessId(); HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcess); if (hProcess != INVALID_HANDLE_VALUE) { TCHAR szPath[MAX_PATH]; if (GetModuleFileName(NULL, szPath, sizeof(szPath))) { std::tstring strDumpFileName = szPath; strDumpFileName += TEXT(".dmp");
             //CreateFile创建dump文件,调用MiniDumpWriteDump函数往dump文件写异常信息 HANDLE hFile
= CreateFile(strDumpFileName.c_str(), FILE_ALL_ACCESS, 0, NULL, CREATE_ALWAYS, NULL, NULL); if (hFile != INVALID_HANDLE_VALUE) { MINIDUMP_EXCEPTION_INFORMATION exception_information; exception_information.ThreadId = GetCurrentThreadId(); exception_information.ExceptionPointers = ExceptionInfo; exception_information.ClientPointers = TRUE; if (MiniDumpWriteDump(hProcess, dwProcess, hFile, MiniDumpNormal, &exception_information, NULL, NULL)) { bDumpOK = true; } CloseHandle(hFile); } } CloseHandle(hProcess); } if (bDumpOK) MessageBox(NULL, TEXT("本程序遇到未处理的异常,MiniDump文件已经生成在程序的运行目录。"), TEXT("提示"), MB_OK); else MessageBox(NULL, TEXT("本程序遇到未处理的异常,生成MiniDump文件失败。"), TEXT("提示"), MB_OK); return EXCEPTION_EXECUTE_HANDLER; } bool CrashDumper::_PlaceHolder() {return true;}

  之所以在静态库中.cpp中的代码不起作用,是因为没有代码去调用crash_dumper_w32.cpp的代码,链接的时候就被编译器给丢掉了。上面的语句在匿名空间中定义了一个变量,这样,每一个包含它的.cpp文件就“被迫”创建了一个不可访问的bPlaceHolder变量,而该变量又必须使用CrashDumper::_PlaceHolder()函数来初始化。crash_dumper_w32.cpp文件的代码就被强制链接进来了。

  基于MFC的在生成环境下可用的DMP生成:

#pragma once
/**
 *    进程崩溃调试 dump
 */
class  CJG_CrashDumper
{
public:
    CJG_CrashDumper(void);
    ~CJG_CrashDumper(void);
public:
    /**
     *    初始化
     *    改变SEH
     */
    static void Init();
    static LONG ApplicationCrashHandler(EXCEPTION_POINTERS *pException) ;

private:
    // 创建Dump文件
    static void CreateDumpFile(
        LPCTSTR lpstrDumpFilePathName, 
        EXCEPTION_POINTERS *pException
        ) ;
};

  

#include "StdAfx.h"
#include <Windows.h>
#include "JG_CrashDumper.h"
#include <imagehlp.h>
#include <atlstr.h>//20181213Lp使用MFC类型
#pragma comment(lib,"Dbghelp.lib")

CJG_CrashDumper::CJG_CrashDumper(void)
{
}

CJG_CrashDumper::~CJG_CrashDumper(void)
{
}

void CJG_CrashDumper::CreateDumpFile(
    LPCTSTR lpstrDumpFilePathName, 
    EXCEPTION_POINTERS *pException
    )  
{  
    // 创建Dump文件   
    HANDLE hDumpFile = CreateFile(lpstrDumpFilePathName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);  

    // Dump信息    
    MINIDUMP_EXCEPTION_INFORMATION dumpInfo;  
    dumpInfo.ExceptionPointers = pException;  
    dumpInfo.ThreadId = GetCurrentThreadId();  
    dumpInfo.ClientPointers = TRUE;  

    // 写入Dump文件内容     
    MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL);  

    CloseHandle(hDumpFile);  
}

LONG CJG_CrashDumper::ApplicationCrashHandler(EXCEPTION_POINTERS *pException)  
{     
    // 在这里添加处理程序崩溃情况的代码   
    // 现在很多软件都是弹出一个发送错误报告的对话框   
    //    cout << "创建Dump" << endl;
    // 生成Dump文件
    TCHAR tszPath[MAX_PATH] = {0};
    CString strPath;
    CString strTime;
    SYSTEMTIME systime;
    GetSystemTime(&systime);
    GetModuleFileName(NULL,tszPath,sizeof(tszPath)-1);
    strPath = tszPath;
    strPath.MakeLower();    
    strTime.Format(
        _T("%04d%02d%02d%02d%02d%02d.dmp"),
        systime.wYear, systime.wMonth, systime.wDay,
        systime.wHour, systime.wMinute, systime.wSecond);
    strPath.Replace(".exe",strTime);    /*for exe*/    
    strPath.Replace(".dll",strTime);    /*for dll*/

    CreateDumpFile(strPath, pException);
    //    cout << "Dump创建完成" << endl;
    // 这里以弹出一个错误对话框并退出程序为例子   
    // 在工程目录的Debug 
    //FatalAppExit(-1,  _T("这个程序目前挂掉了!"));  
    return EXCEPTION_EXECUTE_HANDLER;  
} 

void CJG_CrashDumper::Init(){
    SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)ApplicationCrashHandler);
}
View Code

 

 

 

  此外,如果是服务类型的程序,还可以在异常处理函数中增加自动启动新实例的功能,以保证服务不间断。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM