編寫的windows程序,崩潰時產生crash dump文件的辦法

一、引言

dump文件是C++程序發生異常時,保存當時程序運行狀態的文件,是調試異常程序重要的方法,所以程序崩潰時,除了日志文件,dump文件便成了我們查找錯誤的最后一根救命的稻草。windows程序產生dump文件和linux程序產生dump文件的方式不一樣,linux默認是不讓產生core dump文件,只要在用戶自己的~/.bash_profile文件中增加

ulimit -S -c unlimited > /dev/null 2>&1

這樣程序崩潰就可以產生可調試的core dump文件了。但是windows環境就得寫代碼才能實現了。

二、原理

windows程序當遇到異常,沒有try-catch或者try-catch也無法捕獲到的異常時,程序就會自動退出,如果這時候沒有dump文件的話,我們是沒有得到任何程序退出的信息。在windows程序異常退出之前,會預先調用一個在程序中注冊的異常處理回調函數(默認是沒有設置),只要我們在這個回調函數中調用MiniDumpWriteDump函數就可以產生我們想要的dump文件。

三、實現

1.調用SetUnhandledExceptionFilter注冊一個自定義的異常處理回調函數

SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);

異常處理回調函數的原型

LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo);

2.CreateFile創建dump文件,調用MiniDumpWriteDump函數往dump文件寫異常信息

[cpp]?view plain?copy
?print?
  1. inline?void?CreateMiniDump(PEXCEPTION_POINTERS?pep,?LPCTSTR?strFileName)??
  2. {??
  3. ????HANDLE?hFile?=?CreateFile(strFileName,?GENERIC_READ?|?GENERIC_WRITE,??
  4. ????????FILE_SHARE_WRITE,?NULL,?CREATE_ALWAYS,?FILE_ATTRIBUTE_NORMAL,?NULL);??
  5. ??
  6. ????if((hFile?!=?NULL)?&&?(hFile?!=?INVALID_HANDLE_VALUE))??
  7. ????{??
  8. ????????MINIDUMP_EXCEPTION_INFORMATION?mdei;??
  9. ????????mdei.ThreadId???????????=?GetCurrentThreadId();??
  10. ????????mdei.ExceptionPointers??=?pep;??
  11. ????????mdei.ClientPointers?????=?NULL;??
  12. ??
  13. ????????MINIDUMP_CALLBACK_INFORMATION?mci;??
  14. ????????mci.CallbackRoutine?????=?(MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;??
  15. ????????mci.CallbackParam???????=?0;??
  16. ??
  17. ????????::MiniDumpWriteDump(::GetCurrentProcess(),?::GetCurrentProcessId(),?hFile,?MiniDumpNormal,?(pep?!=?0)???&mdei?:?0,?NULL,?&mci);??
  18. ??
  19. ????????CloseHandle(hFile);??
  20. ????}??
  21. }??

CreateMiniDump函數是在異常處理回調函數MyUnhandledExceptionFilter中調用的

[cpp]?view plain?copy
?print?
  1. LONG?__stdcall?MyUnhandledExceptionFilter(PEXCEPTION_POINTERS?pExceptionInfo)??
  2. {??
  3. ????CreateMiniDump(pExceptionInfo,?"core.dmp");??
  4. ??
  5. ????return?EXCEPTION_EXECUTE_HANDLER;??
  6. }??

3.將SetUnhandledExceptionFilter失效

vs2005中,編譯的過程中,編譯器會自動給你的程序加上一句SetUnhandledExceptionFilter(NULL),這就會導致你之前自定義的

SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);

無效,就有可能不會產生dump文件,因此我們必須在自定義的SetUnhandledExceptionFilter之后,讓之后調用的SetUnhandledExceptionFilter無效。增加以下代碼:

