Access VBA:是否可以重置错误处理?

15

我在程序的第一部分使用了以下语句:

On Error GoTo start

假设在我的第二部分中再次使用:

On Error Resume Next

由于第一个错误处理程序仍然处于活动状态,因此不会激活第二个错误处理程序。是否有任何方法在使用后取消第一个错误处理程序的激活状态?

我在程序的第一部分中使用了以下语句:

On Error GoTo start

如果在我的第二部分中再次使用:

On Error Resume Next

由于第一个错误处理程序仍然处于活动状态,所以不会激活第二个错误处理程序。是否有任何方法可以在使用后取消第一个错误处理程序的激活状态?

Set objexcel = CreateObject("excel.Application")
                     objexcel.Visible = True
                     On Error GoTo Openwb
                     wbExists = False
                     Set wbexcel = objexcel.Workbooks.Open("C:\REPORT3.xls")
                     Set objSht = wbexcel.Worksheets("Sheet1")
                     objSht.Activate
                     wbExists = True
Openwb:
                     
                     On Error GoTo 0
                     If Not wbExists Then
                     objexcel.Workbooks.Add
                     Set wbexcel = objexcel.ActiveWorkbook
                     Set objSht = wbexcel.Worksheets("Sheet1")

                     End If
                     
                     On Error GoTo 0
                                         
Set db = DBEngine.opendatabase("C:\book.mdb")
Set rs = db.OpenRecordset("records")

Set rs2 = CreateObject("ADODB.Recordset")
rs2.ActiveConnection = CurrentProject.Connection


For Each tdf In CurrentDb.TableDefs
   
   If Left(tdf.Name, 4) <> "MSys" Then
        rs.MoveFirst
        strsql = "SELECT * From [" & tdf.Name & "] WHERE s=15 "

        Do While Not rs.EOF
            On Error Resume Next
            
            rs2.Open strsql 

在执行最后一条语句时,我想忽略错误并继续下一个表的操作,但是错误处理似乎不起作用。

5个回答

17

On error goto 0将错误处理交给Visual Basic(一般是在消息框中显示)

On error goto label会将代码重定向到label:

On error resume next会忽略错误并继续运行

Resume next会将代码重定向到发生错误后的下一行

这意味着可以结合使用这些指令,例如:

    On Error goto 0
    ...
    On Error goto 0

不合理

如果你想重定向一个“on error”指令,你必须这样做:

    Do While Not rs.EOF
        
        On Error Resume Next
        rs2.Open strsql
        On error Goto 0

        rs2.moveNext

    Loop

如果你想将一个错误重定向到一个标签(用于处理或其他目的),然后回到出错代码的位置,你需要编写类似以下的代码:

    On error goto label
    ...
    ...
    On error goto 0
    exit sub (or function)

    label:
    ....
    resume next
    end function

但我真的建议您在错误管理方面更加严谨。您应该首先能够做到这样:

    Set objexcel = CreateObject("excel.Application")
    objexcel.Visible = True

    On Error GoTo error_Treatment
    wbExists = False
    Set wbexcel = objexcel.Workbooks.Open("C:\REPORT3.xls")
    Set objSht = wbexcel.Worksheets("Sheet1")
    objSht.Activate
    wbExists = True
    On error GoTo 0

    Set db = DBEngine.opendatabase("C:\book.mdb")
    Set rs = db.OpenRecordset("records")

    Set rs2 = CreateObject("ADODB.Recordset")
    rs2.ActiveConnection = CurrentProject.Connection

    For Each tdf In CurrentDb.TableDefs
        ....
        'there are a number of potential errors here in your code'
        'you should make sure that rs2 is closed before reopening it with a new instruction'
        'etc.'
    Next tdf

    Exit sub

    error_treatment:
    SELECT Case err.number
       Case **** '(the err.number raised when the file is not found)'
           objexcel.Workbooks.Add
           Set wbexcel = objexcel.ActiveWorkbook
           Set objSht = wbexcel.Worksheets("Sheet1")
           Resume next 'go back to the code'
       Case **** '(the recordset cannot be opened)'
           ....
           ....
           Resume next 'go back to the code'
       Case **** '(whatever other error to treat)'
           ....
           ....
           Resume next 'go back to the code'
       Case Else
           debug.print err.number, err.description '(check if .description is a property of the error object)'
           'your error will be displayed in the immediate windows of VBA.' 
           'You can understand it and correct your code until it runs'
       End select
    End sub

