1内容概述(文章的内容是什么)
首先介绍了本文的主要内容,然后依次介绍了为什么要对MFC进行异常处理、如何打印MFC系统的调用堆栈、如何捕获处理系统异常,最后完成了线程安全的系统日志类。
2背景(为什么需要这样做)
在进行MFC开发时,我们会遇到C++类的异常、各个组件厂商的自定义异常以及MFC系统的异常。C++类的异常和组件厂商的异常通常可以采用try catch逻辑捕获处理,MFC系统的异常通常是采用__try __except逻辑处理,虽然有所不同,但是对于使用者意义都是可以理解的。但是这样使用时,在一个函数内两种逻辑是不能混用的,通常将不同的异常处理封装在不同的函数内来达到这样的球球,这样我们在开发时除了关心业务逻辑还要考虑这个问题,十分麻烦。所以需要将异常整合。
在实际工作中我们经常遇到某种情况下系统崩溃了出错了,这种异常难以在办公室重现,而采用__try __except逻辑处理我们仅能知道发了异常对具体的哪行出现了问题也是不清楚,不利于问题解决。需要对__try __except中出错的位置打印出错误调用堆栈。
日志文件不可或缺,出现问题,拿出日志文件分析出错的位置和原因。
3主要内容
3.1 打印MFC异常调用堆栈信息
因为MFC发生异常时,可以通过调用GetExceptionInformation()获取发生异常时的寄存器值,通过这些值配合StackWalk、SymGetLineFromAddr函数可以近似求出调用堆栈(需要编译的PDB文件在exe的同一目录下)
3.2 整合异常的捕获
需要通过异常转换将SHE异常转换成trycatch可以捕获的异常,整合异常处理。通过_set_se_translator注册异常处理函数,在函数内throw 标准异常。
3.3 线程安全日志类
该类实现线程安全打印日志到文件,单独启动线程实现日志写入,不会堵塞函数执行。
4 主要代码
// Log.h: interface for the Log class.
//
//
#if !defined(AFX_LOG_H__C2109AE4_5C0C_4E00_9E17_9E2CA531B6EC__INCLUDED_)
#define AFX_LOG_H__C2109AE4_5C0C_4E00_9E17_9E2CA531B6EC__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "LockableQueue.h"
#include "provider.h"
#include "Thread.h"
#include "eh.h"
class LogSEHTrans{
public:
//仅对当前线程有效,多线程使用时每个线程都需要声明
static void DeclareSEHTransForThisThread()
{
_set_se_translator(TranslateSEH2CE);
}
PEXCEPTION_POINTERS GetPEXCEPTION_POINTERS()
{
return &mPep;
}
private:
static void _cdecl TranslateSEH2CE(UINT dwEC, PEXCEPTION_POINTERS pep)
{
throw LogSEHTrans(pep);
}
LogSEHTrans(PEXCEPTION_POINTERS pep)
{
mContext = *pep->ContextRecord;
mEr = *pep->ExceptionRecord;
mPep.ContextRecord = &mContext;
mPep.ExceptionRecord = &mEr;
}
private:
EXCEPTION_POINTERS mPep;
EXCEPTION_RECORD mEr;
CONTEXT mContext;
};
class MsgClass
{
public :
char info[1024];
void Fill(char*buffer)
{
SYSTEMTIME m_SystemTime;
GetLocalTime(&m_SystemTime);
sprintf_s(info, "%02d%02d%02d%03d,%d,%s\r\n", m_SystemTime.wHour, m_SystemTime.wM