循环中的vba错误处理

时间:2011-10-04 19:51:59

标签: vba error-handling

vba的新手,尝试'on error goto'但是,我不断收到错误'索引超出范围'。

我只想制作一个由包含查询表的工作表名称填充的组合框。

    For Each oSheet In ActiveWorkbook.Sheets
        On Error GoTo NextSheet:
         Set qry = oSheet.ListObjects(1).QueryTable
         oCmbBox.AddItem oSheet.Name

NextSheet:
    Next oSheet

我不确定问题是否与在循环中嵌套On Error GoTo或如何避免使用循环有关。

8 个答案:

答案 0 :(得分:21)

问题可能是您没有从第一个错误中恢复。您不能在错误处理程序中抛出错误。您应该添加一个简历语句,如下所示,因此VBA不再认为您在错误处理程序中:

For Each oSheet In ActiveWorkbook.Sheets
    On Error GoTo NextSheet:
     Set qry = oSheet.ListObjects(1).QueryTable
     oCmbBox.AddItem oSheet.Name
NextSheet:
    Resume NextSheet2
NextSheet2:
Next oSheet

答案 1 :(得分:14)

作为像示例代码一样处理循环错误的一般方法,我宁愿使用:

on error resume next
for each...
    'do something that might raise an error, then
    if err.number <> 0 then
         ...
    end if
 next ....

答案 2 :(得分:3)

怎么样:

    For Each oSheet In ActiveWorkbook.Sheets
        If oSheet.ListObjects.Count > 0 Then
          oCmbBox.AddItem oSheet.Name
        End If
    Next oSheet

答案 3 :(得分:1)

我不想为我的代码中的每个循环结构设计特殊的错误处理程序,所以我有一种方法可以使用我的标准错误处理程序找到问题循环,这样我就可以为它们编写一个特殊的错误处理程序。

如果循环中发生错误,我通常想知道导致错误的原因而不是跳过错误。要了解这些错误,我会像许多人一样将错误消息写入日志文件。但是,如果循环中发生错误,则写入日志文件是危险的,因为每次循环迭代时都可以触发错误,在我的情况下,80 000次迭代并不罕见。因此,我将一些代码放入我的错误记录功能中,该功能可以检测到相同的错误并跳过将它们写入错误日志。

我在每个过程中使用的标准错误处理程序如下所示。它记录错误类型,发生错误的过程以及过程接收的任何参数(在本例中为FileType)。

procerr:
    Call NewErrorLog(Err.number, Err.Description, "GetOutputFileType", FileType)
    Resume exitproc

我写入表的错误记录功能(我在ms-access中)如下所示。它使用静态变量来保留先前的错误数据值,并将它们与当前版本进行比较。记录第一个错误,然后第二个相同的错误将应用程序推送到调试模式,如果我是用户或在其他用户模式下退出应用程序。

Public Function NewErrorLog(ErrCode As Variant, ErrDesc As Variant, Optional Source As Variant = "", Optional ErrData As Variant = Null) As Boolean
On Error GoTo errLogError

    'Records errors from application code
    Dim dbs As Database
    Dim rst As Recordset

    Dim ErrorLogID As Long
    Dim StackInfo As String
    Dim MustQuit As Boolean
    Dim i As Long

    Static ErrCodeOld As Long
    Static SourceOld As String
    Static ErrDataOld As String

    'Detects errors that occur in loops and records only the first two.
    If Nz(ErrCode, 0) = ErrCodeOld And Nz(Source, "") = SourceOld And Nz(ErrData, "") = ErrDataOld Then
        NewErrorLog = True
        MsgBox "Error has occured in a loop: " & Nz(ErrCode, 0) & Space(1) & Nz(ErrDesc, "") & ": " & Nz(Source, "") & "[" & Nz(ErrData, "") & "]", vbExclamation, Appname
        If Not gDeveloping Then  'Allow debugging
            Stop
            Exit Function
        Else
            ErrDesc = "[loop]" & Nz(ErrDesc, "")  'Flag this error as coming from a loop
            MsgBox "Error has been logged, now Quiting", vbInformation, Appname
            MustQuit = True  'will Quit after error has been logged
        End If
    Else
        'Save current values to static variables
        ErrCodeOld = Nz(ErrCode, 0)
        SourceOld = Nz(Source, "")
        ErrDataOld = Nz(ErrData, "")
    End If

    'From FMS tools pushstack/popstack - tells me the names of the calling procedures
    For i = 1 To UBound(mCallStack)
        If Len(mCallStack(i)) > 0 Then StackInfo = StackInfo & "\" & mCallStack(i)
    Next

    'Open error table
    Set dbs = CurrentDb()
    Set rst = dbs.OpenRecordset("tbl_ErrLog", dbOpenTable)

    'Write the error to the error table
    With rst
        .AddNew
        !ErrSource = Source
        !ErrTime = Now()
        !ErrCode = ErrCode
        !ErrDesc = ErrDesc
        !ErrData = ErrData
        !StackTrace = StackInfo
        .Update
        .BookMark = .LastModified
        ErrorLogID = !ErrLogID
    End With


    rst.Close: Set rst = Nothing
    dbs.Close: Set dbs = Nothing
    DoCmd.Hourglass False
    DoCmd.Echo True
    DoEvents
    If MustQuit = True Then DoCmd.Quit

exitLogError:
    Exit Function

errLogError:
    MsgBox "An error occured whilst logging the details of another error " & vbNewLine & _
    "Send details to Developer: " & Err.number & ", " & Err.Description, vbCritical, "Please e-mail this message to developer"
    Resume exitLogError

End Function

请注意,错误记录器必须是应用程序中防弹最多的功能,因为应用程序无法正常处理错误记录器中的错误。出于这个原因,我使用NZ()来确保空值不能潜入。请注意,我还将[循环]添加到第二个相同的错误,以便我知道首先查看错误过程中的循环。

答案 4 :(得分:0)

这个

On Error GoTo NextSheet:

应该是:

On Error GoTo NextSheet

另一个解决方案也很好。

答案 5 :(得分:0)

怎么样?

If oSheet.QueryTables.Count > 0 Then
  oCmbBox.AddItem oSheet.Name
End If 

或者

If oSheet.ListObjects.Count > 0 Then
    '// Source type 3 = xlSrcQuery
    If oSheet.ListObjects(1).SourceType = 3 Then
         oCmbBox.AddItem oSheet.Name
    End IF
End IF

答案 6 :(得分:0)

实际上,Gavin Smith的答案需要稍微改变一下,因为你无法在没有错误的情况下恢复。

Sub MyFunc()
...
    For Each oSheet In ActiveWorkbook.Sheets
        On Error GoTo errHandler:
        Set qry = oSheet.ListObjects(1).QueryTable
        oCmbBox.AddItem oSheet.name

    ...
NextSheet:
    Next oSheet

...
Exit Sub

errHandler:
Resume NextSheet        
End Sub

答案 7 :(得分:0)

还有另一种控制错误处理的方法,它适用于循环。创建一个名为margin: 0 auto;的字符串变量,并使用该变量确定单个错误处理程序如何处理错误。

代码模板是:

here