想象一下要写一个不会因为异常而终止的程序---------有足够的内存,不会有非法的指针,并且要访问的文件也是始终存在,也不会发生死锁。在这样的条件下写代码一定时愉快的事情。代码将会容易编写,容易阅读,并且也容易理解。再也不需要为代码里随处可见的if语句等儿烦恼。
结构化异常处理(structured exception hangding,SEH)就可以为你解决这些事情它把主要功能编写和软件异常处理分开,让我们能集中注意力完成手头的工作,而后再去处理软件可能的异常。
SEH包含两方面功能:
1,终止处理;
2,异常处理;
一,终止处理
语法为:
try{
//Guarded body
...
}
_finally{
//Termination hander
...
}
除非在执行try块的时候调用了 ExitProcess,ExitThread ,TerminateProcess,TerminateThread(调用这几个函数引起的各种问题以后再叙述),否则_finally块内的代码一定能执行。
下面有几个小例子来解释系统如何执行代码。
1,Func1 (信号量的释放) 注释中的序号为代码执行顺序
DWORD Func1()
{
//1,
DWORD temp ;
......
_try{
//2,
......
WaitForSingleObject(g_hSem,INFINITE;
......
}
_finally{
//3,
ReleaseSemapore(g_Shem,1,NULL);
}
//4,
return temp;
}
这个例子看起来并没有给我们带来什么方便,它等待一个信号量,然后做一些操作后接着释放信号量资源。
下面我们稍微改动
2,Func2
DWORD Func2()
{
//1,
DWORD temp ;
......
_try{
//2,
......
WaitForSingleObject(g_hSem,INFINITE;
temp = 5;
......
return temp;
}
_finally{
//3,
printf("ReleaseSemapore\n");
ReleaseSemapore(g_Shem,1,NULL);
}
//4,
temp = 9;
return temp;
}
那对于这种情况呢?函数返回值是多少?
函数最后返回的是5,并且信号量最终也是释放了。虽然在_try块中调用return不是一个聪明的做法。
当return语句试图退出try块的时候,编译器会保证return在 finally块之后执行,而后面的代码自然就没机会执行了。
3,Func3
终止处理程序将真正证明它的价值。
DWORD Func1()
{
//1,
DWORD temp ;
......
_try{
//2,
......
WaitForSingleObject(g_hSem,INFINITE;
temp = FuncOther();
......
}
_finally{
//3,
ReleaseSemapore(g_Shem,1,NULL);
}
//4,
return temp;
}
假设FuncOther 存在一个缺陷会导致程序访问非法的内存。
如果没有SEH,这种情况下, 最终导致Windows错误报告,弹出终止对话框。一旦用户选择取消这个对话框,进程就会终止,但此时信号量没有释放,其他进程会无休止的等待。
而在SEH框架下,这个问题就得到完美的解决,信号量一定能得到释放。
二,异常处理
语法为:
try{
//Guarded body
...
}
_except(exception filter){
//exception hander
...
}
1,Func4
DWORD Funcmeister2()
{
DWORD dwTemp = 0;
//1. Do any processing here.
...
__try
{
//2. Perform some operation(s).
dwTemp = 5 / dwTemp; // Generates an exception
dwTemp += 10; // Never executes
}
__except(EXCEPTION_EXECUTE_HANDLER) //3
{
//4. Handle an exception.
MessageBeep(0);
...
}
//5. Continue processing.
return(dwTemp);
}
try块中,一个指令视图用5除以0,CPU会捕获到这个事件,并抛出一个硬件异常。当异常被抛出时,系统定位到exception块的开始处,并对异常过滤程序的表达式求值。
EXCEPTION_EXECUTE_HANDLER 1 异常执行处理
EXCEPTION_CONTINUE_SEARCH 0 异常继续查找
EXCEPTION_CONTINUE_EXECUTION -1 异常继续执行
异常处理过程如下图:
2,关于EXCEPTION_EXECUTE_HANDLER
这个值是告诉系统,我知道可能会产生这个异常,并且我要处理它。
处理过程完成后,程序会接下来执行exception块的下一条语句。
3,关于EXCEPTION_CONTINUE_EXECUTION
这个值是告诉系统,在执行了异常处理代码后,再次执行发送异常的那句代码。
4,EXCEPTION_CONTINUE_SEARCH
这个值是告诉系统,这里没有处理这个异常的代码,需要寻找最近的try块的异常处理程序。