[cpp]?view plain?copy
?print?
  1. //?此函數一旦成功調用,之后對?SetUnhandledExceptionFilter?的調用將無效??
  2. void?DisableSetUnhandledExceptionFilter()??
  3. {??
  4. ????void*?addr?=?(void*)GetProcAddress(LoadLibrary("kernel32.dll"),??
  5. ????????"SetUnhandledExceptionFilter");??
  6. ??
  7. ????if?(addr)??
  8. ????{??
  9. ????????unsigned?char?code[16];??
  10. ????????int?size?=?0;??
  11. ??
  12. ????????code[size++]?=?0x33;??
  13. ????????code[size++]?=?0xC0;??
  14. ????????code[size++]?=?0xC2;??
  15. ????????code[size++]?=?0x04;??
  16. ????????code[size++]?=?0x00;??
  17. ??
  18. ????????DWORD?dwOldFlag,?dwTempFlag;??
  19. ????????VirtualProtect(addr,?size,?PAGE_READWRITE,?&dwOldFlag);??
  20. ????????WriteProcessMemory(GetCurrentProcess(),?addr,?code,?size,?NULL);??
  21. ????????VirtualProtect(addr,?size,?dwOldFlag,?&dwTempFlag);??
  22. ????}??
  23. }??

最終代碼整理:

//minidump.h

[cpp]?view plain?copy
?print?
  1. #pragma?once??
  2. #include?<windows.h>??
  3. #include?<DbgHelp.h>??
  4. #include?<stdlib.h>??
  5. #pragma?comment(lib,?"dbghelp.lib")??
  6. ??
  7. #ifndef?_M_IX86??
  8. #error?"The?following?code?only?works?for?x86!"??
  9. #endif??
  10. ??
  11. inline?BOOL?IsDataSectionNeeded(const?WCHAR*?pModuleName)??
  12. {??
  13. ????if(pModuleName?==?0)??
  14. ????{??
  15. ????????return?FALSE;??
  16. ????}??
  17. ??
  18. ????WCHAR?szFileName[_MAX_FNAME]?=?L"";??
  19. ????_wsplitpath(pModuleName,?NULL,?NULL,?szFileName,?NULL);??
  20. ??
  21. ????if(wcsicmp(szFileName,?L"ntdll")?==?0)??
  22. ????????return?TRUE;??
  23. ??
  24. ????return?FALSE;??
  25. }??
  26. ??
  27. inline?BOOL?CALLBACK?MiniDumpCallback(PVOID????????????????????????????pParam,??
  28. ??????????????????????????????????????const?PMINIDUMP_CALLBACK_INPUT???pInput,??
  29. ??????????????????????????????????????PMINIDUMP_CALLBACK_OUTPUT????????pOutput)??
  30. {??
  31. ????if(pInput?==?0?||?pOutput?==?0)??
  32. ????????return?FALSE;??
  33. ??
  34. ????switch(pInput->CallbackType)??
  35. ????{??
  36. ????case?ModuleCallback:??
  37. ????????if(pOutput->ModuleWriteFlags?&?ModuleWriteDataSeg)??
  38. ????????????if(!IsDataSectionNeeded(pInput->Module.FullPath))??
  39. ????????????????pOutput->ModuleWriteFlags?&=?(~ModuleWriteDataSeg);??
  40. ????case?IncludeModuleCallback:??
  41. ????case?IncludeThreadCallback:??
  42. ????case?ThreadCallback:??
  43. ????case?ThreadExCallback:??
  44. ????????return?TRUE;??
  45. ????default:;??
  46. ????}??
  47. ??
  48. ????return?FALSE;??
  49. }??
  50. ??
  51. inline?void?CreateMiniDump(PEXCEPTION_POINTERS?pep,?LPCTSTR?strFileName)??
  52. {??
  53. ????HANDLE?hFile?=?CreateFile(strFileName,?GENERIC_READ?|?GENERIC_WRITE,??
  54. ????????FILE_SHARE_WRITE,?NULL,?CREATE_ALWAYS,?FILE_ATTRIBUTE_NORMAL,?NULL);??
  55. ??
  56. ????if((hFile?!=?NULL)?&&?(hFile?!=?INVALID_HANDLE_VALUE))??
  57. ????{??
  58. ????????MINIDUMP_EXCEPTION_INFORMATION?mdei;??
  59. ????????mdei.ThreadId???????????=?GetCurrentThreadId();??
  60. ????????mdei.ExceptionPointers??=?pep;??
  61. ????????mdei.ClientPointers?????=?NULL;??
  62. ??
  63. ????????MINIDUMP_CALLBACK_INFORMATION?mci;??
  64. ????????mci.CallbackRoutine?????=?(MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;??
  65. ????????mci.CallbackParam???????=?0;??
  66. ??
  67. ????????::MiniDumpWriteDump(::GetCurrentProcess(),?::GetCurrentProcessId(),?hFile,?MiniDumpNormal,?(pep?!=?0)???&mdei?:?0,?NULL,?&mci);??
  68. ??
  69. ????????CloseHandle(hFile);??
  70. ????}??
  71. }??
  72. ??
  73. LONG?__stdcall?MyUnhandledExceptionFilter(PEXCEPTION_POINTERS?pExceptionInfo)??
  74. {??
  75. ????CreateMiniDump(pExceptionInfo,?"core.dmp");??
  76. ??
  77. ????return?EXCEPTION_EXECUTE_HANDLER;??
  78. }??
  79. ??
  80. //?此函數一旦成功調用,之后對?SetUnhandledExceptionFilter?的調用將無效??
  81. void?DisableSetUnhandledExceptionFilter()??
  82. {??
  83. ????void*?addr?=?(void*)GetProcAddress(LoadLibrary("kernel32.dll"),??
  84. ????????"SetUnhandledExceptionFilter");??
  85. ??
  86. ????if?(addr)??
  87. ????{??
  88. ????????unsigned?char?code[16];??
  89. ????????int?size?=?0;??
  90. ??
  91. ????????code[size++]?=?0x33;??
  92. ????????code[size++]?=?0xC0;??
  93. ????????code[size++]?=?0xC2;??
  94. ????????code[size++]?=?0x04;??
  95. ????????code[size++]?=?0x00;??
  96. ??
  97. ????????DWORD?dwOldFlag,?dwTempFlag;??
  98. ????????VirtualProtect(addr,?size,?PAGE_READWRITE,?&dwOldFlag);??
  99. ????????WriteProcessMemory(GetCurrentProcess(),?addr,?code,?size,?NULL);??
  100. ????????VirtualProtect(addr,?size,?dwOldFlag,?&dwTempFlag);??
  101. ????}??
  102. }??
  103. ??
  104. void?InitMinDump()??
  105. {??
  106. ????//注冊異常處理函數??
  107. ????SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);??
  108. ??
  109. ????//使SetUnhandledExceptionFilter??
  110. ????DisableSetUnhandledExceptionFilter();??
  111. }??

