1. 程式人生 > >windows核心程式設計--SEH(結構異常處理)

windows核心程式設計--SEH(結構異常處理)

SEH 的工作原理。
         Windows 程式設計中最重要的理念就是訊息傳遞,事件驅動。當GUI應用程式觸發一個訊息時,系統將把該訊息放入訊息佇列,然後去查詢並呼叫窗體的訊息處理函式(CALLBACK),傳遞的引數當然就是這個訊息。我們同樣可以把異常也當作是一種訊息,應用程式發生異常時就觸發了該訊息並告知系統。系統接收後同樣會找它的“回撥函式”,也就是我們的異常處理例程。當然,如果我們在程式中沒有做異常處理的話,系統也不會置之不理,它將彈出我們常見的應用程式錯誤框,然後結束該程式。所以,當我們改變思維方式,以CALLBACK 的思想來看待 SEH,SEH 將不再神祕。

SEH 是 Windows 系統提供的功能,跟開發工具無關。值得一提的是,VC 將 SEH 進行了封裝 try  catch  finally,c++中也可以用c的封裝 __try{}__except(){} 和 __try{}__finally{}. 所以當你建立一個C++ try塊時,編譯器就生成一個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塊中的程式碼。實際上,當你寫一條C++ throw語句時,編譯器就生成一個對Wi n d o w s的R a i s e E x c e p t i o n函式的呼叫。用於t h r o w語句的變數傳遞給R a i s e E x c e p t i o n作為附加的引數。

r_no157.gif 
一個簡單的使用SEH的例子

假如要實現一個完全強壯的應用程式,該程式需要每週7天,每天2 4小時執行。在今天的世界裡,軟體變得這麼複雜,有那麼多的變數和因子來影響程式的效能,筆者認為如果不用S E H,要實現完全強壯的應用程式簡直是不可能的。我們先來看一個樣板程式,即C的執行時函式s t r c p y:

 char *  strcpy(
    char *  strDestination,
    const   char *  strSource);


這是一個相當簡單的函式,它怎麼會引起一個程序結束呢?如果呼叫者對這些引數中的某一個傳遞N U L L(或任何無效的地址),s t r c p y就引起一個存取異常,並且導致整個程序結束。
使用S E H,就可以建立一個完全強壯的s t r c p y函式:

 char *  RobustStrCpy( char *  strDestination,  const   char *  strSource)
 {
   __try 
    {
      strcpy(strDestination, strSource);
   } 

   __except(EXCEPTION_EXECUTE_HANDLER)
    {
       //  Nothing to do here 
 
   } 

 
    return (strDestination);

 


這個函式所做的一切就是將對s t r c p y的呼叫置於一個結構化的異常處理框架中。如果s t r c p y執行成功,函式就返回。如果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,導致該執行緒執行異常處理程式程式碼。在這個函式中,處理程式程式碼什麼也不做,R o b u s t S t r C p y只是返回到它的呼叫者,根本不會造成程序結束。

另一個使用:

 #include  " stdio.h " 
 
 void  test()
 {
 int *  p  =   0x00000000 ;  //  pointer to NULL 
 

__try
 {
puts( " in try " );
__try
 {
puts( " in try " );

 //  causes an access violation exception;
 //  導致一個儲存異常 
 
* p  =   13 ; 

 //  呵呵,注意這條語句 
 
puts( " 這裡不會被執行到 " );

__finally
 {
puts( " in finally " );

 
 //  呵呵,注意這條語句 
 
puts( " 這裡也不會被執行到 " );

__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 " );

上面的程式執行結果如下:
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 ;}  



 //  這個函式中使用了 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); 

 

 

 //  這個函式沒什麼改變,仍然採用 try-except 異常機制,也即 SEH 機制  
 

 void  test() 

 

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

__try 

 

 //  這裡呼叫 test1 函式  
 

test1(); 

puts( " in try " ); 

__try 

 

puts( " in try " ); 

 //  causes an access violation exception; 

 //  導致一個儲存異常  
 

 * p  =   13 ; 

puts( "  這裡不會被執行到  " ); 

 

__finally 

 

puts( " in finally " ); 

 

puts( "  這裡也不會被執行到  " ); 

 

__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 " ); 

 


上面程式不僅能夠被編譯通過,而且執行結果也是正確的(和預期的一樣,同樣符合 C++ 異常處理模型的規則,和 SEH 異常模型的處理規則)。其結果如下:

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