AutoDmp.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. #include "StdAfx.h"
  2. #include "AutoDmp.h"
  3. //-----------------dmp文件生成相关--------------------------------------------
  4. #include "detours.h"
  5. #ifndef _WIN64
  6. #pragma comment(lib, "AutoDmp\\lib.X86\\detours.lib")
  7. #else
  8. #pragma comment(lib, "AutoDmp\\lib.X64\\detours.lib")
  9. #endif
  10. #include <string>
  11. #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS (0x00000004)
  12. #define MiniDumpWithThreadInfo 0x1000
  13. typedef BOOL(WINAPI *PGetModuleHandleEx)(DWORD dwFlags, LPCTSTR lpModuleName, HMODULE *phModule);
  14. VOID CreateDump(struct _EXCEPTION_POINTERS *pExceptionPointers)
  15. {
  16. //收集信息
  17. CStringW strBuild;
  18. strBuild.Format(L"Build: %s %s", __DATE__, __TIME__);
  19. CStringW strError;
  20. HMODULE hModule;
  21. WCHAR szModuleName[MAX_PATH] = { 0 };
  22. PGetModuleHandleEx pFun = (PGetModuleHandleEx)GetProcAddress(GetModuleHandle(_T("kernel32.dll")), _T("GetModuleHandleExW"));
  23. if (!pFun) {
  24. return;
  25. }
  26. pFun(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)pExceptionPointers->ExceptionRecord->ExceptionAddress, &hModule);
  27. GetModuleFileNameW(hModule, szModuleName, ARRAYSIZE(szModuleName));
  28. std::wstring strDmppath = szModuleName;
  29. size_t index = strDmppath.rfind(L'.');
  30. strDmppath = strDmppath.substr(0, index);
  31. strDmppath.append(L"_Dmpfile");
  32. strError.Format(L"%s %d , %d ,%d.", szModuleName, pExceptionPointers->ExceptionRecord->ExceptionCode, pExceptionPointers->ExceptionRecord->ExceptionFlags, pExceptionPointers->ExceptionRecord->ExceptionAddress);
  33. CreateDirectoryW(strDmppath.c_str(), NULL);
  34. //生成 mini crash dump
  35. BOOL bMiniDumpSuccessful;
  36. DWORD dwBufferSize = MAX_PATH;
  37. HANDLE hDumpFile;
  38. SYSTEMTIME stLocalTime;
  39. MINIDUMP_EXCEPTION_INFORMATION ExpParam;
  40. GetLocalTime(&stLocalTime);
  41. WCHAR szFileName[MAX_PATH];
  42. swprintf_s(szFileName, MAX_PATH, L"%04d%02d%02d-%02d%02d%02d-ProcessID[%ld]-ThreadID[%ld].dmp",
  43. stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
  44. stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond,
  45. GetCurrentProcessId(), GetCurrentThreadId());
  46. strDmppath += L'\\';
  47. strDmppath.append(szFileName);
  48. hDumpFile = CreateFileW(strDmppath.c_str(), GENERIC_READ | GENERIC_WRITE,
  49. FILE_SHARE_WRITE | FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
  50. MINIDUMP_USER_STREAM UserStream[2];
  51. MINIDUMP_USER_STREAM_INFORMATION UserInfo;
  52. UserInfo.UserStreamCount = 1;
  53. UserInfo.UserStreamArray = UserStream;
  54. UserStream[0].Type = CommentStreamW;
  55. UserStream[0].BufferSize = strBuild.GetLength()*sizeof(WCHAR);
  56. UserStream[0].Buffer = strBuild.GetBuffer();
  57. UserStream[1].Type = CommentStreamW;
  58. UserStream[1].BufferSize = strError.GetLength()*sizeof(WCHAR);
  59. UserStream[1].Buffer = strError.GetBuffer();
  60. ExpParam.ThreadId = GetCurrentThreadId();
  61. ExpParam.ExceptionPointers = pExceptionPointers;
  62. ExpParam.ClientPointers = TRUE;
  63. MINIDUMP_TYPE MiniDumpWithDataSegs = (MINIDUMP_TYPE)(MiniDumpNormal
  64. | MiniDumpWithHandleData
  65. | MiniDumpWithUnloadedModules
  66. | MiniDumpWithIndirectlyReferencedMemory
  67. | MiniDumpScanMemory
  68. | MiniDumpWithProcessThreadData
  69. | MiniDumpWithThreadInfo);
  70. bMiniDumpSuccessful = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
  71. hDumpFile, MiniDumpWithDataSegs, &ExpParam, NULL, NULL);
  72. return;
  73. }
  74. LONG WINAPI AutoDmp::NewUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *lpExceptionInfo)
  75. {
  76. OutputDebugString(_T("NewUnhandledExceptionFilter\n"));
  77. CreateDump(lpExceptionInfo);
  78. return EXCEPTION_EXECUTE_HANDLER;
  79. }
  80. AutoDmp::AutoDmp()
  81. {
  82. m_lpUnhandledExceptionFilter = NULL;
  83. do {
  84. SetErrorMode(SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
  85. m_lpUnhandledExceptionFilter = DetourFindFunction("KERNEL32.DLL", "UnhandledExceptionFilter");
  86. if (NULL == m_lpUnhandledExceptionFilter) {
  87. break;
  88. }
  89. LONG lRes = NO_ERROR;
  90. lRes = DetourTransactionBegin();
  91. if (NO_ERROR != lRes) {
  92. break;
  93. }
  94. lRes = DetourAttach(&m_lpUnhandledExceptionFilter, NewUnhandledExceptionFilter);
  95. if (NO_ERROR != lRes) {
  96. break;
  97. }
  98. lRes = DetourTransactionCommit();
  99. if (NO_ERROR != lRes) {
  100. break;
  101. }
  102. } while (0);
  103. }
  104. AutoDmp::~AutoDmp()
  105. {
  106. if (m_lpUnhandledExceptionFilter) {
  107. do {
  108. LONG lRes = NO_ERROR;
  109. lRes = DetourTransactionBegin();
  110. if (NO_ERROR != lRes) {
  111. break;
  112. }
  113. lRes = DetourDetach(&m_lpUnhandledExceptionFilter, NewUnhandledExceptionFilter);
  114. if (NO_ERROR != lRes) {
  115. break;
  116. }
  117. lRes = DetourTransactionCommit();
  118. if (NO_ERROR != lRes) {
  119. break;
  120. }
  121. } while (0);
  122. }
  123. }
  124. //dmp生成参考资料
  125. //http://www.sjsjw.com/kf_other/article/031086ABA018049.asp
  126. //在win7 64bit + vs2008 + sdk v7.0的环境下编译Detours
  127. //http://blog.csdn.net/genesisbible/article/details/6771988
  128. //下载编译好的Detours
  129. //http://download.csdn.net/download/staver102/7648875
  130. //DMP文件的使用:
  131. //把dmp文件和exe, pdb文件放在同一目录下, 然后用编译器(如vc)打开, 然后开始调试就会中断到刚才中断的地方.
  132. //使用符号服务器
  133. //您可以使用符号服务器自动下载用于调试 Visual Studio .NET 项目的正确符号。
  134. //Microsoft 在 http://msdl.microsoft.com/download/symbols 上为开发人员维护了一个公共符号服务器。
  135. //此服务器为各种操作系统(Windows NT 4.0、Windows 2000、Windows XP 和 Windows Server 2003)、MDAC、IIS、ISA 和 .NET Framework 提供符号。
  136. //
  137. //另外,您也可以将本地符号服务器安装在 Intranet 上或本地计算机上。
  138. //要使用符号服务器,必须在项目中指定正确的服务器路径。
  139. //
  140. //设置符号服务器的路径
  141. //1.在 Visual Studio 中打开该项目。
  142. //2.在“解决方案资源管理器”视图中选择解决方案的名称。
  143. //3.从“项目”菜单中选择“设置启动项目”。
  144. //4.在“解决方案 <项目> 属性页”对话框中,打开“通用属性”文件夹,单击“调试符号文件”。
  145. //5.在“在这些路径中搜索符号文件”框中创建新的行,方法是双击空的新行或单击“新建行”按钮。
  146. //6.在新行中输入符号服务器的路径。
  147. //若要使用 Microsoft 公共符号服务器,请输入:
  148. //srv*c:\cache*http://msdl.microsoft.com/download/symbols;
  149. //若要使用 Intranet 符号服务器,请输入:
  150. //srv*\\server\path\symbols;
  151. //若要使用本地计算机上的符号服务器,请输入:
  152. //c:\path\symbols;
  153. //7.不要单击“检查项”按钮。
  154. //8.单击“确定”按钮。
  155. //9.将 symsrv.dll 从 Visual Studio .NET 安装盘复制到 C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE。
  156. //-----------------dmp文件生成相关--------------------------------------------