//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); }
此外,如果是服务类型的程序,还可以在异常处理函数中增加自动启动新实例的功能,以保证服务不间断。