摘自《Windows驱动开发技术详解》
1. 机构化异常处理(try-except块)
		
				
						      
				
				结构化异常处理(
				SHE, Structured Exception Handling
				)是微软编译器提供的独特处理机制,这种处理方式能在一定程度上在出现错误的情况下,避免程序崩溃。先说明两个概念。
				
						
						
				
		
		
				
						(1)
				
				异常:异常的概念类似于中断的概念,当程序中某中错误触发一个异常,操作系统会寻找处理这个异常的处理函数。如果程序提供异常处理函数,则进入该函数,否则由操作系统提供的默认异常处理函数处理。在内核模式下,操作系统默认处理错误的方法是直接让系统蓝屏,并在蓝屏上简单描述出错的信息。
				
						
						
				
		
		
				
						(2)
				
				回卷:程序执行到某个地方出现异常错误时,系统会寻找出错点是否处于一个
				try{}
				块中,并进入
				try
				块提供的异常处理代码。如果当前
				try
				块没有提供异常处理,则会向更外一层的
				try
				块寻找异常处理代码,直到最外层
				try
				块也没有提供异常处理代码,则交由操作系统处理。这种向更外一层寻找异常处理的机制,被称为回卷。
				
						
						
				
		
		
				一般处理异常,是通过
				try-except
				块来处理的。
				
						
						
				
		
		
				__try
		
		
				{
		
		
				//your normal code
		
		
				}
		
		
				__except(filter_value)
		
		
				{
		
		
				
						       //your operate code
		
		
				}
		
		
				在被
				__try{}
				包围的块中,如果出现异常,会根据
				filter_value
				的数值,判断是否需要在
				__except{}
				块中处理。
				filter_value
				的数组会有三种可能。
				
						
						
				
		
		
				
						(1)                
				
				EXCEPTION_EXECUTE_HANDLE
				,该数值为
				1
				。进入到
				__except
				进行错误处理,处理完后不再回到
				__try{}
				块中,转而继续执行下面的代码。
				
						
						
				
		
		
				
						(2)                
				
				EXCEPTION_CONTINUE_SEARCH
				,该数值为
				0
				。不进入
				__except
				块中的异常处理,而是向上一层回卷。如果已经是最外层,则向操作系统请求异常处理函数。
				
						
						
				
		
		
				
						(3)                
				
				EXCEPTION_CONTINUE_EXECUTION
				,该数值为
				-1
				。重复先去错误的指令,这个在驱动程序中很少用到。
				
						
						
				
		
		
				下面一段代码是用来检测某段内存是否可读写,这段代码通过
				try-except
				来探测指针的地址是否可写。
				
						
						
				
		
		
				VOID ProbeTest()
		
		
				{
		
		
				
						       PVOID pBad = NULL;
		
		
				
						       KdPrint((“Enter ProbeTest\n”));
		
		
				
						       __try
		
		
				{
		
		
				
						       KdPrint((“Enter __try block\n”));
		
		
				
						       //
				判断空指针是否可写,显然会导致异常
		
		
				
						       ProbeForWrite(pBad, 100, 4);
		
		
				
						       //
				由于在上面引发异常,所以下面语句不会被执行
		
		
				
						       KdPrint((“Leave __try block\n”));
		
		
				}
		
		
				__except(EXCEPTION_EXCUTE_HANDLE)
		
		
				{
		
		
				
						       KdPrint((“Catch the exception\n”));
		
		
				
						       KdPrint((“The program will keep going\n”));
		
		
				}
		
		
				//
				该语句会被执行
		
		
				KdPrint((“Leave ProbeTest\n”));
		
		
				}
		
		
				
						      
				
				除了处理异常之外,
				DDK
				还提供了一些函数用来触发异常。如表
				1
				所示:
				
						
						
				
		
		
				表
				1
				:
				触发异常函数
		
		
				
						
								
										| 
														函数
												 | 
														描述
												 | 
								
										| 
														ExRaiseStatus
												 | 
														用指定状态代码触发异常
												 | 
								
										| 
														ExRaiseAccessViolatioin
												 | 
														触发
														STATUS_ACCESS_VILOATION
														异常
												 | 
								
										| 
														ExRaiseDatatypeMisalignment
												 | 
														触发
														STATUS_DATATYPE_MISALIGNMENT
														异常
												 | 
						
				
		 
		
				
						 
				
		
		
				2. 
				结构化异常处理(
				try-finally
				块)
				
						
						
				
		
		
				
						      
				
				结构化异常处理还有另外一种使用方法,就是利用
				try-finally
				块,强迫函数在退出前执行一段代码。
				
						
						
				
		
		
				NTSTATUS TryFinallyTest()
		
		
				{
		
		
				NTSTATUS status  = STATUS_SECCESS;
		
		
				__try
		
		
				{
		
		
				
						       //your normal code
		
		
				
						       return status;
		
		
				}
		
		
				__finally
		
		
				{
		
		
				
						       //
				程序退出前必然运行到此
		
		
				
						       KdPrint((“Enter finally block\n”));
		
		
				}
		
		
				}
		
		
				
						      
				
				上面代码的
				__try{}
				块中,无论运行什么代码(即使是
				return
				语句或者触发异常),在程序退出前都会运行
				__finally{}
				块中的代码。这样的目的是,在退出前需要运行一些资源回收的工作,而资源回收代码的最佳位置就是放在这个块中。
				
						
						
				
		
		
				
						      
				
				此外,使用
				try-finally
				块还可以在某种程度上简化代码。比较下面两段代码,其中地一段是没有使用
				try-finally
				块的代码,而第二段是使用了
				try-finally
				。可以看出,第二段代码比第一段代码清晰明了。
				
						
						
				
		
		
				第一段代码:
				
						
						
				
		
		
				VOID FooTest()
		
		
				{
		
		
				
						       NTSTATUS status = STATUS_SUCCESS;
		
		
				
						       //
				执行操作
				1
		
		
				
						       status = Foo1();
		
		
				
						       //
				判断操作是否成功
		
		
				
						       if (!NT_SUCCESS(status))
		
		
				
						       {
		
		
				
						              //
				回收资源
		
		
				
						              return status;
		
		
				}
		
		
				
						 
				
		
		
				//
				执行操作
				2
		
		
				
						       status = Foo2();
		
		
				
						       //
				判断操作是否成功
		
		
				
						       if (!NT_SUCCESS(status))
		
		
				
						       {
		
		
				
						              //
				回收资源
		
		
				
						              return status;
		
		
				}
		
		
				
						 
				
		
		
				//
				执行操作
				n
		
		
				
						       status = FooN();
		
		
				
						       //
				判断操作是否成功
		
		
				
						       if (!NT_SUCCESS(status))
		
		
				
						       {
		
		
				
						              //
				回收资源
		
		
				
						              return status;
		
		
				}
		
		
				
						 
				
		
		
				return status;
		
		
				}
		
		
				第二段代码:
				
						
						
				
		
		
				VOID FooTest()
		
		
				{
		
		
				
						       NTSTATUS status = STATUS_SUCCESS;
		
		
				
						       __try
		
		
				{
		
		
				
						       //
				执行操作
				1
		
		
				
						       status = Foo1();
		
		
				
						       //
				判断操作是否成功
		
		
				
						       if (!NT_SUCCESS(status))
		
		
				
						       {
		
		
				
						              return status;
		
		
				}
		
		
				
						 
				
		
		
				//
				执行操作
				1
		
		
				
						       status = Foo2();
		
		
				
						       //
				判断操作是否成功
		
		
				
						       if (!NT_SUCCESS(status))
		
		
				
						       {
		
		
				
						              return status;
		
		
				}
		
		
				
						 
				
		
		
				//
				执行操作
				n
		
		
				
						       status = Foo1();
		
		
				
						       //
				判断操作是否成功
		
		
				
						       if (!NT_SUCCESS(status))
		
		
				
						       {
		
		
				
						              return status;
		
		
				}
		
		
				}
		
		
				__finally
		
		
				{
		
		
				
						       //
				回收资源
		
		
				}
		
		
				return status;
		
		
				}