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