鱼C论坛

 找回密码
 立即注册

SEH 的工作原理

热度 6已有 2657 次阅读2011-4-5 15:33 |个人分类:系统篇|

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;
 //  导致一个存储异常 
 
*  =   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; 

 //  导致一个存储异常  
 

 
*  =   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 

1

路过

雷人

握手
5

鲜花

鸡蛋

刚表态过的朋友 (6 人)

发表评论 评论 (1 个评论)

回复 我是桃川人 2012-7-18 16:15
没看懂

facelist

您需要登录后才可以评论 登录 | 立即注册

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-10-25 03:25

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

返回顶部