错误处理程序的设计
错误处理程序是在你编写的应用程序中捕获错误和作出响应的例程。你应在你认为可能出现错误的过程中添加错误处理程序(除非你可明确判定,否则应假定任何Visual Basic 语句都可能产生错误)。错误处理程序设计的步骤如下:
1. 设置或使一个错误陷井有效,以告诉应用程序发生错误时转移到何处(错误处理例程将运行)。
On Error语句使错误陷井有效,并为应用程序指定错误处理例程从标有标签处开始。
在前面的示例中,FileExists函数包含一个名为CheckError的错误处理例程。
2. 编写一个响应你可预测的所有错误的错误处理例程。如果在某个点上,控制流实际转移到陷井中,此时陷井处于激活状态。
CheckError例程使用一个If...Then...Else语句来响应Err对象的Number属性值(Number属性是响应Visual Basic 错误的一个数值参数),从而实现错误的处理。示例中,在产生“磁盘未准备好”的错误时,为用户显示要求关上软驱门的信息提示;在产生“驱动器无效”的错误时,为用户显示另一信息提示。如果发生其他错误,则显示相应的描述,并中止程序。
3. 退出错误处理例程。
出现“磁盘未准备好”的错误时,Resume语句使代码转回到发生错误的语句处。然后Visual Basic 将试着重新运行那个语句。如果条件未发生改变,就会再次发生错误,并转回到错误处理例程。
出现“驱动器无效”的错误时,Resume Next语句使代码转回到紧接着发生错误的语句之后的语句处。
本主题的余下部分对如何执行这些步骤进行了详细论述。在阅读这些步骤时,请参阅前面示例中的FileExists函数。
设置错误陷井
当Visual Basic 运行错误处理程序指定的On Error语句时,错误陷井被激活。当包含错误陷井的过程处于激活状态时,该错误陷井是有效的—也就是说,在运行Exit Sub、Exit Function、Exit Property、End Sub、End Function或End Property语句前,过程中的错误陷井是有效的。在任何给定的过程中,任何时候都只能有一个错误陷井有效,你可创建多个备用的错误陷井,并在不同时间内分别激活它们。使用On Error语句的特殊形式On Error GoTo 0来禁止某一错误陷井。
使用On Error GoTo line语句,设置从错误陷井跳转到一个错误处理程序中,其中line 参数指定识别错误处理代码的标签。在FileExists函数示例中的标签为CheckError(虽然冒号是标签的组成部分,但在On Error GoTo line语句中不用冒号)。
编写错误处理例程
编写错误处理例程的第一步是添加行标签,以标识错误处理例程的开始。行标签应具有一个描述性名称,而且必须在其后加上冒号。编写时的习惯做法是把错误处理代码置于过程的结尾处,即行标签在Eixt Sub 、Exit Function或Exit Property语句后。这可避免过程中无错误发生时错误处理代码的执行。
错误处理例程的主体包括实际处理错误的代码,通常采用Select Case或If ...Then...Else语句。你需要确定可能发生哪些错误,并为每个错误提供相应的处理措施,如在出现“磁盘未准备好”错误时,提示用户插入磁盘。通常需要使用Else或Case Else条件从句来提供一个处理任何预计外错误的选项,在前面的FileExists函数示例中,该选项是警告用户并结束应用程序。
Err对象的Number属性包含一个代表最近发生的运行时错误的数值代码。Err对象与Select Case或If...Then...Else语句的结合使用,可使你对发生的任何错误采取特定的措施。
退出错误处理例程
在FileExists函数示例中,错误处理程序使用了Resume语句,以从产生错误的语句处恢复运行;使用Resume Next语句,以从紧随产生错误语句的下一语句处恢复运行。还可采用其他方法来退出错误处理例程。你可根据情况使用下列表中的任何语句。
语句 描述
Resume [0] 程序从产生错误的语句恢复运行或从最近一次调用包含错误处理程序的过程的语句处恢复运行。使用该语句可在更正产生错误的条件后恢复运行。
Resume Next 程序从紧随产生错误的语句的下个语句恢复运行。如果错误发生在包含错误处理程序的过程以外,且被调用的过程不包含有效的错误处理程序,则从紧随调用发生错误的过程的语句之后的语句处恢复运行。
Resume line 程序在 line 参数指定的标签处恢复运行。line 参数是行标签(或非零行号),它必须和错误处理程序在同一个过程中。
Err.Raise Number:=number 触发运行时错误。当这个语句在错误处理例程中运行时,Visual Basic 搜索另一错误处理例程的调用列表(调用列表是被调用过程链,通过它,可到达当前的执行点。这方面的详细信息,参阅本章后面的“错误处理层次结构”)。
Resume与Resume Next间的差异
Resume 与Resume Next之间的差别在于:Resume是从产生错误的语句恢复应用程序的运行;Resume Next是从紧随产生错误的语句的下个语句恢复应用程序的运行。一般而言,对于错误处理程序可以更正的错误使用Resume,对于错误处理程序不能更正的错误使用Resume Next。你可编写错误处理程序,使存在的运行时错误不会让用户看到或者为用户显示错误信息并允许用户进行更正。
在下面的示例中,使用错误处理来进行其变量的“安全”除法,而不显示可能发生的错误。进行除法时可能发生的错误如下表所示。
错误 原因
“被零除” 分子为非零数,但分母为零。
“溢出” 分子、分母均为零(在浮点数除法中)。
“非法过程调用”分子和/或分母是非数值变量(或不能被看作数值变量)。
对于所有这三种情况,下面示例为这些错误设置陷井并返回Null(空)。
Function Divide (numer, denom) as Variant
Const mnErrDivByZero = 11, mnErrOverFlow = 6, mnErrBadCall = 5
On Error GoTo MathHandler
Divide = numer / denom
Exit Function
MathHandler:
If Err.Number = MnErrDivByZero Or Err.Number = ErrOverFlow _
Or Err = ErrBadCall Then
Divide = Null '如果发生被零除、溢出或非法过程调用错误,返回Null。
Else
' 显示意外错误信息
MsgBox "意外错误 " & Err.Number & ": " & _
Err.Description, vbExclamation
End If ' 对于所有情况都继续执行Resume Next。
Resume Next ' 从Exit Function语句执行。
End Function
在特定行恢复执行
Resume Next还可用在循环中发生的错误,你可以重新启动运行或使用Resume line语句控制程序转到某特定行标签处。
下面示例说明了Resume line 语句的使用。与前面的FileExists示例不同的是,这个函数允许用户输入文件名称,当文件存在时函数返回该文件名称。
Function VerifyFile As String
Const mnErrBadFileName = 52, mnErrDriveDoorOpen = 71
Const mnErrDeviceUnavailable = 68, mnErrInvalidFileName = 64
Dim strPrompt As String, strMsg As String, strFileSpec As String
strPrompt = "输入检查的文件名称:"
StartHere:
strFileSpec = "*.*" ' 以一默认的名称开始。
strMsg = strMsg & vbCRLF & strPrompt
'让用户更改默认名称。
strFileSpec = InputBox(strMsg, "文件查找", strFileSpec, 100, _100)
' 如果用户删除默认名称,退出。
If strFileSpec = "" Then Exit Function
On Error GoTo Handler
VerifyFile = Dir(FileSpec)
Exit Function
Handler:
Select Case Err.Number ' 分析错误代码并加载信息。
Case ErrInvalidFileName, ErrBadFileName
strMsg = "你输入的文件名称无效,请重试一次。"
Case MnErrDriveDoorOpen
strMsg = "关上磁盘驱动器门,重试一次。"
Case MnErrDeviceUnavailable
strMsg = "你所指定的驱动器未找到,重试一次。"
Case Else
Dim intErrNum As Integer
intErrNum = Err.Number
Err.Clear ' 清除Err对象。
Err.Raise Number:= intErrNum ' 重新生成错误。
End Select
Resume StartHere '跳转回StartHere标签,使用户可重新输入另一文件名。
End Function
如果找到一个与输入的文件名相匹配的文件,函数返回该文件名。如果未找到匹配的文件,函数返回一个零长度的字符串。如果意料中的错误发生,一条信息将被指定给strMsg变量,并跳转回标签StartHere重新执行,这使得用户有机会输入一个有效的路径和文件名称。
如果出现意外的错误,在Case Else中重新生成错误,使得调用列表中另一错误处理程序可捕获错误。这样做是有必要的,因为如果不重新生成错误,代码就会继续从Resume StartHere行运行,而如果重新生成错误,你可有效地防止错误的重复发生;新错误将被设置在调用堆栈的另一层。
[此贴子已经被作者于2005-1-22 0:46:41编辑过] |