總結一下dump文件生成和調試的方法:
1:用SetUnhandledExceptionFilter捕獲未處理的異常,包含頭文件<windows.h>。函數原型為:
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(
__in LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter
);
SetUnhandledExceptionFilter返回值為:The SetUnhandledExceptionFilter function returns the address of the previous exception filter established with the function. A NULL return value means that there is no current top-level exception handler.返回回掉函數的地址。
回掉函數原型為:
1 typedef LONG (WINAPI *PTOP_LEVEL_EXCEPTION_FILTER)( 2 __in struct _EXCEPTION_POINTERS *ExceptionInfo 3 ); 4 typedef PTOP_LEVEL_EXCEPTION_FILTER LPTOP_LEVEL_EXCEPTION_FILTER;
回掉函數須返回以下3種類型:
| Value | Meaning |
|---|---|
| EXCEPTION_EXECUTE_HANDLER |
Return from UnhandledExceptionFilter and execute the associated exception handler. This usually results in process termination.捕獲到異常,並在異常處結束程序。 |
| EXCEPTION_CONTINUE_EXECUTION |
Return from UnhandledExceptionFilter and continue execution from the point of the exception. Note that the filter function is free to modify the continuation state by modifying the exception information supplied through its LPEXCEPTION_POINTERS parameter.表示錯誤已經被修復,從異常發生處繼續執行。如果在回掉函數內部不對異常進行處理,每次回掉結束又會捕獲到異常,將導致無限進入SetUnhandledExceptionFilter函數,死循環。 |
| EXCEPTION_CONTINUE_SEARCH |
Proceed with normal execution of UnhandledExceptionFilter. That means obeying the SetErrorMode flags, or invoking the Application Error pop-up message box.捕獲到異常,並調用系統默認異常錯誤框,結束程序。
|
2:在SetUnhandledExceptionFilter的回掉函數中,用MiniDumpWriteDump函數將異常寫入dump文件。需要包含DbgHelp.h,引入#pragma comment(lib, "dbghelp.lib")。MiniDumpWriteDump函數的原型為:
1 BOOL WINAPI MiniDumpWriteDump( 2 __in HANDLE hProcess, // 進程句柄,可以用GetCurrentProcess()獲得 3 __in DWORD ProcessId, // 進程ID,可以用GetCurrentProcessId()獲得 4 __in HANDLE hFile, // 待寫入的dmp文件 5 __in MINIDUMP_TYPE DumpType, // 寫入的dump信息類型,從MINIDUMP_TYPR中選擇。 6 __in PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, // 指向異常信息結構的指針,如果該值是NULL,將不會寫入任何異常信息 7 __in PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, // 指向用戶自定義信息塊,可以為NULL 8 __in PMINIDUMP_CALLBACK_INFORMATION CallbackParam // 指向回掉函數的擴展信息塊,可以為NULL 9 );
在MiniDumpWriteDump參數項中,比較重要的是異常信息塊PMINIDUMP_EXCEPTION_INFORMATION,其結構如下:
1 typedef struct _MINIDUMP_EXCEPTION_INFORMATION { 2 DWORD ThreadId; //線程ID,可以用GetCurrentThreadId()獲得 3 PEXCEPTION_POINTERS ExceptionPointers; //指向異常信息指針,EXCEPTION_POINTER內包含了異常信息代碼/flag等內容,異常發生時各寄存器狀態和內容。用回掉函數的參數賦值即可 4 BOOL ClientPointers; //TRUE和FALSE好像都可以,搞不清楚區別 5 } MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION;
3:了解上述內容后,封裝成類,方便移植。h文件:
1 #pragma once 2 #include <string> 3 using namespace std; 4 class CCreateDump 5 { 6 public: 7 CCreateDump(); 8 ~CCreateDump(void); 9 static CCreateDump* Instance(); 10 static long __stdcall UnhandleExceptionFilter(_EXCEPTION_POINTERS* ExceptionInfo); 11 //聲明Dump文件,異常時會自動生成。會自動加入.dmp文件名后綴 12 void DeclarDumpFile(std::string dmpFileName = ""); 13 private: 14 static std::string strDumpFile; 15 static CCreateDump* __instance; 16 };
cpp文件:
1 #include "StdAfx.h" 2 #include "CreateDump.h" 3 #include <DbgHelp.h> 4 #pragma comment(lib, "dbghelp.lib") 5 6 CCreateDump* CCreateDump::__instance = NULL; 7 std::string CCreateDump::strDumpFile = ""; 8 9 CCreateDump::CCreateDump() 10 { 11 } 12 13 CCreateDump::~CCreateDump(void) 14 { 15 16 } 17 18 long CCreateDump::UnhandleExceptionFilter(_EXCEPTION_POINTERS* ExceptionInfo) 19 { 20 HANDLE hFile = CreateFile(strDumpFile.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL, NULL ); 21 if(hFile!=INVALID_HANDLE_VALUE) 22 { 23 MINIDUMP_EXCEPTION_INFORMATION ExInfo; 24 ExInfo.ThreadId = ::GetCurrentThreadId(); 25 ExInfo.ExceptionPointers = ExceptionInfo; 26 ExInfo.ClientPointers = FALSE; 27 // write the dump 28 BOOL bOK = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ExInfo, NULL, NULL ); 29 CloseHandle(hFile); 30 if (!bOK) 31 { 32 DWORD dw = GetLastError(); 33 //寫dump文件出錯處理,異常交給windows處理 34 return EXCEPTION_CONTINUE_SEARCH; 35 } 36 else 37 { //在異常處結束 38 return EXCEPTION_EXECUTE_HANDLER; 39 } 40 } 42 else 43 { 44 return EXCEPTION_CONTINUE_SEARCH; 45 } 46 } 47 48 void CCreateDump::DeclarDumpFile(std::string dmpFileName) 49 { 50 SYSTEMTIME syt; 51 GetLocalTime(&syt); 52 char c[MAX_PATH]; 53 sprintf_s(c,MAX_PATH,"[%04d-%02d-%02d %02d:%02d:%02d]",syt.wYear,syt.wMonth,syt.wDay,syt.wHour,syt.wMinute,syt.wSecond); 54 strDumpFile = std::string(c); 55 if (!dmpFileName.empty()) 56 { 57 strDumpFile += dmpFileName; 58 } 59 strDumpFile += std::string(".dmp"); 60 SetUnhandledExceptionFilter(UnhandleExceptionFilter); 61 } 62 63 CCreateDump* CCreateDump::Instance() 64 { 65 if (__instance == NULL) 66 { 67 __instance = new CCreateDump; 68 } 69 return __instance; 70 }
調用方法:加入頭文件引用,在程序開始時寫入
CCreateDump::Instance()->DeclarDumpFile("dumpfile");
4:工程屬性設置,VS2008工程屬性->linker->debugging->Generate Debug Info選擇yes,生成pdb文件。
5:用vs2008打開dump文件,debug即可。
