在windows SEH機制注釋(1) 基于ReactOS 一文中,注釋了try/except宏,windows的SEH機制除了這對宏,還有try/finall宏,用來執行善後處理。相比try/except,try/finall簡單很多,沒有繞人的長跳轉,基本上屬于順序處理流程。如下:
1.
func()
{
_SEH_TRY
{
//do sth
_asm int 0x03;
}
_SEH_FINALLY(FINALLY_)
{
status = _SEH_GetExceptionCode();
}
_SEH_END
}
2.宏擴充
func()
{
for(;;)
{
_SEH_INIT_CONST int _SEHTopTryLevel = (_SEHScopeKind != 0);
_SEHPortableFrame_t * const _SEHCurPortableFrame = _SEHPortableFrame;
_SEHPortableTryLevel_t * const _SEHPrevPortableTryLevel = _SEHPortableTryLevel;
{
_SEH_INIT_CONST int _SEHScopeKind = 0;
register int _SEHState = 0;
register int _SEHHandle = 0;
_SEHFrame_t _SEHFrame;
_SEHTryLevel_t _SEHTryLevel;
_SEHPortableFrame_t * const _SEHPortableFrame =
_SEHTopTryLevel ? &_SEHFrame.SEH_Header : _SEHCurPortableFrame;
_SEHPortableTryLevel_t * const _SEHPortableTryLevel = &_SEHTryLevel.ST_Header;
(void)_SEHScopeKind;
(void)_SEHPortableFrame;
(void)_SEHPortableTryLevel;
(void)_SEHHandle;
for(;;)
{
if(_SEHState)
/*
初始時_SEHState為0,進入SEH_FINALL!else分支,設定SEH處理結構__SEHTryLevel
*/
{
for(;;)
{
{
<-try/
{
//(1)
//do sth,如果發生異常,沒有跳轉,确切的說是由系統在fs:[0]中查找上一層堆棧中提供的處理函數
//如果沒有發生異常,順序的執行到(2)處,執行善後處理
_asm int 0x03;
}
finall ->/
}
break;
}
_SEHPortableFrame->SPF_TopTryLevel = _SEHPrevPortableTryLevel;
break;
}
else
{
_SEHTryLevel.ST_Header.SPT_Handlers.SH_Filter = 0;
/*
FINALLY_由_SEH_FINALLY(FINALLY_)傳入,設定收尾函數
*/
_SEHTryLevel.ST_Header.SPT_Handlers.SH_Finally = (FINALLY_);
_SEHTryLevel.ST_Header.SPT_Next = _SEHPrevPortableTryLevel;
_SEHFrame.SEH_Header.SPF_TopTryLevel = &_SEHTryLevel.ST_Header;
if(_SEHTopTryLevel)
{
if(&_SEHLocals != _SEHDummyLocals)
_SEHFrame.SEH_Locals = &_SEHLocals;
_SEH_EnableTracing(_SEH_DO_DEFAULT_TRACING);
_SEHFrame.SEH_Header.SPF_Handler = _SEHCompilerSpecificHandler;
_SEHEnterFrame(&_SEHFrame.SEH_Header);
}
/*
經過++ _SEHState;
continue;
程式進入if(_SEHState),執行受保護的代碼(其實不算受保護的代碼,與
SEH_Except相比少了長跳轉)
*/
++ _SEHState;
continue;
}
//(2)
break;
}
// _SEH_FINALLY(FINALLY_)
/*
執行這個回調有2種可能
1.執行完(1)後,一路break出來,執行善後函數或者
2.執行(1)時遇到異常,進入異常處理過程。期間執行unwind時會調用
(SEHTryLevel.ST_Header.SPT_Handlers.SH_Finally)(&_SEHFrame.SEH_Header);
*/
(FINALLY_)(&_SEHFrame.SEH_Header);
if(0)
{
//
{
status = _SEH_GetExceptionCode();
}
//
}
}
if(_SEHTopTryLevel)
_SEHLeaveFrame();
break;
}
}