windows下程序有时突然崩溃了,偶发性的崩溃很难找。于是就需要保存崩溃时的dump信息了。
下面是关于如何生成dmp文件的代码。
头文件
#pragma once #include <windows.h> #include <DbgHelp.h> #include <stdlib.h> #include <string> #pragma comment(lib, "dbghelp.lib")namespace FrameworkMiniDump {std::wstring GetTimeNowString();std::string WStringToString(const std::wstring& str);std::wstring StringToWString(const std::string& str);std::string getexepath();inline BOOL IsDataSectionNeeded(const WCHAR* pModuleName);inline BOOL CALLBACK MiniDumpCallback(PVOID pParam,const PMINIDUMP_CALLBACK_INPUT pInput,PMINIDUMP_CALLBACK_OUTPUT pOutput);inline void CreateMiniDump(PEXCEPTION_POINTERS pep, LPCTSTR strFileName);LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo);void DisableSetUnhandledExceptionFilter();// 此函数一旦成功调用,之后对 SetUnhandledExceptionFilter 的调用将无效void InitMinDump(); }
源文件:
#include "MiniDump.h" #include <iostream> #include <ctime> #include <string>namespace FrameworkMiniDump {std::wstring GetTimeNowString(){time_t rawtime;struct tm * timeinfo;wchar_t buffer[80];time(&rawtime);timeinfo = localtime(&rawtime);//wcsftime(buffer, sizeof(buffer), L"%d-%m-%Y %H:%M:%S", timeinfo);wcsftime(buffer, sizeof(buffer), L"%d-%m-%Y-%H-%M-%S", timeinfo);std::wstring str(buffer);return str;}std::wstring StringToWString(const std::string& str){ #if defined(WIN32)size_t sz = str.length();int nd = MultiByteToWideChar(CP_ACP, 0, &str[0], sz, NULL, 0);std::wstring ret(nd, 0);int w = MultiByteToWideChar(CP_ACP, 0, &str[0], sz, &ret[0], nd);if (str.length() != sz) {throw std::exception("StringToWString Err");}return ret; #elseconst char* p = str.c_str();size_t len = str.length();size_t sz = len * sizeof(wchar_t);wchar_t* tp = new wchar_t[sz];size_t w = mbstowcs(tp, p, sz);if (w != len) {delete[] tp;throw std::exception("StringToWString Err");}std::wstring ret(tp);delete[] tp;return ret; #endif}std::string WStringToString(const std::wstring& str){size_t sz = str.length(); #if defined(WIN32)int nd = WideCharToMultiByte(CP_ACP, 0, &str[0], sz, NULL, 0, NULL, NULL);std::string ret(nd, 0);int w = WideCharToMultiByte(CP_ACP, 0, &str[0], sz, &ret[0], nd, NULL, NULL);/*if (ret.length() != sz) {throw std::exception("WStringToString Err");}*/return ret; #elseconst wchar_t* p = str.c_str();char* tp = new char[sz];size_t w = wcstombs(tp, p, sz);if (w != sz) {delete[] tp;throw std::exception("WStringToString Err");}std::string ret(tp);delete[] tp;return ret; #endif}std::string getexepath(){wchar_t result[MAX_PATH];std::wstring wstr = std::wstring(result, GetModuleFileName(NULL, result, MAX_PATH));return WStringToString(wstr);}inline BOOL IsDataSectionNeeded(const WCHAR* pModuleName){if (pModuleName == 0){return FALSE;}WCHAR szFileName[_MAX_FNAME] = L"";_wsplitpath(pModuleName, NULL, NULL, szFileName, NULL);if (_wcsicmp(szFileName, std::wstring(L"ntdll").c_str()) == 0)return TRUE;return FALSE;}inline BOOL CALLBACK MiniDumpCallback(PVOID pParam,const PMINIDUMP_CALLBACK_INPUT pInput,PMINIDUMP_CALLBACK_OUTPUT pOutput){if (pInput == 0 || pOutput == 0)return FALSE;switch (pInput->CallbackType){case ModuleCallback:if (pOutput->ModuleWriteFlags & ModuleWriteDataSeg)if (!IsDataSectionNeeded(pInput->Module.FullPath))pOutput->ModuleWriteFlags &= (~ModuleWriteDataSeg);case IncludeModuleCallback:case IncludeThreadCallback:case ThreadCallback:case ThreadExCallback:return TRUE;default:;}return FALSE;}inline void CreateMiniDump(PEXCEPTION_POINTERS pep, LPCTSTR strFileName){HANDLE hFile = CreateFile(strFileName, GENERIC_READ | GENERIC_WRITE,FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE)){MINIDUMP_EXCEPTION_INFORMATION mdei;mdei.ThreadId = GetCurrentThreadId();mdei.ExceptionPointers = pep;mdei.ClientPointers = NULL;MINIDUMP_CALLBACK_INFORMATION mci;mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;mci.CallbackParam = 0;::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpNormal, (pep != 0) ? &mdei : 0, NULL, &mci);CloseHandle(hFile);}}LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo){std::string exename = "Dmp";std::wstring wexename = StringToWString(exename);;std::wstring filename = wexename + L"-" + GetTimeNowString() + L".dmp";CreateMiniDump(pExceptionInfo, filename.c_str());return EXCEPTION_EXECUTE_HANDLER;}// 此函数一旦成功调用,之后对 SetUnhandledExceptionFilter 的调用将无效void DisableSetUnhandledExceptionFilter(){void* addr = (void*)GetProcAddress(LoadLibrary(L"kernel32.dll"),"SetUnhandledExceptionFilter");if (addr){unsigned char code[16];int size = 0;code[size++] = 0x33;code[size++] = 0xC0;code[size++] = 0xC2;code[size++] = 0x04;code[size++] = 0x00;DWORD dwOldFlag, dwTempFlag;VirtualProtect(addr, size, PAGE_READWRITE, &dwOldFlag);WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL);VirtualProtect(addr, size, dwOldFlag, &dwTempFlag);}}void InitMinDump(){//注册异常处理函数 SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);//使SetUnhandledExceptionFilter DisableSetUnhandledExceptionFilter();} }
使用:
int main() {......FrameworkMiniDump::InitMinDump(); ...... }
调用一下InitMinDump就可以了,这里面会注册一个回调,崩溃时会保存的dmp文件。
注意:需要在debug模式。保存下来的dmp文件,需要结合pdb文件和源代码才能定位到哪里崩溃了。具体的我也不懂。