封装了一个C++类,当程序意外崩溃的时候可以生成dump文件,以便确定错误原因。
头文件:
//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); }; 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() { 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"); 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;}
代码很简单,唯一需要提一下的是下面的一句代码,这个技巧是为了解决当crash_dumper_w32.cpp文件被编译成单独的静态库在程序中使用不起作用的问题。
namespace
{
const bool bPlaceHolder = CrashDumper::_PlaceHolder();
}
之所以在静态库中.cpp中的代码不起作用,是因为没有代码去调用crash_dumper_w32.cpp的代码,链接的时候就被编译器给丢掉了。上面的语句在匿名空间中定义了一个变量,这样,每一个包含它的.cpp文件就“被迫”创建了一个不可访问的bPlaceHolder变量,而该变量又必须使用CrashDumper::_PlaceHolder()函数来初始化。crash_dumper_w32.cpp文件的代码就被强制链接进来了。
此外,如果是服务类型的程序,还可以在异常处理函数中增加自动启动新实例的功能,以保证服务不间断。