最后更新时间:2010-01-19 11:42:20
来自MSDN-2001-OCT: Visual Tools and Languages/Visual Studio 6.0 Documentation/Visual Basic Documentation/Using Visual Basic/Programmer’s Guide/Part 2: What Can You Do With Visual Basic/Debugging Your Code and Handling Errors/
1. Designing an Error Handler
(1) Intercepting an error is also known as trapping an error. When an error occurs,Visual Basic sets the varIoUs properties of the error object,Err,such as an error number,a description,and so on. You can use the Err object and its properties in an error-handling routine so that your application can respond intelligently to an error situation.
An error handler is a routine for trapping and responding to errors in your application.
(2) An error trap is enabled when Visual Basic executes the On Error statement,which specifies an error handler.
(3) Generally,you would use Resume whenever the error handler can correct the error,and Resume Next when the error handler cannot. 比如下面的文件操作,如果是在 Open 语句时出错,文件没打开,那么关闭是不需要的,调用 Close 出错是可以忽略的(来自这个帖子15楼Tiger_Zhao的发言)。
Private Sub Command10_Click()
On Error GoTo Err_Command10_Click
Dim hFile as integer
hFile = FreeFile()
Open ... As #hFile
...
Exit_Command10_Click:
On Error Resume Next
Close #hFile
Exit Sub
Err_Command10_Click:
MsgBox Err.Description
Resume Exit_Command10_Click
End Sub
(4) Resume line: Resumes program execution at the label specified by line (必须在同一过程内)
2. Error Handling Hierarchy
(1) An enabled error handler is one that was activated by executing an On Error statement and hasn't yet been turned off — either by an On Error GoTo 0 statement or by exiting the procedure where it was enabled.
An active error handler is one in which execution is currently taking place.
(2) When an error occurs within a procedure lacking an enabled error-handling routine,or within an active error-handling routine(错误捕获过程里的错误不会被捕获),Visual Basic searches the calls list for another enabled error-handling routine.
If it doesn't encounter an enabled error handler anywhere in the calls list,it presents a default unexpected error message and halts execution.
If the error handler's range of errors doesn't include the error that actually occurred,an unanticipated error can occur within the procedure with the enabled error handler. In such a case,the procedure could execute endlessly(如下例所示),especially if the error handler executes a Resume statement. To prevent such situations,use the Err object's Raise method in a Case Else statement in the handler. This actually generates an error within the error handler,forcing Visual Basic to search through the calls list for a handler that can deal with the error.
On Error GoTo ErrHandle
Dim i As Integer
i = 1 / 0
Exit Sub
ErrHandle :
Debug . Print Err . Description
Resume
End Sub
@H_404_220@ @H_404_220@
(3) While you are debugging your code,use the Err object's Raise method to regenerate the error in all error handlers for cases where no code in the handler deals with the specific error. This allows your application to try to correct the error in other error-handling routines along the calls list. It also ensures that Visual Basic will display an error message if an error occurs that your code doesn't handle.
However,in a stand-alone .exe file,you should be cautIoUs: If you execute the Raise method and no other procedure traps the error,your application will terminate execution immediately,without any QueryUnload or Unload events occurring.
When the code reaches a Resume statement,the Clear method of the Err object is invoked. It is necessary to regenerate the error in order to pass it back to the prevIoUs procedure on the call stack.
Err.Raise 直接将抛出异常。如果该语句是在本身的错误处理中触发,则不会被自己捕获,将直接中断本过程向上级调用过程返回异常;如果是在错误处理代码之外,则被本过程捕获。具体可见http://topic.csdn.net/u/20090608/04/eda00766-b7a8-4159-8417-b94780052c47.html 7楼和8楼的例子。再比如这个帖子0楼的例子和5楼的解释和3楼的更正和7楼的附加说明和22楼的附加说明和25楼的推荐代码,从这个例子可以看出,如果在错误处理代码中用Goto语句,那么即使是错误处理代码之外的语句也会被当做错误处理代码,从而其中的错误也不会被本过程捕获。
(4) Use the Clear method if you need to explicitly clear the Err object after handling an error.??This is necessary when using inline error handling with On Error Resume Next. Visual Basic calls the Clear method automatically whenever it executes any type of Resume statement,Exit Sub,Exit Function,Exit Property,or any On Error statement.
当你试图raise一个错误的时候,最好先用一下clear方法。比如像下面这个例子,有没有clear,效果是不一样的。
On Error GoTo ErrHandle
Err . Raise 11 '除数为0
Exit Sub
ErrHandle :
' Err.Clear
Err . Raise 57 'I/O设备错
Resume Next
End Sub
@H_404_220@ @H_404_220@
(5) If you don't want another procedure in the calls list to trap the error,use the Stop statement to force your code to terminate. Using Stop lets you examine the context of the error while refining your code in the development environment.
Be sure to remove any Stop statements before you create an .exe file. If a stand-alone Visual Basic application (.exe) encounters a Stop statement,it treats it as an End statement and terminates execution immediately,without any QueryUnload or Unload events occurring.
(6) Write a fail-safe error-handling procedure that all your error handlers can call as a last resort for errors they cannot handle. This fail-safe procedure can perform an orderly termination of your application by unloading forms and saving data.
3. Testing Error Handling by Generating Errors
(1) Err,Visual Basic's globally defined error object.
(2) If you want to generate and trap your own errors,you can add your error numbers to the vbObjectError constant.
4. Inline or Centralized Error Handling
(1) Inline Error Handling指:When you check for errors immediately after each line that may cause an error,you are performing inline error handling.
(2) Returning Error Numbers
If Dir (p) <> " " Then
FileExists = conSuccess ' Return a constant
' indicating the
Else ' file exists.
FileExists = conFailure ' Return failure
' constant.
End If
End Function
Dim ResultValue As Long
ResultValue = FileExists ( "C:/Testfile.txt")
If ResultValue = conFailure Then
.
. ' Handle the error.
.
Else
.
. ' Proceed with the program.
.
End If
@H_404_220@ @H_404_220@
The key to inline error handling is to test for an error immediately after each statement or function call. In this manner,you can design a handler that anticipates exactly the sort of error that might arise and resolve it accordingly. This approach does not require that an actual run-time error arise. This becomes useful when working with API and other DLL procedures which do not raise Visual Basic exceptions. Instead,these procedures indicate an error condition,either in the return value,or in one of the arguments passed to the procedures; check the documentation for the procedure you are using to determine how these procedures indicate an error condition.
(3) Handling Errors in the Calling Procedure:
If Dir (p) <> " " Then
Err . Raise conSuccess ' Return a constant
' indicating the
Else 'file exists.
Err . Raise conFailure ' Raise error number
' conFailure.
End If
End Function
Dim ResultValue As Long
On Error Resume Next
ResultValue = FileExists ( "C:/Testfile.txt")
If Err . Number = conFailure Then
.
. ' Handle the error.
.
Else
.
. ' Continue program.
.
End If
@H_404_220@ @H_404_220@
The next example uses both the return value and one of the passed arguments to indicate whether or not an error condition resulted from the function call.
ByRef Result As Integer) As Long
On Error GoTo ErrorHandler
Result = x ^P
Exit Function
ErrorHandler :
Power = conFailure
End Function
' Calls the Power function.
Dim lngReturnValue As Long , lngErrorMaybe As Long
lngErrorMaybe = Power ( 10 , 2 , lngReturnValue)
If lngErrorMaybe Then
.
. ' Handle the error.
.
Else
.
. ' Continue program.
.
End If
@H_404_220@ @H_404_220@
(4) Using Variant Data Types
On Error GoTo ErrorHandler
Power = x ^P
Exit Function
ErrorHandler :
Power = CVErr( Err . Number) ' Convert error code to
' tagged Variant.
End Function
' Calls the Power function.
Dim varReturnValue As Variant
varReturnValue = Power ( 10 , 2)
If IsError ( varReturnValue) Then
.
. ' Handle the error.
.
Else
.
. ' Continue program.
.
End If
@H_404_220@ @H_404_220@
(5) Centralized Error Handling: With careful planning,you can reduce code size by writing a few procedures that your error-handling code can call to handle common error situations.
5. Turning Off Error Handling
(1) To turn off an enabled error trap,use the On Error GoTo 0 statement. Once Visual Basic executes this statement,errors are detected but not trapped within the procedure.
On Error GoTo 0 和其他 On Error语句搭配可以限制错误捕获的代码范围,这有时是很有用的技巧。某些时候需要用 Err.Raise 语句向调用者抛出错误,就需要先用本语句将自己的错误捕获关掉。再比如下面这段代码,在正常退出的代码段中要关掉错误捕获,否则可能会导致由错误捕获带来的死循环(详见这个帖子1楼和2楼babyt的解释)。
Private Sub Command10_Click() On Error GoTo Err_Command10_Click Dim x As Integer x = 1 / 0 Exit_Command10_Click: '正常退出程序的代码
'注释掉这一行,会导致错误捕获的死循环 'On Error GoTo 0 x = 1 / 0 Exit Sub Err_Command10_Click: MsgBox Err.Description Resume Exit_Command10_Click End Sub
(2) Instead,while debugging,you could turn off error handlers so that every time there's an error,you enter break mode.
快捷菜单-》toggle->Select the Break on All Errors option.
(3) 调试类模块时可以选择:Break in Class Module option。
With this option selected,an error in a class module or an object in another application or project that is running in Visual Basic will cause that class to enter the debugger's break mode,allowing you to analyze the error.
An error arising in a compiled object will not display the Immediate window in break mode; rather,such errors will be handled by the object's error handler,or trapped by the referencing module.
6. Error Handling with ActiveX Components
(1) When an error is raised in an external object and it is untrapped,it will be raised in the procedure that called the external object.
(2) The interface specifies that any object regenerating an error that arises in a referenced object should not simply propagate the error (pass the error code),but should instead remap the error number to something meaningful.
(3) Whenever possible,a class module should try to handle every error that arises within the module itself,and should also try to handle errors that arise in an object it references that are not handled by that object.
However,there are some errors that it cannot handle because it cannot anticipate them. There are also cases where it is more appropriate for the referencing object to handle the error,rather than the referenced object.
(4) A class module could include the following error handler to accommodate any error it might trap,regenerating those it is unable to resolve:
Select Case ErrNum
Case 7 ' Handle out-of-memory error.
.
.
.
Case 440 ' Handle external object error.
Err . Raise Number : = vbObjectError + 9999
' Error from another Visual Basic object.
Case Is > vbObjectError and Is < vbObjectError _
+ 65536
ObjectError = ErrNum
Select Case ObjectError
' This object handles the error,based on
' error code documentation for the object.
Case vbObjectError + 10
.
.
.
Case Else
' Remap error as generic object error and
' regenerate.
Err . Raise Number : = vbObjectError + 9999
End Select
Case Else
' Remap error as generic object error and
' regenerate.
Err . Raise Number : = vbObjectError + 9999
End Select
Err . Clear
Resume Next
@H_404_220@ @H_404_220@
The Case 440
statement traps errors that arise in a referenced object outside the Visual Basic application.When this error is raised,it is generally the result of a fatal automation error (one that would cause the component to end execution),or because an object didn't correctly handle a trapped error. Error 440 shouldn't be propagated unless it is a fatal error.
The statement
@H_404_220@ @H_404_220@
traps errors that originate in an object within the Visual Basic application,or within the same object that contains this handler. Only errors defined by objects will be in the range of the vbObjectError offset.
Any error not handled should be regenerated with a new number,as shown in the Case Else statement. Within your application,you can design a handler to anticipate this new number you've defined. If this were a public class (not available in the Learning Edition),you would also want to include an explanation of the new error-handling code in your application's documentation.
The last Case Else statement traps and regenerates any other errors that are not trapped elsewhere in the handler. Because this part of the trap will catch errors that may or may not have the vbObjectError constant added,you should simply remap these errors to a generic "unresolved error" code. That code should be added to vbObjectError,indicating to any handler that this error originated in the referenced object.