配合UnhandledExceptionFilterEx()实现崩溃后自动重启

原创 2018年04月17日 15:58:29

使用函数UnhandledExceptionFilterEx()捕捉崩溃,在崩溃前重启程序。

函数

int RestartProcess(bool bNormal = false);
中默认参数bNormal用于控制崩溃之后是否自动结束程序,具体可以自测。
#include "MiniDump.h"
#include <windows.h>
#include <imagehlp.h>
#include <stdlib.h>
#include <tchar.h>
#pragma comment(lib, "dbghelp.lib")

int RestartProcess(bool bNormal = false);

inline BOOL IsDataSectionNeeded(const WCHAR* pModuleName)
{
	if (pModuleName == 0)
	{
		return FALSE;
	}
	WCHAR szFileName[_MAX_FNAME] = L"";
	//_wsplitpath(pModuleName, NULL, NULL, szFileName, NULL);
	_wsplitpath_s(pModuleName, NULL, 0, NULL, 0, szFileName, 0, NULL, 0);
	//if (wcsicmp(szFileName, L"ntdll") == 0)
	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);
	case IncludeModuleCallback:
	case IncludeThreadCallback:
	case ThreadCallback:
	case ThreadExCallback:
		return TRUE;
	default:;
	}
	return FALSE;
}

//创建Dump文件
inline void CreateMiniDump(EXCEPTION_POINTERS* pep, LPCTSTR strFileName)
{
	HANDLE hFile = CreateFile(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)
{
	TCHAR szMbsFile[MAX_PATH] = { 0 };
	::GetModuleFileName(NULL, szMbsFile, MAX_PATH);
	TCHAR* pFind = _tcsrchr(szMbsFile, '\\');
	if (pFind)
	{
		*(pFind + 1) = 0;
		//_tcscat(szMbsFile, _T("CreateMiniDump.dmp"));
		_tcscat_s(szMbsFile, _T("CreateMiniDump.dmp"));
		CreateMiniDump(pException, szMbsFile);
	}
	// TODO: MiniDumpWriteDump
	RestartProcess();
	FatalAppExit(-1, _T("Fatal Error"));

	return EXCEPTION_CONTINUE_SEARCH;
}

//运行异常处理
void RunCrashHandler()
{
	static bool bIni = false;
	if (!bIni)
	{
		SetUnhandledExceptionFilter(UnhandledExceptionFilterEx);
		PreventSetUnhandledExceptionFilter();
		bIni = true;
	}
}

在程序框架中实现函数RestartProcess()如下:

int RestartProcess(bool bNormal = true)
{
	PROCESS_INFORMATION info;
	STARTUPINFO startup;
	TCHAR szPath[128];
	TCHAR *szCmdLine;
	GetModuleFileName(AfxGetApp()-> m_hInstance, szPath, sizeof(szPath));
	szCmdLine = GetCommandLine();
	GetStartupInfo(&startup);
	BOOL bSucc = CreateProcess(szPath, szCmdLine, NULL, NULL,
		FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &startup, &info);
	if(bNormal && bSucc)
	{
		CWnd *pWnd = AfxGetMainWnd();
		if(pWnd != NULL)
		{
			pWnd->PostMessage(WM_CLOSE, 0, 0);
		}
		else
			ExitProcess(-1);
	}
	else
		ExitProcess(-1);

	return 0;
}

测试方法,在程序初始化的时候调用RunCrashHandler(),然后实现任意一个崩溃即可,比如数组越界或者除0,注意要防止代码被优化掉,如果异常代码被优化掉,则没有任何反应。

更多的交流,欢迎加入 暗号271888395

程序崩溃自动重启以及将未捕获到的异常写退出栈

  • 2010年06月28日 17:47
  • 1.12MB
  • 下载

android app崩溃后自动重启

1.偶然发现项目因为一场崩溃后,自动重启到上一界面。因为未知原因,重启后fragment显示有误,需要杀死进程后才能正常适应app。悲剧的是,因为马上就重启进程 了,导致LOG中看不到异常原因。非常不...
  • hunanqi
  • hunanqi
  • 2017-07-05 13:51:49
  • 1698

APP崩溃后自动重启

APP异常崩溃后重启
  • luzhenyuxfcy
  • luzhenyuxfcy
  • 2015-09-22 18:21:53
  • 1926

app崩溃后捕获异常或自动重启

假如你开发的app有这个需求的话:崩溃后自动重启。你可以参照下文:
  • caiwenfeng_for_23
  • caiwenfeng_for_23
  • 2014-11-16 23:20:09
  • 17527

如何监视一个进程,崩溃挂掉后自动重启

如何监视一个进程,崩溃挂掉后自动重启 2011-03-21 20:53 2239人阅读 评论(0) 收藏 举报 shell脚本服务器bashpathwindows 如何保证服务一...
  • robertzhouxh
  • robertzhouxh
  • 2013-09-03 13:08:58
  • 651

Android开发之app崩溃后捕获异常或自动重启

本文主要介绍如何实现app崩溃后捕获异常或自动重启,请看文章!
  • itluochen
  • itluochen
  • 2016-08-14 18:39:15
  • 5057

MFC 程序崩溃自动重启 和 未捕获到的异常写退出栈

MFC 程序崩溃自动重启 和 未捕获到的异常写退出栈   2013-09-11 09:39:04|  分类: VS编译集合|举报|字号 订阅      ...
  • boshuzhang
  • boshuzhang
  • 2016-07-29 19:54:00
  • 1717

如何让 App 在崩溃后自动重启

最近公司的项目出现了一点棘手的问题,由于某种未知的原因,该 App 在网络连接上出现了问题,只能用轮询来进行网络请求。但是这种方式会使得 App 每隔半小时就崩溃一次,最后无奈之下,决定让 App 在...
  • mouzhai
  • mouzhai
  • 2017-04-11 16:54:41
  • 238

Android异常崩溃Crash重启方案

在Android开发过程中,如果有Crash,我们往往想看到具体Crash的情景,但是在发布版本后,应用万一出现崩溃现象,就会出现一个弹窗说应用崩溃了,如果给用户看到,会有很大不良印象,如果是我,我觉...
  • qq_19711823
  • qq_19711823
  • 2016-05-17 11:39:36
  • 4578

【Android】App应用崩溃(Crash/Force Close)之后如何让它自动重启?

英文原文: Auto Restart application after Crash/Force Close in Android. 手机上的Android应用,经常会出现“Force Cl...
  • u010983881
  • u010983881
  • 2016-07-14 16:27:39
  • 3284
收藏助手
不良信息举报
您举报文章:配合UnhandledExceptionFilterEx()实现崩溃后自动重启
举报原因:
原因补充:

(最多只允许输入30个字)