全部博文(668)
分类:
2008-08-07 09:07:48
为什么要 把 SEH 类型的系统异常转化为 C++ 类型的异常?
做一件事情之前,我们最好要搞清为什么!“十万个为什么” 可曾造就了多少顶级奇才!呵呵! WHY? ? WHY ? WHY ?这对任何一个人来说,都绝对是个好习惯,阿愚同学就一直把这个当“宝贝”。那么,究竟 为什么要 把 SEH 类型的系统异常转化为 C++ 类型的异常?朋友们,大家都想想,整理整理自己的意见和想法。这里,阿愚给出它个人的理解,如下:
如何实现 把 SEH 类型的系统异常转化为 C++ 类型的异常?
虽然说把 SEH 类型的系统异常转化为 C++ 类型的异常,给 C++ 程序员带来的是好处多多,但是实现起来并不复杂,因为系统底层和 VC 运行库已经为我们铺路搭桥了,也即我们可以通过 VC 运行库中的“ _ set_se_translator ”函数来轻松搞定它。 MSDN 中对它解释如下:
Handles Win32 exceptions (C structured exceptions) as C++ typed exceptions.
typedef void (*_se_translator_function)( unsigned int, struct _EXCEPTION_POINTERS* );
_se_translator_function _set_se_translator( _se_translator_function se_trans_func );
The _set_se_translator function provides a way to handle Win32 exceptions (C structured exceptions) as C++ typed exceptions. To allow each C exception to be handled by a C++ catch handler, first define a C exception “wrapper” class that can be used, or derived from, in order to attribute a specific class type to a C exception. To use this class, install a custom C exception translator function that is called by the internal exception-handling mechanism each time a C exception is raised. Within your translator function, you can throw any typed exception that can be caught by a matching C++ catch handler.
To specify a custom translation function, call _set_se_translator with the name of your translation function as its argument. The translator function that you write is called once for each function invocation on the stack that has try blocks. There is no default translator function.
In a multithreaded environment, translator functions are maintained separately for each thread. Each new thread needs to install its own translator function. Thus, each thread is in charge of its own translation handling.
The se_trans_func function that you write must take an unsigned integer and a pointer to a Win32 _EXCEPTION_POINTERS structure as arguments. The arguments are the return values of calls to the Win32 API GetExceptionCode and GetExceptionInformation functions, respectively.
至于 _ set_se_translator 函数的具体机制,以及 把系统异常转化为 C++ 类型的异常的原理这里不再详细讨论,而仅仅是给出了大致的工作流程: 首先,通过 _ set_se_translator 函数设置一个对所有的 系统异常产生作用的回调处理函数(也是与 TLS 数据有关);因此,每当程序运行时产生了系统异常之后,前面我们设置的自定义回调函数于是便会接受程序的控制权;接着,我们在该函数的实现中,可以根据不同类型的系统异常( EXCEPTION_POINTERS ),来分别抛出一个 C++ 类型的异常错误 。呵呵!简单吧!不再白话了,还是来瞧瞧阿愚所设计的一个简单演示例程吧!代码如下:
// FILENAME:SEH-test.cpp
#include
#include
#include
#include
#include
using namespace std;
////////////////////////////////////////////////////////////////////////////////
class seh_exception_base : public std::exception
{
public:
seh_exception_base (const PEXCEPTION_POINTERS pExp, std::string what )
: m_ExceptionRecord(*pExp->ExceptionRecord),
m_ContextRecord(*pExp->ContextRecord),
m_what(what){};
~seh_exception_base() throw(){} ;
virtual const char* what() const throw()
{
return m_what.c_str();
}
virtual DWORD exception_code() const throw()
{
return m_ExceptionRecord.ExceptionCode;
}
virtual const EXCEPTION_RECORD& get_exception_record() const throw()
{
return m_ExceptionRecord;
}
virtual const CONTEXT& get_context() const throw()
{
return m_ContextRecord;
}
// 初始化函数
static void initialize_seh_trans_to_ce()
{
_set_se_translator( trans_func );
}
// 系统异常出现时的回调函数
static void trans_func( unsigned int u, EXCEPTION_POINTERS* pExp );
protected:
std::string m_what;
EXCEPTION_RECORD m_ExceptionRecord;
CONTEXT m_ContextRecord;
};
////////////////////////////////////////////////////////////////////////////////
// 下面是系统异常被转换后的 C++ 类型的异常
// 篇幅有限,因此只简单设计了对几种常见的系统异常的转换
////////////////////////////////////////////////////////////////////////////////
class seh_exception_access_violation : public seh_exception_base
{
public:
seh_exception_access_violation (const PEXCEPTION_POINTERS pExp, std::string what)
: seh_exception_base(pExp, what) {};
~seh_exception_access_violation() throw(){};
};
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
class seh_exception_divide_by_zero : public seh_exception_base
{
public:
seh_exception_divide_by_zero (const PEXCEPTION_POINTERS pExp, std::string what)
: seh_exception_base(pExp, what) {};
~seh_exception_divide_by_zero() throw(){};
};
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
class seh_exception_invalid_handle : public seh_exception_base
{
public:
seh_exception_invalid_handle (const PEXCEPTION_POINTERS pExp, std::string what)
: seh_exception_base(pExp, what) {};
~seh_exception_invalid_handle() throw(){};
};
////////////////////////////////////////////////////////////////////////////////
// 系统异常出现时的回调函数
// 这里是实现,很关键。针对不同的异常,抛出一个 C++ 类型的异常
void seh_exception_base::trans_func( unsigned int u, EXCEPTION_POINTERS* pExp )
{
switch(pExp->ExceptionRecord->ExceptionCode)
{
case EXCEPTION_ACCESS_VIOLATION :
throw seh_exception_access_violation(pExp, " 保护异常 ");
break;
case EXCEPTION_INT_DIVIDE_BY_ZERO :
throw seh_exception_divide_by_zero(pExp, " 被 0 除异常 ");
break;
case EXCEPTION_INVALID_HANDLE :
throw seh_exception_invalid_handle(pExp, " 无效句病异常 ");
break;
default :
throw seh_exception_base(pExp, " 其它 SEH 异常 ");
break;
}
}
// 来测试吧!
void main( void )
{
seh_exception_base::initialize_seh_trans_to_ce();
try
{
// 被 0 除
int x, y=0;
x = 5 / y;
// 存储保护
char* p =0;
*p = 0;
// 其它系统异常,例如中断异常
__asm int 3;
}
catch( seh_exception_access_violation& e )
{
printf( "Caught SEH_Exception. 错误原因: %s\n", e.what());
//other processing
}
catch( seh_exception_divide_by_zero& e )
{
printf( "Caught SEH_Exception. 错误原因: %s\n", e.what());
//other processing
}
catch( seh_exception_base& e )
{
printf( "Caught SEH_Exception. 错误原因: %s, 错误代码: %x\n", e.what(), e.exception_code());
}
}
总结
语言中的异常处理模型是踩着 C++ 异常处理模型肩膀上过来的。它继承了 C++ 异常处理模型的风格和优点,同时,它也比 C++ 异常处理模型更,更可高,更强大和更丰富。下一篇文章中,主人公阿愚打算乘胜追击,来讨论一些关于 Java 语言中的异常处理模型。感兴趣的 朋友们,继续吧!