4.測試代碼

//test.cpp

[cpp]?view plain?copy
?print?
  1. #include?<iostream>??
  2. #include?"minidump.h"??
  3. void?test()??
  4. {??
  5. ????std::string?s?=?"abcd";??
  6. ??
  7. ????try{??
  8. ????????s[100]?=?'b';??
  9. ????}??
  10. ????catch(std::exception&?e)??
  11. ????{??
  12. ????????std::cout?<<?"with?exception:["?<<?e.what()?<<?"]"?<<?std::endl;??
  13. ????}??
  14. ????catch(...)??
  15. ????{??
  16. ????????std::cout?<<?"with?unknown?exception"?<<?std::endl;??
  17. ????}??
  18. }??
  19. ??
  20. void?main()??
  21. {??
  22. ????InitMinDump();??
  23. ??
  24. ????test();??
  25. ??
  26. ????system("pause");??
  27. }??

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/458715.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/458715.shtml
英文地址,請注明出處:http://en.pswp.cn/news/458715.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Nginx+PHP實時生成不同尺寸圖片

原來圖片服務器采用Windows .net架構&#xff0c;鑒于需求需要生成各種尺寸圖片。流程說明:用戶從Nginx請求對應的圖片,判斷是否存在_200x300的對應參數&#xff0c;如果沒有就直接請求到對應目錄的原圖&#xff0c;否則繼續判斷是否在本地已經生成了對應的緩存圖片&#xff0c…