下一步将是预测您代码中的错误,以便不会引发err对象。例如,您可以编写像这样的通用函数:
    Public function fileExists (myFileName) as Boolean

你可以通过在代码中测试xls文件的存在,利用这个函数来获得更多优势:
    if fileExists("C:\REPORT3.xls") Then
        Set wbexcel = objexcel.Workbooks.Open("C:\REPORT3.xls")
    Else
       objexcel.Workbooks.Add
       Set wbexcel = objexcel.ActiveWorkbook
    Endif        
    Set objSht = wbexcel.Worksheets("Sheet1")
    objSht.Activate

您不再需要wbExist变量...

同样地,您应该预期记录集中没有记录的情况。在测试之前写下rs.MoveFirst可能会引发错误。因此,您应该编写

    If rs.EOF and rs.BOF then
    Else
        rs.moveFirst
        Do while not rs.EOF
             rs.moveNext
        Loop
    End If

5
您需要清除错误。尝试将此代码放入:
If Err.Number > 0 Then
    Err.Clear
End If

您还可以使用Err.Number来处理特定的错误情况。

这似乎也不起作用。 如果将Excel的第一部分放在单独的子程序中,则此代码有效,但我现在想保持它这样。 - tksy
我认为仅仅丢弃所有的错误并不是一个好主意。如果你丢弃了一个意料之外的错误会怎样呢? - David-W-Fenton
David,说得好。这就是为什么我说你可以使用Err.Number来处理特定的错误情况。而不是进行通用的清除所有操作,只有在出现你预期的错误时才进行清除。 - Jason Z

3

避免错误通常比处理错误更好。例如:

Set objexcel = CreateObject("excel.Application")
objexcel.Visible = True

'On Error GoTo Openwb '
'wbExists = False '

If Dir("C:\REPORT3.xls") = "" Then
    objexcel.Workbooks.Add
    Set wbexcel = objexcel.ActiveWorkbook
    Set objSht = wbexcel.Worksheets("Sheet1")
Else
    Set wbexcel = objexcel.Workbooks.Open("C:\REPORT3.xls")
    Set objSht = wbexcel.Worksheets("Sheet1")
End If

objSht.Activate
'wbExists = True '

谢谢,这解决了问题。 但是,有没有可能在使用错误处理后继续在程序中取消它? - tksy
2
争议:在 VBA 中,当测试零长度字符串时使用 vbNullString 要比 "" 更高效,因为该 Access 常量已经分配了其内存。虽然在此常量中并不重要,但养成习惯始终在循环中使用 vbNullString 是很好的。 - David-W-Fenton
@tksy: "On Error GoTo 0" 就是这样。它将 VBA 返回到通常的错误处理方式。这并不意味着 "On Error GoTo Start",我认为你的问题是这个意思。 - Mark Nold
你的评论是正确的,但有些地方无法这样做。无论如何,如果能避免这种“错误”处理,就应该尝试使用它。 - Friedrich
3
这在技术上是正确的,但未回答问题。实际上这是一个简单的问题:“是否有一种方法可以重置错误处理”。 - João Mendes

1

回答和解决方案是有区别的。有时候我们只需要一个回答,警告也很重要,让我们通过经验学习到这并不是一个好的解决方案。话虽如此,我找到了this

你需要使用On Error GoTo -1或Err.Clear来重置错误捕获。

查看我几个月前发布的这个答案以获取更详细的解释。


1

你可以把你的源代码发到这里吗?也许你是在错误的语句中使用了on error。 - Dirk Vollmar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接