主要參考:http://blog.csdn.net/hbrr224/archive/2006/05.aspx
SEH 的工作原理。
???????? Windows 程序設(shè)計(jì)中最重要的理念就是消息傳遞,事件驅(qū)動。當(dāng)GUI應(yīng)用程序觸發(fā)一個消息時(shí),系統(tǒng)將把該消息放入消息隊(duì)列,然后去查找并調(diào)用窗體的消息處理函數(shù)(CALLBACK),傳遞的參數(shù)當(dāng)然就是這個消息。我們同樣可以把異常也當(dāng)作是一種消息,應(yīng)用程序發(fā)生異常時(shí)就觸發(fā)了該消息并告知系統(tǒng)。系統(tǒng)接收后同樣會找它的“回調(diào)函數(shù)”,也就是我們的異常處理例程。當(dāng)然,如果我們在程序中沒有做異常處理的話,系統(tǒng)也不會置之不理,它將彈出我們常見的應(yīng)用程序錯誤框,然后結(jié)束該程序。所以,當(dāng)我們改變思維方式,以CALLBACK 的思想來看待 SEH,SEH 將不再神秘。
SEH 是 Windows 系統(tǒng)提供的功能,跟開發(fā)工具無關(guān)。值得一提的是,VC 將 SEH 進(jìn)行了封裝 try? catch? finally,c++中也可以用c的封裝 __try{}__except(){} 和 __try{}__finally{}. 所以當(dāng)你建立一個C++ try塊時(shí),編譯器就生成一個S E H_ _t r y塊。一個C + +c a t c h測試變成一個S E H異常過濾器,并且c a t c h中的代碼變成S E H_ _e x c e p t塊中的代碼。實(shí)際上,當(dāng)你寫一條C++ throw語句時(shí),編譯器就生成一個對Wi n d o w s的R a i s e E x c e p t i o n函數(shù)的調(diào)用。用于t h r o w語句的變量傳遞給R a i s e E x c e p t i o n作為附加的參數(shù)。
一個簡單的使用SEH的例子
假如要實(shí)現(xiàn)一個完全強(qiáng)壯的應(yīng)用程序,該程序需要每周7天,每天2 4小時(shí)運(yùn)行。在今天的世界里,軟件變得這么復(fù)雜,有那么多的變量和因子來影響程序的性能,筆者認(rèn)為如果不用S E H,要實(shí)現(xiàn)完全強(qiáng)壯的應(yīng)用程序簡直是不可能的。我們先來看一個樣板程序,即C的運(yùn)行時(shí)函數(shù)s t r c p y:
char
*
?strcpy(
???
char
*
?strDestination,
???
const
?
char
*
?strSource);
這是一個相當(dāng)簡單的函數(shù),它怎么會引起一個進(jìn)程結(jié)束呢?如果調(diào)用者對這些參數(shù)中的某一個傳遞N U L L(或任何無效的地址),s t r c p y就引起一個存取異常,并且導(dǎo)致整個進(jìn)程結(jié)束。
使用S E H,就可以建立一個完全強(qiáng)壯的s t r c p y函數(shù):
char
*
?RobustStrCpy(
char
*
?strDestination,?
const
?
char
*
?strSource)

{
???__try?

???
{
??????strcpy(strDestination,?strSource);
???}
???__except(EXCEPTION_EXECUTE_HANDLER)

???
{
??????
//
?Nothing?to?do?here
???}
???
return
(strDestination);
}
這個函數(shù)所做的一切就是將對s t r c p y的調(diào)用置于一個結(jié)構(gòu)化的異常處理框架中。如果s t r c p y執(zhí)行成功,函數(shù)就返回。如果s t r c p y引起一個存取異常,異常過濾器返回E X C E P T I O N _E X E C U T E _ H A N D L E R,導(dǎo)致該線程執(zhí)行異常處理程序代碼。在這個函數(shù)中,處理程序代碼什么也不做,R o b u s t S t r C p y只是返回到它的調(diào)用者,根本不會造成進(jìn)程結(jié)束。
另一個使用:
#include?
"
stdio.h
"
void
?test()

{
int
*
?p?
=
?
0x00000000
;?
//
?pointer?to?NULL
__try

{
puts(
"
in?try
"
);
__try

{
puts(
"
in?try
"
);

//
?causes?an?access?violation?exception;
//
?導(dǎo)致一個存儲異常
*
p?
=
?
13
;?

//
?呵呵,注意這條語句
puts(
"
這里不會被執(zhí)行到
"
);
}
__finally

{
puts(
"
in?finally
"
);
}
//
?呵呵,注意這條語句
puts(
"
這里也不會被執(zhí)行到
"
);
}
__except(puts(
"
in?filter?1
"
),?
0
)

{
puts(
"
in?except?1
"
);
}
}
void
?main()

{
puts(
"
hello
"
);
__try

{
test();
}
__except(puts(
"
in?filter?2
"
),?
1
)

{
puts(
"
in?except?2
"
);
}
puts(
"
world
"
);
}
?
上面的程序運(yùn)行結(jié)果如下:
hello
in try
in try
in filter 1
in filter 2
in finally
in except 2
world
Press any key to continue
另一個混合c++的異常處理使用:
// 注意,這是 C++ 程序,文件名為: SEH-test.cpp
#include?
"
stdio.h
"
?

class
?A?


{?

public
:?


void
?f1()?
{}
?

//
?拋出?C++?異常?
void
?f2()?
{?
throw
?
888
;}
?

}
;?

//
?這個函數(shù)中使用了?try-catch?處理異常,也即?C++?異常處理?
void
?test1()?


{?

A?a1;?

A?a2,a3;?

try
?


{?

a2.f1();?

a3.f2();?

}
?

catch
(
int
?errorcode)?


{?

printf(
"
catch?exception,error?code:%d\n
"
,?errorcode);?

}
?

}
?

//
?這個函數(shù)沒什么改變,仍然采用?try-except?異常機(jī)制,也即?SEH?機(jī)制?
void
?test()?


{?

int
*
?p?
=
?
0x00000000
;?
//
?pointer?to?NULL?
__try?


{?

//
?這里調(diào)用?test1?函數(shù)?
test1();?

puts(
"
in?try
"
);?

__try?


{?

puts(
"
in?try
"
);?

//
?causes?an?access?violation?exception;?

//
?導(dǎo)致一個存儲異常?
*
p?
=
?
13
;?

puts(
"
?這里不會被執(zhí)行到?
"
);?

}
?

__finally?


{?

puts(
"
in?finally
"
);?

}
?

puts(
"
?這里也不會被執(zhí)行到?
"
);?

}
?

__except(puts(
"
in?filter?1
"
),?
0
)?


{?

puts(
"
in?except?1
"
);?

}
?

}
?

void
?main()?


{?

puts(
"
hello
"
);?

__try?


{?

test();?

}
?

__except(puts(
"
in?filter?2
"
),?
1
)?


{?

puts(
"
in?except?2
"
);?

}
?

puts(
"
world
"
);?

}
?

上面程序不僅能夠被編譯通過,而且運(yùn)行結(jié)果也是正確的(和預(yù)期的一樣,同樣符合 C++ 異常處理模型的規(guī)則,和 SEH 異常模型的處理規(guī)則)。其結(jié)果如下:
hello
catch exception,error code:888
in try
in try
in filter 1
in filter 2
in finally
in except 2
world
Press any key to continue
主要參考:http://blog.csdn.net/hbrr224/archive/2006/05.aspx