//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); }
此外,如果是服務類型的程序,還可以在異常處理函數中增加自動啟動新實例的功能,以保證服務不間斷。