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 = "Enter file specification to check:"
   
StartHere:
   strFileSpec = "*.*"   ' Start with a default specification.
   strMsg = strMsg & vbCrLf & strPrompt
   ' Let the user modify the default.
   strFileSpec = InputBox(strMsg, "File Search", strFileSpec, 100, 100)
   ' Exit if user deletes default.
   If strFileSpec = "" Then Exit Function
   On Error GoTo Handler
    VerifyFile = Dir(strFileSpec)
    Exit FunctionHandler:
   Select Case Err.Number   ' Analyze error code and load message.
      Case ErrInvalidFileName, ErrBadFileName
         strMsg = "Your file specification was "
         strMsg = strMsg & "invalid; try another."
      Case mnErrDriveDoorOpen
         strMsg = "Close the disk drive door and "
         strMsg = strMsg & "try again."
      Case mnErrDeviceUnavailable
         strMsg = "The drive you specified was not "
         strMsg = strMsg & "found. Try again."
      Case Else
         Dim intErrNum As Integer
         intErrNum = Err.Number
         Err.Clear            ' Clear the Err object.
         Err.Raise Number:=intErrNum    ' Regenerate the error.
   End Select
   Resume StartHere   ' This jumps back to StartHere label so the user can try another file name.
End Function以上这段代码来自MSDN。Using Visual Basic\Programmer’s Guide\Part 2: What Can You Do With Visual Basic\Debugging Your Code and Handling Errors\这是一个用来示范错误处理的例子。我不明白最后一个case里的Err.Raise Number:=intErrNum语句的作用。在MSDN里有如下解释:In this case, intErrNum is a variable that contains the error number which triggered the error handler. 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明明是在resume语句之前哪?这是不是MSDN的笔误,还是俺理解有误?请好心回答的朋友帮助剖析一下:这个err.raise如果没用错的话,这个调用堆栈是个什么情况?

