生產環境程式崩潰時,若能自動生成 MiniDump 文件,事後可用 WinDbg / Visual Studio 進行離線除錯,快速定位崩潰堆疊與變數值。本文提供基於 dbghelp.dll 的完整實現代碼,僅需在程式入口呼叫一次即可啟用。
#include <windows.h>
#include <dbghelp.h>
#include <tchar.h>
#pragma comment(lib, "dbghelp.lib")
LONG WINAPI TopLevelExceptionFilter(struct _EXCEPTION_POINTERS* pExceptionInfo) {
// 1. 組裝 Dump 檔名:版本-日期時間-進程ID-線程ID.dmp
TCHAR szFileName[MAX_PATH] = {0};
TCHAR* szVersion = _T("v1.0");
SYSTEMTIME st; GetLocalTime(&st);
_stprintf_s(szFileName, _T("%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp"),
szVersion, st.wYear, st.wMonth, st.wDay,
st.wHour, st.wMinute, st.wSecond,
GetCurrentProcessId(), GetCurrentThreadId());
// 2. 建立檔案
HANDLE hFile = CreateFile(szFileName, GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) return EXCEPTION_CONTINUE_SEARCH;
// 3. 寫入 MiniDump(含完整記憶體)
MINIDUMP_EXCEPTION_INFORMATION ei;
ei.ThreadId = GetCurrentThreadId();
ei.ExceptionPointers = pExceptionInfo;
ei.ClientPointers = FALSE;
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile,
MiniDumpWithFullMemory, &ei, NULL, NULL);
CloseHandle(hFile);
// getchar(); // 如需暫停觀察可取消註釋
return EXCEPTION_EXECUTE_HANDLER;
}
在 main() / WinMain() 最開頭插入:
SetUnhandledExceptionFilter(TopLevelExceptionFilter);
| 參數 | 含義 |
|---|---|
MiniDumpWithFullMemory | 包含完整進程記憶體,體積較大但資訊最全 |
MiniDumpWithDataSegs | 僅包含資料段,體積較小 |
MiniDumpNormal | 最小集合(堆疊、模組、線程) |
根據磁碟空間與隱私需求選擇適當旗標;生產環境建議 MiniDumpWithDataSegs | MiniDumpWithHandleData 平衡大小與可診斷性。
CreateDirectory 將 Dump 集中存放,避免汙染工作目錄。.pdb 並妥善保存,否則 Dump 難以還原符號。SetUnhandledExceptionFilter 為進程級,所有線程共用;若需區分線程,可在過濾器內記錄 GetCurrentThreadId()。int main() {
SetUnhandledExceptionFilter(TopLevelExceptionFilter);
int* p = nullptr; *p = 1; // 故意觸發 Access Violation
return 0;
}
執行後當前目錄將出現 v1.0-20240115-143022-1234-5678.dmp,拖入 VS 或 WinDbg 即可看到崩潰堆疊。