一、windows下的崩溃捕获
windows程序当遇到异常,没有try-catch或者try-catch也无法捕获到的异常时,程序就会自动退出。windows系统默认是不产生程序dmp文件的。
dump文件是C++程序发生异常时,保存当时程序运行状态的文件,是调试异常程序重要的方法。
1. 产生dmp的三种方式:
方法一: 使用windows系统api,在要捕获dmp文件的程序代码中添加即可
#include "windows.h" #include "DbgHelp.h" //ANSI转化成UNICODE LPWSTR ANSITOUNICODE(const char* pBuf) { int lenA = lstrlenA(pBuf); int lenW=0; LPWSTR lpszFile; lenW = MultiByteToWideChar(CP_ACP,0,pBuf,lenA,0,0); if(lenW > 0) { lpszFile = SysAllocStringLen(0,lenW); //申请一个指定字符长度的 BSTR 指针,并初始化为一个字符串 MultiByteToWideChar(CP_ACP,0,pBuf,lenA,lpszFile,lenW); // } return lpszFile; } typedef BOOL (WINAPI * MINIDUMP_WRITE_DUMP)( IN HANDLE hProcess, IN DWORD ProcessId, IN HANDLE hFile, IN MINIDUMP_TYPE DumpType, IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL IN PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL IN PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL ); void CreateDumpFile(LPCWSTR 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; MINIDUMP_WRITE_DUMP MiniDumpWriteDump_; HMODULE hDbgHelp = LoadLibrary(ANSITOUNICODE("DBGHELP.DLL")); MiniDumpWriteDump_ = (MINIDUMP_WRITE_DUMP)GetProcAddress(hDbgHelp, "MiniDumpWriteDump"); MiniDumpWriteDump_(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL); CloseHandle(hDumpFile); } // 处理Unhandled Exception的回调函数 LONG ApplicationCrashHandler(EXCEPTION_POINTERS *pException) { QDir temp; QString errorPath; bool exist = temp.exists(QCoreApplication::applicationDirPath()+"/Log"); if(!exist) { bool ok = temp.mkdir(QCoreApplication::applicationDirPath()+"/Log"); if(!ok) //失败 放在执行路径下 errorPath = QCoreApplication::applicationDirPath()+QString("/%1崩溃日志.dmp").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh.mm.ss")); } errorPath = QCoreApplication::applicationDirPath()+QString("/Log/%1崩溃日志.dmp").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh.mm.ss")); // 这里弹出一个错误对话框并退出程序 CreateDumpFile(ANSITOUNICODE(errorPath.toStdString().c_str()), pException); FatalAppExit(-1, ANSITOUNICODE("*** 未知 错误! ***")); return EXCEPTION_EXECUTE_HANDLER; } int main(int argc, char *argv[]) { SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)ApplicationCrashHandler); QApplication a(argc, argv); TestWidget w; w.showMaximized(); return a.exec(); }
将上述代码 可以移植到任何windows程序中使用即可。
方法二: 修改注册表
1. 打开dmp文件生成:
使用管理员权限,执行一下脚本内容,运行后: 任何程序崩溃都会在C:\CrashDump 产生dmp文件(full dmp)。
@echo 启用Dump reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpFolder /t REG_EXPAND_SZ /d "C:\CrashDump" /f reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpType /t REG_DWORD /d 2 /f reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpCount /t REG_DWORD /d 10 /f @echo Dump已经启用

2. 关闭dmp的生成:
管理员权限执行以下脚本修改注册表信息:
@echo 关闭Dump reg delete "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /f @echo Dump已经关闭
3. 注册表中Windows Error Reporting\LocalDumps (WER)下字段说明:
在他下面创建一个项,名字为你要检测的程序名。 此项中需要4个值配置 值:DumpFolder, 类型:REG_EXPAND_SZ - 就是存储dump的位置 值:DumpCount, 类型:REG_DWORD - 最大保留的dump个数,默认为10. 值:DumpType, 类型:REG_DWORD - Dump类型,0:Custom dump, 1: Mini dump, 2: Full dump. 默认值为1 值:CustomDumpFlags, 类型:REG_DWORD - 没怎么用。 启动Windows Error Reporting Server服务 服务启动后如果相应程序出现了崩溃的情况,WER就会自动将Crash Dump保存到指定的目录 注意: (1)Windows Error Reporting Server服务每当触发一次dump,就会变成非启动状态,因此在设置此服务时,应当设置启动类型为自动。 (2)在配置WER时,需要注意的是Count大小的设置,如果dmp文件个数超过Count的个数,会进行滚动覆盖,即新的dmp会覆盖旧的dmp。
方法三:手动创建转储文件
当windows应用程序出现无响应时,可以打开任务管理器,找到无响应的进程,右键选择创建转储文件即可,即生成崩溃对应的dmp文件,该文件一般位于 C:\Users\happy\AppData\Local\Temp目录。