交给客户的软件奔溃了怎么办?
我们不能再客户电脑上安装vs,也不想傻傻的用log来猜测出错的地方。
利用Dbghelp可以解决这一问题。
首先是vs生成release版本的时候需要同时生成pdb文件,这里以vs2015为例:
https://blog.csdn.net/yhc166188/article/details/80695317
基本设置流程如下:
1、项目->属性->C/C++->General->Debug Information Format->Program Database for Edit & Continue (/ZI)
2、项目->属性->C/C++->Optimization->Optimization->Disabled(/Od)
3、项目->属性->Linker->Debugging->Generate Debug Info->Yes(/DEBUG)
此时,再编译软件,就会同时生成.pdb文件。
回到项目中来,我们还需要添加一点代码,使得程序优雅的奔溃。
新建一个dumpfile.h文件,将以下代码拷贝进去
1 #pragma once 2 #include <windows.h> 3 #include < Dbghelp.h> 4 #include <iostream> 5 #include <vector> 6 #include <tchar.h> 7 using namespace std; 8 9 10 #pragma comment(lib, "Dbghelp.lib") 11 12 13 namespace NSDumpFile 14 { 15 void CreateDumpFile(LPCWSTR lpstrDumpFilePathName, EXCEPTION_POINTERS *pException) 16 { 17 // 创建Dump文件 18 // 19 HANDLE hDumpFile = CreateFile(lpstrDumpFilePathName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 20 21 22 // Dump信息 23 // 24 MINIDUMP_EXCEPTION_INFORMATION dumpInfo; 25 dumpInfo.ExceptionPointers = pException; 26 dumpInfo.ThreadId = GetCurrentThreadId(); 27 dumpInfo.ClientPointers = TRUE; 28 29 30 // 写入Dump文件内容 31 // 32 MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL); 33 34 35 CloseHandle(hDumpFile); 36 } 37 38 39 LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) 40 { 41 return NULL; 42 } 43 44 45 BOOL PreventSetUnhandledExceptionFilter() 46 { 47 HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll")); 48 if (hKernel32 == NULL) 49 return FALSE; 50 51 52 void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter"); 53 if (pOrgEntry == NULL) 54 return FALSE; 55 56 57 unsigned char newJump[100]; 58 DWORD dwOrgEntryAddr = (DWORD)pOrgEntry; 59 dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp far 60 61 62 void *pNewFunc = &MyDummySetUnhandledExceptionFilter; 63 DWORD dwNewEntryAddr = (DWORD)pNewFunc; 64 DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr; 65 66 67 newJump[0] = 0xE9; // JMP absolute 68 memcpy(&newJump[1], &dwRelativeAddr, sizeof(pNewFunc)); 69 SIZE_T bytesWritten; 70 BOOL bRet = WriteProcessMemory(GetCurrentProcess(), pOrgEntry, newJump, sizeof(pNewFunc) + 1, &bytesWritten); 71 return bRet; 72 } 73 74 LONG WINAPI UnhandledExceptionFilterEx(struct _EXCEPTION_POINTERS *pException) 75 { 76 TCHAR szMbsFile[MAX_PATH] = { 0 }; 77 ::GetModuleFileName(NULL, szMbsFile, MAX_PATH); 78 TCHAR* pFind = _tcsrchr(szMbsFile, '\\'); 79 if (pFind) 80 { 81 *(pFind + 1) = 0; 82 _tcscat(szMbsFile, _T("CrashDumpFile.dmp")); 83 CreateDumpFile(szMbsFile, pException); 84 } 85 86 87 // TODO: MiniDumpWriteDump 88 FatalAppExit(-1, _T("Fatal Error")); 89 return EXCEPTION_CONTINUE_SEARCH; 90 } 91 92 93 void RunCrashHandler() 94 { 95 SetUnhandledExceptionFilter(UnhandledExceptionFilterEx); 96 PreventSetUnhandledExceptionFilter(); 97 } 98 }; 99 100 101 #define DeclareDumpFile() NSDumpFile::RunCrashHandler();
接着,在全局类(例如main文件,或者QMainWindow派生类)里面添加头文件dumpfile.h,然后在构造函数或者全局添加宏:
DeclareDumpFile()即可。
#include "StockTradeByTdxMulti.h" #include <QtWidgets/QApplication> #include <QFile> #include "dumpfile.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); DeclareDumpFile() StockTradeByTdxMulti w; w.show(); return a.exec(); }
如果exe出错了,就会生成CrashDumpFile.dmp文件,当然你也可以改成你希望的名字。
最后,你从客户那边拿到CrashDumpFile.dmp,放到上面说的.pdb文件所在文件夹。双击运行CrashDumpFile.dmp,vs就会运行起来。
点击画圈的部分就可以定位到代码出错的位置啦。