JavaScript設計模式 Item 2 -- 接口的實現

1、接口概述 1。什么是接口&#xff1f; 接口是提供了一種用以說明一個對象應該具有哪些方法的手段。盡管它可以表明這些方法的語義&#xff0c;但它并不規定這些方法應該如何實現。 2. 接口之利 促進代碼的重用。 接口可以告訴程序員一個類實現了哪些方法&#xff0c;從而幫助…

Spring Boot 樂觀鎖加鎖失敗 - 集成AOP

Spring Boot with AOP 手頭上的項目使用了Spring Boot&#xff0c; 在高并發的情況下&#xff0c;經常出現樂觀鎖加鎖失敗的情況&#xff08;OptimisticLockingFailureException&#xff0c;同一時間有多個線程在更新同一條數據&#xff09;。為了減少直接向服務使用者直接返回…

掌握VS2010調試 -- 入門指南

1 導言 在軟件開發周期中&#xff0c;測試和修正缺陷&#xff08;defect&#xff0c;defect與bug的區別&#xff1a;Bug是缺陷的一種表現形式&#xff0c;而一個缺陷是可以引起多種Bug的&#xff09;的時間遠多于寫代碼的時間。通常&#xff0c;debug是指發現缺陷并改正的過程。…

151031

create or replace procedure pr_test1 is v_case number(3): 100; beginif 2>1 thendbms_output.put_line(成立);elsif 4>3 thenif 7>6 thendbms_output.put_line(不成立);end if; elsif 6>5 thendbms_output.put_line(也行);elsedbms_output.put_line(也不成立);…

postgresql9.5 run 文件linux安裝后配置成開機服務

網上出現的比較多安裝方法要么是源碼安裝&#xff0c;要么是yum安裝&#xff0c;我發覺都要配置很多屬性&#xff0c;比較麻煩&#xff0c;所以現在我在centos7長用 run文件來安裝 http://get.enterprisedb.com/postgresql/postgresql-9.5.1-1-linux-x64.run 這里的安裝shell整…

Windows API GetProcAddress 及demo code

GetProcAddress函數檢索指定的動態鏈接庫(DLL)中的輸出庫函數地址。 函數原型&#xff1a; FARPROC GetProcAddress( HMODULE hModule, // DLL模塊句柄 LPCSTR lpProcName// 函數名 ); 參數&#xff1a; hModule [in] 包含此函數的DLL模塊的句柄。LoadLibrary、AfxLoadLibrary …

【操作系統】進程管理

進程管理 進程的基本概念 程序的順序執行及其特征 程序的順序執行:僅當前一操作(程序段)執行完后&#xff0c;才能執行后續操作。 程序順序執行時的特征&#xff1a;順序性&#xff0c;封閉性&#xff0c;可再見性。 前趨圖 前趨圖(Precedence Graph)是一個有向無循環圖&#…

va_list va_start va_end的使用

<pre name"code" class"cpp" style"color: rgb(51, 51, 51); white-space: pre-wrap; word-wrap: break-word;"><strong>一、 從printf()開始</strong> 從大家都很熟悉的格式化字符串函數開始介紹可變參數函數。 原型&#xf…

Linux學習之CentOS(三)----將Cent0S 7的網卡名稱eno16777736改為eth0

【正文】 Linux系統版本&#xff1a;CentOS_7&#xff08;64位&#xff09; 一、前言&#xff1a; 今天又從Centos 6.5裝回了Centos 7&#xff0c;畢竟還是要順應潮流嘛。安裝完成之后&#xff0c;發現發現CentOS 7默認的網卡名稱是eno16777736&#xff0c;如圖所示&#xff1a…

本地音頻播放,使用AVFoundation.framework中的AVAudioPlayer來實現

