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

