一、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目錄。