本地音頻播放,使用AVfoundation.framework中的AVAudioPlayer來實現 /*AVAudioPlayer的使用比較簡單: 1、初始化AVAudioPlayer對象&#xff0c;此時通常指定本地文件路徑 2、設置播放器屬性&#xff0c;例如重復次數、音量大小等 3、調用play方法播放。 */

AngularJS操作DOM——angular.element

addClass()-為每個匹配的元素添加指定的樣式類名after()-在匹配元素集合中的每個元素后面插入參數所指定的內容&#xff0c;作為其兄弟節點append()-在每個匹配元素里面的末尾處插入參數內容attr() - 獲取匹配的元素集合中的第一個元素的屬性的值bind() - 為一個元素綁定一個事…

C++中operator的主要用法

1&#xff0e; operator 用于類型轉換函數&#xff1a; 類型轉換函數的特征&#xff1a; 1&#xff09; 型轉換函數定義在源類中&#xff1b; 2&#xff09; 須由 operator 修飾&#xff0c;函數名稱是目標類型名或目標類名&#xff1b; 3&#xff09; 函數沒有參數&#x…

聲紋識別

一、 聲紋識別是一項根據語音波形中反映說話人生理和行為特征的語音參數&#xff0c;自動識別說話人身份的技術。與語音識別不同的是&#xff0c;聲紋識別利用的是語音信號中的說話人身份信息&#xff0c;而不考慮語音中的字詞意思。由于每個人的生物特征具有與其他人不同的唯一…

Asp.net mvc 實時生成縮率圖到硬盤

之前對于縮率圖的處理是在圖片上傳到服務器之后&#xff0c;同步生成兩張不同尺寸的縮率供前端調用&#xff0c;剛開始還能滿足需求&#xff0c;慢慢的隨著前端展示的多樣化&#xff0c;縮率圖已不能前端展示的需求&#xff0c;所以考慮做一個實時生成圖片縮率圖服務。 每次調用…

數據庫事務的隔離機制

數據庫事務(Database Transaction) &#xff0c;是指作為單個邏輯工作單元執行的一系列操作&#xff0c;要么完全地執行&#xff0c;要么完全地不執行。----百度百科就是說你定義一組數據庫操作&#xff0c;然后告訴數據庫說這些操作要么都成功&#xff0c;要么都不成功。類似于…

如何使用CppUnit進行單元測試

http://www.vckbase.com/document/viewdoc/?id1762 一、前言 測試驅動開發(TDD)是以測試作為開發過程的中心&#xff0c;它堅持&#xff0c;在編寫實際代碼之前&#xff0c;先寫好基于產品代碼的測試代碼。開發過程的目標就是首先使測試能夠通過&#xff0c;然后再優化設計結構…

錄制wav格式的音頻

項目中有面部認證、聲紋認證&#xff0c;服務器端要求上傳wav格式的音頻&#xff0c;所以寫了這樣一個小demo。 剛剛開始寫博客還不知道怎么上傳代碼&#xff0c;就復制了&#xff0c;嘻嘻 DotimeManage.h class DotimeManage; protocol DotimeManageDelegate <NSObject&g…

iOS開發網絡篇—Reachability檢測網絡狀態

前言&#xff1a;當應用程序需要訪問網絡的時候&#xff0c;它首先應該檢查設備的網絡狀態&#xff0c;確認設備的網絡環境及連接情況&#xff0c;并針對這些情況提醒用戶做出相應的處理。最好能監聽設備的網絡狀態的改變&#xff0c;當設備網絡狀態連接、斷開時&#xff0c;程…

網絡七層協議 五層模型 TCP連接 HTTP連接 socket套接字

socket&#xff08;套接字&#xff09;是通信的基石&#xff0c;是支持TCP/IP協議的網絡通信的基本操作單元&#xff0c;包含進行網絡通信必須的五種信息&#xff1a;連接使用的協議&#xff0c;本地主機的IP地址&#xff0c;本地進程的協議端口&#xff0c;遠地主機的IP地址&a…