版权声明:本文为博主原创文章,转载请注明原帖地址。 https://blog.csdn.net/sunflover454/article/details/51200663
// minidmp.h
#pragma once
#include <windows h="">
#include <imagehlp h="">
#include <stdlib h="">
#include <strsafe h="">
#pragma comment(lib, "dbghelp.lib")
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, L"ntdll") == 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);
break;
case IncludeModuleCallback:
case IncludeThreadCallback:
case ThreadCallback:
case ThreadExCallback:
return TRUE;
default:
break;
}
return FALSE;
}
//创建Dump文件
inline void CreateMiniDump(EXCEPTION_POINTERS *pep, LPCWSTR strFileName)
{
HANDLE hFile = CreateFileW(strFileName, GENERIC_WRITE, 0, 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 = FALSE;
MINIDUMP_CALLBACK_INFORMATION mci;
mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;
mci.CallbackParam = 0;
MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)0x0000ffff;
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &mdei, NULL, &mci);
CloseHandle(hFile);
}
}
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
{
return NULL;
}
BOOL PreventSetUnhandledExceptionFilter()
{
HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll"));
if (hKernel32 == NULL)
return FALSE;
void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter");
if(pOrgEntry == NULL)
return FALSE;
unsigned char newJump[ 100 ];
DWORD dwOrgEntryAddr = (DWORD) pOrgEntry;
dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp far
void *pNewFunc = &MyDummySetUnhandledExceptionFilter;
DWORD dwNewEntryAddr = (DWORD) pNewFunc;
DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr;
newJump[ 0 ] = 0xE9; // JMP absolute
memcpy(&newJump[ 1 ], &dwRelativeAddr, sizeof(pNewFunc));
SIZE_T bytesWritten;
BOOL bRet = WriteProcessMemory(GetCurrentProcess(), pOrgEntry, newJump, sizeof(pNewFunc) + 1, &bytesWritten);
return bRet;
}
LONG WINAPI UnhandledExceptionFilterEx(struct _EXCEPTION_POINTERS *pException)
{
WCHAR szPath[MAX_PATH];
WCHAR szFileName[MAX_PATH];
WCHAR *szAppName = L"DumpFile";
HANDLE hDumpFile;
SYSTEMTIME stLocalTime;
MINIDUMP_EXCEPTION_INFORMATION ExpParam;
GetLocalTime( &stLocalTime );
//GetTempPath( dwBufferSize, szPath );
GetModuleFileNameW(NULL, szPath, MAX_PATH);
wchar_t *pstr = wcsrchr(szPath, '\\');
memset(pstr + 1, 0, 2);
StringCchPrintfW( szFileName, MAX_PATH, L"%s%s", szPath, szAppName );
CreateDirectoryW( szFileName, NULL );
StringCchPrintfW( szFileName, MAX_PATH, L"%s%s\\%04d%02d%02d-%02d%02d%02d.dmp", szPath, szAppName,
stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond);
CreateMiniDump(pException, szFileName);
// TODO: 这里可以将dump文件通过邮件发送给开发者,也可以通过http发送给服务端,服务端管理dump文件
FatalAppExit(-1, _T("*** Unhandled Exception! ***"));
return EXCEPTION_CONTINUE_SEARCH;
}
//运行异常处理
void RunCrashHandler()
{
SetUnhandledExceptionFilter(UnhandledExceptionFilterEx);
PreventSetUnhandledExceptionFilter();
}
// Test.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "minidmp.h"
void CrashTest()
{
strcpy(NULL,"adfadfg");
}
int _tmain(int argc, _TCHAR* argv[])
{
//设置异常处理回调函数
RunCrashHandler();
CrashTest();
getchar();
return 0;
}
核心就是这样了,注意点:程序发布时记得带上dbghelp.dll,这个是系统dll,开发机上肯定都会有。剩下的就是把dump文件上传到服务器或者直接使用邮件发到指定邮箱了。
有了dump文件,结合发布版本的pdb文件以及源代码就能很快定位到崩溃点了。