交給客戶的軟件奔潰了怎么辦?
我們不能再客戶電腦上安裝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就會運行起來。
點擊畫圈的部分就可以定位到代碼出錯的位置啦。

