::SetUnhandledExceptionFilter(ExceptionFilter); 是 Windows 編程中用于設置頂層未處理異常過濾器的關鍵 API 調用。它屬于 Windows 結構化異常處理(SEH, Structured Exception Handling)機制的一部分,主要用于捕獲那些未被程序內部處理的異常(如內存訪問違規、除零錯誤等)。以下是詳細說明:
1.函數原型
LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter
);
-
參數 lpTopLevelExceptionFilter:指向用戶自定義的異常處理函數的指針。
-
返回值:舊的頂層異常過濾器函數指針(可保存以便后續恢復)。
2.核心作用
2.1 全局異常捕獲
當程序發生未處理的異常(如崩潰)時,系統會調用通過 SetUnhandledExceptionFilter 注冊的異常處理函數,而不是彈出默認的 Windows 錯誤對話框(如“程序已停止工作”)。
2.2 自定義崩潰處理
開發者可以在自定義的 ExceptionFilter 函數中實現以下操作:
- 記錄崩潰信息(如調用棧、寄存器狀態)。
- 生成 MiniDump 文件(用于后續調試)。
- 執行緊急數據保存或資源釋放。
- 上傳錯誤報告到服務器。
3.參數 ExceptionFilter 的實現
自定義異常處理函數需符合以下簽名:
LONG WINAPI ExceptionFilter(_EXCEPTION_POINTERS* pExceptionInfo);
- 參數 pExceptionInfo:指向 EXCEPTION_POINTERS 結構體的指針,包含異常上下文和記錄信息。
- 返回值:
- EXCEPTION_EXECUTE_HANDLER:系統終止程序。
- EXCEPTION_CONTINUE_SEARCH:系統繼續查找其他異常處理程序(如默認錯誤對話框)。
- EXCEPTION_CONTINUE_EXECUTION:嘗試恢復執行(通常不推薦,可能導致不穩定)。
4.典型使用場景
4.1 記錄崩潰信息
#include <Windows.h>
#include <DbgHelp.h> // 需要鏈接 DbgHelp.lib// 自定義異常處理函數
LONG WINAPI MyExceptionFilter(_EXCEPTION_POINTERS* pExceptionInfo) {// 生成 MiniDump 文件HANDLE hFile = CreateFile(L"crash.dmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);if (hFile != INVALID_HANDLE_VALUE) {MINIDUMP_EXCEPTION_INFORMATION dumpInfo = {0};dumpInfo.ThreadId = GetCurrentThreadId();dumpInfo.ExceptionPointers = pExceptionInfo;dumpInfo.ClientPointers = FALSE;MiniDumpWriteDump(GetCurrentProcess(),GetCurrentProcessId(),hFile,MiniDumpNormal,&dumpInfo,NULL,NULL);CloseHandle(hFile);}return EXCEPTION_EXECUTE_HANDLER; // 終止程序
}int main() {// 設置全局異常過濾器::SetUnhandledExceptionFilter(MyExceptionFilter);// 此處可能觸發崩潰的代碼(示例)int* p = nullptr;*p = 42; // 觸發訪問違規異常return 0;
}
4.2禁止默認錯誤對話框
某些場景下(如后臺服務程序),需禁止彈出系統錯誤對話框:
// 返回 EXCEPTION_EXECUTE_HANDLER 直接終止程序,不彈窗
SetUnhandledExceptionFilter(MyExceptionFilter);
5.注意事項
5.1 多線程安全
SetUnhandledExceptionFilter 是進程全局的,需確保在程序初始化時設置一次,避免多線程競爭。
5.2 第三方庫的覆蓋
某些庫(如某些 C++ 運行時、防病毒軟件)可能會覆蓋你的異常過濾器。可在關鍵位置(如主循環)重復設置。
5.3 異常處理函數的可靠性
- 避免在 ExceptionFilter 中分配內存或調用復雜函數(程序可能已處于不穩定狀態)。
- 直接使用 Win32 API(如 WriteFile)而非 C/C++ 標準庫函數(如 fprintf)。
5.4 與 C++ 異常的區別
- SEH 處理的是系統級異常(如訪問違規),而 try/catch 僅捕獲 C++ 異常(如 throw 語句拋出的異常)。
- 若需同時處理 C++ 異常,需結合 std::set_terminate 或其他機制。
5.5 64 位系統的差異
- 在 64 位 Windows 中,某些異常(如非法指令)可能無法被捕獲,需檢查文檔或使用 Vectored Exception Handling(AddVectoredExceptionHandler)。
6.替代方案
- Vectored Exception Handling (VEH)
通過 AddVectoredExceptionHandler 注冊異常處理函數,可捕獲所有異常(包括已處理的異常)。 - C++ 信號處理
使用 signal 函數處理特定信號(如 SIGSEGV),但功能較為有限。
7.完整示例:生成 MiniDump
#include <Windows.h>
#include <DbgHelp.h>
#pragma comment(lib, "DbgHelp.lib")LONG WINAPI MyExceptionFilter(_EXCEPTION_POINTERS* pExceptionInfo) {HANDLE hFile = CreateFile(L"CrashDump.dmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);if (hFile != INVALID_HANDLE_VALUE) {MINIDUMP_EXCEPTION_INFORMATION dumpInfo = {0};dumpInfo.ThreadId = GetCurrentThreadId();dumpInfo.ExceptionPointers = pExceptionInfo;dumpInfo.ClientPointers = FALSE;MiniDumpWriteDump(GetCurrentProcess(),GetCurrentProcessId(),hFile,MiniDumpWithFullMemory, // 包含完整內存信息&dumpInfo,NULL,NULL);CloseHandle(hFile);}return EXCEPTION_EXECUTE_HANDLER;
}int main() {SetUnhandledExceptionFilter(MyExceptionFilter);// 觸發崩潰的示例代碼volatile int* p = nullptr;*p = 42;return 0;
}
8.總結
::SetUnhandledExceptionFilter(ExceptionFilter); 是 Windows 程序中捕獲未處理異常的核心工具,常用于:
- 生成崩潰轉儲文件(MiniDump)。
- 記錄錯誤日志。
- 優雅終止程序。
使用時需注意異常處理函數的可靠性、線程安全性和潛在覆蓋問題。對于復雜項目,建議結合 Vectored Exception Handling 或第三方崩潰報告庫(如 Google Breakpad)。