解决方案 »

  1.   

    汗。才发现 Err.Raise Number:=intErrNum之前还有个Err.Clear            俺不问了。
    揍当友情散分帖8
      

  2.   

    刚想说   
    Err.Clear            ' Clear the Err object.就看到你也发现了
    那我就不客气了
      

  3.   

    这里的 Err.Raise 直接将抛出异常,而且由于是在本身的错误处理中触发的,不会被自己捕获,将直接中断本过程向上级调用过程返回异常。
    前面的 Err.Clear 只是一个好的习惯,而不是必要条件。
      

  4.   


    还真是这样的:
    Public Sub TestErr()
        On Error GoTo ErrHandle
        Dim i As Integer
        i = 1 / 0
        Exit Sub
    ErrHandle:
        Debug.Print Err.Description
        Dim intErrNum As Integer
        intErrNum = Err.Number
    '    Err.Clear            ' Clear the Err object.
        Err.Raise Number:=intErrNum    ' Regenerate the error.
        Resume NextEnd SubPublic Sub TestErrs()
    On Error GoTo ErrHandle
        Call TestErr
        Debug.Print "next line after testerr"
        Exit Sub
    ErrHandle:
        Debug.Print "error handle in outer procedure"
        Resume Next
    End Sub
      

  5.   

    下面这个例子证明,如果err.raise在错误处理代码之外则被本过程trap:Public Sub TestErr()
        On Error GoTo ErrHandle
        Dim i As Integer
    '    i = 1 / 0
        Err.Raise 11
        Exit Sub
    ErrHandle:
        Debug.Print Err.Description
        Dim intErrNum As Integer
        intErrNum = Err.Number
        Debug.Print Err.Number
    '    Err.Clear            ' Clear the Err object.
        Err.Raise Number:=intErrNum    ' Regenerate the error.
        Resume NextEnd SubPublic Sub TestErrs()
    On Error GoTo ErrHandle
        Call TestErr
        Debug.Print "next line after testerr"
        Exit Sub
    ErrHandle:
        Debug.Print "error handle in outer procedure"
        Resume Next
    End Sub
      

  6.   

    有疑问多实践。
    如果你自己设个断点,单步走一下,早就发现 Err.Raise 的作用了。
    自己总结出来印象会更深刻。
      

  7.   


    这里还有一段话,也许能用来解释你描述的这个现象: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.
      

  8.   

    err.Raise是产生一个运行时的错误,它不能在激活的错误处理程序中去产生, 前面老鸟也担到了..
    通常用在自定义错误...比如改下楼主的示例:Public Sub TestErr(i As Long, j As Long)
        If j = 0 Then
            Err.Raise 555, , "除数不能为0"    '512以前是系统错误号
            Exit Sub
        End If
        MsgBox i / j
    End Sub
    Private Sub Command1_Click()
    On Error GoTo 100
        TestErr 100, 0
        Exit Sub
    100:
        Debug.Print Err.Number & " : " & Err.Description
    End Sub
      

  9.   

    上面if中的exit sub多余:Public Sub TestErr(i As Long, j As Long)
    on error goto 100
        If j = 0 Then
            Err.Raise 555, , "除数不能为0"    '512以前是系统错误号
        End If
        MsgBox i / j
        exit sub
    100:
        msgbox err.number;Err.description
    End Sub
      

  10.   


    恩,你说得很对。这个err.clear其实也有它的作用。比如像下面这段,有没有clear,效果是不一样的。Public Sub TestErr()
        On Error GoTo ErrHandle    Err.Raise 11 '除数为0
        Exit SubErrHandle:
    '    Err.Clear
        Err.Raise 57 'I/O设备错
        Resume NextEnd Sub
      

  11.   

    是的,有没有clear确实不一样。Option ExplicitPublic Sub TestErr()
        On Error GoTo ErrHandle    Err.Raise 11 '除数为0
        Exit SubErrHandle:
    '    Err.Clear
        Err.Raise 57 'I/O设备错
        Resume Next
    End SubSub DoTheTest()
        On Error GoTo handle
        TestErr
        Exit Sub
    handle:
        MsgBox "Error # " & Err.Number & ", " & Err.Description & vbCrLf & "Source:" & Err.Source
    End Sub如果没有clear,调用程序检测到的错误值是原始错误值,在这个用例中就是“除数为0”;如果先用clear将原来的错误清除掉,则应能将自定义错误返回调用者,这里就是“I/O设备错”。
      

  12.   

    上面用词不当,应是:不用Err.Clear而直接Err.Raise,只改变了Err.Number,Err.Description及Err.Source这些错误信息没有变,保持原样;先Err.Clear再Err.Raise,则Err对象的所有原有信息都被新信息所取代。Err.Source在上面这个用例中看不出来,但设想一下,如果错误首先是在TestErr()的被调用者(如访问Automation对象)中发生,那么用Err.Clear和不用从TestErr()返回的Err.Source也是不同的。
      

  13.   

    这一切都好理解和推测,如果我们记住,err是一个在VB范围内声明的全局共享的公有变量。
      

  14.   

    又看了一下开发文档。
    Raise 方法产生运行时错误。语法object.Raise number, source, description, helpfile, helpcontext说明除了 number 之外,所有参数都是可选的。如果使用 Raise 而不指定一些参数,并且 Err 对象的属性设置含有未清除的值,则视这些值为错误的值。
      

  15.   


    这段中文翻译比较拗口,看原文是酱紫的:All of the arguments are optional except number. If you use Raise without specifying some arguments, and the property settings of the Err object contain values that have not been cleared, those values serve as the values for your error.
    也就是说,之前没清掉的值,会用作新生成的error的属性值。原理么,我觉得就是我在18楼说的道理。
      

  16.   


    你看MSDN里“Error Handling with ActiveX Components”那一篇。它的例子是这样给的:MyServerHandler:
       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它的说明里提到:Any error not handled should be regenerated with a new number, as shown in the Case Else statement. 不过它的示例代码里并没有用clear方法。我理解它是用了新的错误号,其他全用老值。因为外部来的错误号有可能在VB里是无意义的。所以,似乎也许貌似永远都没有必要用clear方法。我是说在这种向上抛出异常的情况下?
      

  17.   

    22楼说的这个例子具体在这里: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\
      

  18.   

    MSDN的编写者怎么如此热爱resume next几段都有
      

  19.   

    用的代码中常用的是 Error(num) 来抛出错误。不用 Err.Clear :
    Error (17)   '也可以写 Error 17
      

  20.   


    我看楼主也‘中毒’了:
    Public Sub TestErrs()
    On Error GoTo ErrHandle
        Call TestErr
        Debug.Print "next line after testerr"
        Exit Sub
    ErrHandle:
        Debug.Print "error handle in outer procedure"
        Resume Next
    End Sub已经到最后了,还 Resume Next 去 Exit Sub 。
    绕那么远的圈子干吗 
      

  21.   

    是否替换错误纯属个人爱好,经过替换后错误号比较集中,直接将错误说明显示出来通常是用户可以理解的,但是缺点就是不方便编程人员定位错误。在 Err.Raise 中,Err.Number 总是被替换的,不用 Err.Clear 可能有以下原因:
    A)Err.Number 被替换方便程序进行归类处理,而保留 Err.Description 可以得到更详细的错误信息。
    B)如果是多语言版的程序,通常是直接按照 Err.Number 显示对应语言的错误信息,Err.Description 就不需要用到了。还有要记住:所有的 On Error 语句都会清除错误的。
      

  22.   

    Resume Next 的应用场景的确比较少,我的标准错误处理如下,无论是否有错,都可以在 ExitEntry 中进行局部资源的释放。
    Sub Main()
        On Error GoTo ErrHandler
        
        TestErrExitEntry:
        Exit Sub
    ErrHandler:
        Debug.Print Err.Number, Err.Description
        Resume ExitEntry
    End Sub
      

  23.   


    这句话我昨天在MSDN里也看到了,还摘了给你看。可是我却不大理解它。比如下面这段程序:Sub ErrDemoSub()
        On Error GoTo SubHandler
        Err.Raise 11
        
        Err.Raise 57   Exit Sub
    SubHandler:
       Stop
    End Sub在第一次stop之后,你设置下一条语句到Err.Raise 57,执行它之前,在立即窗口
    ?err.Description 
    得到的是11号错误,也就是它并没有被clear那么,“所有的 On Error 语句都会清除错误的。”这个“清除错误的”动作是发生在什么时刻?
      

  24.   

    To tiger_zhao:Public Sub TestErr()
        On Error GoTo ErrHandle    Err.Raise 11 '除数为0
        Exit SubErrHandle:
    '    Err.Clear
        Debug.Print "inner err handle: " & Err.Description
        Err.Raise 57 'I/O设备错
        Resume NextEnd SubPublic Sub TestErrs()
    On Error GoTo ErrHandle
        Call TestErr
        Debug.Print "next line after testerr"
        Exit Sub
    ErrHandle:
        Debug.Print "error handle in outer procedure: " & Err.Description
        Resume Next
    End Sub比如这个例子,在立即窗口TestErrs
    可以看到,外层的on error语句被触发了,但是err.description并未被clear
      

  25.   

    我都还没睡.............处理代码的BUG中.....哎.看来我的结构还需要好好学习一下就一个简单的程序竟然把结构弄得乱七八糟的....
      

  26.   

    下面的代码,本意是为了避免 Close 语句再次触发错误,却将已有错误清除了。
    Option ExplicitSub Main()
        Dim hFile As Integer
        
        On Error GoTo ErrHandler    hFile = FreeFile()
        Open "C:\temp\1.dat" For Binary Access Write As #hFile
        Print #hFile, , CLng(1 / 0)
        Close #hFile    Exit Sub
    ErrHandler:
        On Error Resume Next
        Close #hFile
        MsgBox Err.Number & ":" & Err.Description
    End Sub
      

  27.   

    我没有否认 Err.Description 被保留,我在 29 楼也说了,可能程序只关心 Err.Number。
      

  28.   


    特意查了哈MSDN,里面这么描述error语句:
    The Error statement is supported for backward compatibility. In new code, especially when creating objects, use the Err object's Raise method to generate run-time errors.
      

  29.   


    我的感觉是:所有的resume语句会清除错误,但是on error语句不一定会清除错误。
      

  30.   

    resume 的确会清除错误的
    Private Sub Form_Load()
        On Error GoTo ToExit '打开错误陷阱
        Debug.Print Err.Number, "--", 1
        Err.Raise 11l:        Debug.Print Err.Number, "--", 3    Exit Sub
        '----------------
    ToExit:
        Debug.Print Err.Number, "--", 2
        'GoTo l
        Resume Next
    End SubPrivate Sub Form_Load()
        On Error GoTo ToExit '打开错误陷阱
        Debug.Print Err.Number, "--", 1
        Err.Raise 11l:        Debug.Print Err.Number, "--", 3    Exit Sub
        '----------------
    ToExit:
        Debug.Print Err.Number, "--", 2
        GoTo l
    End Sub
      

  31.   

    对,阿勇这个例子证明:resume语句会清除错误,但是on error语句不一定会清除错误。
      

  32.   

    捕获错误后他哪个分支再次执行了 On Error 语句?
      

  33.   

    恩恩。我弄错了。也明白了。只要解释执行到on error,就会清灵。Sub ErrDemoSub()
        On Error GoTo ErrHandle
        Debug.Print Err.Number, "--", 1
        Err.Raise 11l:
        Debug.Print Err.Number, "--", 3
        Exit Sub
        
    2:
        Debug.Print "zhaotiger"
        Exit Sub
        
    ErrHandler:
        Debug.Print Err.Number, "--", 2
        On Error GoTo 2
        Debug.Print Err.Number, "--", 3
        GoTo lEnd Sub
      

  34.   

    这个帖子讨论了(1)关于“On Error语句会清掉之前的Error的问题”,见54楼的例子
    (2)关于Err.Clear, 15楼和18楼和21楼
    (3)关于错误捕获的层次,7楼和8楼
    (4)关于错误上抛:22F, 29F汗,才发现居然没结帖。