【发布时间】:2016-06-07 13:47:08
【问题描述】:
一段时间以来,我一直在为一位同事编写一个 Visual Basic 脚本,该脚本出现了一个我无法深入了解的奇怪错误。运行时,脚本有时可以正常工作,但很多时候会出现“下标超出范围”错误,导致 Excel 立即崩溃。
我想知道的第一件事是为什么 Excel 会崩溃,即使脚本中有错误捕获代码也是如此。在脚本的开头我有一行:
On Error GoTo ErrorCatch
底部有以下几行:
ErrorCatch:
MsgBox "Error " & Err.Number & " detected - " & Err.Description _
& ". DebugCheckpoint = " & DebugCheckpoint & "."
Err.Clear
DisableSpeedBoosts
DebugCheckpoint 是一个字符串,它会在脚本执行过程中的不同时间点进行更改,以帮助缩小脚本崩溃的范围。最后一行是指同一电子表格的单独模块中的一对函数。一开始,我运行以下函数:
Sub EnableSpeedBoosts()
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
Application.DisplayStatusBar = False
Application.EnableEvents = False
End Sub
虽然我在结尾处有相反的内容:
Sub DisableSpeedBoosts()
'Restore previous settings
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.DisplayStatusBar = True
Application.EnableEvents = True
End Sub
但是,即使该行被注释掉,该脚本仍然会使 Excel 崩溃,因此它可能不相关。
谁能解释为什么 Excel 仍然崩溃,即使错误已被捕获并清除?这是没有意义的第一件事。
至于脚本本身,我要做的是从导入文件中结构相似的表中填充第一张表上的主数据表,同时检查实际和潜在的重复行。 应该发生的是这样的:
用户运行脚本,通过对话框选择导入文件,
如果选择了有效文件,脚本会在第一张工作表上运行一些基本检查,以查看该工作表上的表格是否符合设定的格式,
如果检查通过,则脚本会使用该表和主表中的第二个数组 (DataArray) 填充一个数组 (ImportArray)。
该脚本还会初始化两个空白数组,一个用于添加到主表的项目 (AddArray),另一个用于将实际和潜在的重复项添加到同一电子表格的第二个表 (LogArray )。
然后脚本会遍历 ImportArray,在此和 DataArray 之间运行一些实际和潜在重复行的检查,并将该行添加到 AddArray 或 LogArray 或两者中,在以下情况下潜在的重复。
最后,一旦到达 ImportArray 的末尾,脚本将 AddArray 附加到主表,将 LogArray 附加到重复表,打印一条友好消息,然后退出。
这可能不是最好或最有效的方法,但我认为逻辑相当合理,并且当它工作时效果很好。但是,代码中有一个奇怪的、间歇性的错误,我无法解释。
当我第一次创建这个时,代码在我的机器上运行良好,但很快就让我同事的电脑崩溃了。我们俩都在公司通勤者的 Windows 7 上使用 Excel 2013,因此自定义或变化的范围并不大,但脚本在我的计算机上运行良好,但在他的计算机上崩溃了。错误消息总是相同的,某种形式的“下标超出范围”错误,但我无法解释原因,特别是因为完全相同的脚本能够在我的计算机上导入完全相同的文件而没有问题.
运行更多测试并添加一些调试代码,我现在能够可靠地在我的计算机上重新创建错误。我已将崩溃范围缩小到一行,但现在它比以前更没有意义了。以下 sn-p 中的最后一行不仅会导致脚本崩溃,还会导致 Excel 崩溃:
If (PopulateArray(ImportArray) = False) Then
MsgBox "Failed to load import file. Aborting."
Exit Sub
End If
DebugCheckpoint = "ImportArray tests"
Debug.Print "ImportArray tests"
Debug.Print "ImportArray = (" & LBound(ImportArray, 1) & " to " & UBound(ImportArray, 1) _
& ", " & LBound(ImportArray, 2) & " to " & UBound(ImportArray, 2) & ")"
' Crashes on the next line
Debug.Print "ImportArray(1, 1) = " & ImportArray(1, 1)
PopulateArray 函数提示用户输入一个导入文件并对文件运行一些验证。如果未选择文件或验证测试失败,则返回 false。倒数第二个 Debug.Print 行显示 ImportArray 的尺寸,而崩溃的那一行只是尝试显示第一个元素。下面是使用有效导入文件的即时窗口的外观:
ImportArray tests
ImportArray = (1 to 143, 1 to 5)
"Debug.Print "ImportArray(1, 1) = " & ImportArray(1, 1)" 行没有显示在此窗口中,所以大概是脚本崩溃的那个,但我不明白为什么。我们从上一行知道该数组有 143 x 5 条记录,都以 1 为基数,那么 item (1, 1) 怎么会“超出范围”呢?我在脚本的不同部分尝试了各种代码来尝试解释正在发生的事情,但无济于事。数组似乎只是随机消失。
谁能解释一下这里发生了什么,或者至少给我一些建议来尝试进一步调查。即使我已将崩溃范围缩小到一条线,我也完全看不出那条线导致崩溃的原因。我也不明白为什么它以前可以正常工作,但现在它崩溃了,而我所做的只是添加一些调试代码。
如果可以的话,请帮助我了解发生了什么。
编辑:
好的,我已经缩小了很多范围,并在 Populate() 函数中添加了一些错误检查代码,这样应该更容易看到现在发生了什么。这是完整的主要脚本:
Sub ImportArrayTest()
Dim ImportArray() As Variant
If (PopulateArrayTest(ImportArray) = False) Then
MsgBox "Failed to load import file. Aborting."
Exit Sub
End If
Debug.Print "ImportArray tests"
Debug.Print "ImportArray = (" & LBound(ImportArray, 1) & " to " & UBound(ImportArray, 1) _
& ", " & LBound(ImportArray, 2) & " to " & UBound(ImportArray, 2) & ")"
Debug.Print ImportArray(3, 3)
End Sub
虽然这是精简后的 Populate() 函数:
Function PopulateArrayTest(ImportTable As Variant) As Boolean
Dim ImportFile As Workbook
Dim ImportFileName As Variant
PopulateArrayTest = False
ImportFileName = Application.GetOpenFilename("Excel (*.xls*),*.xls*", 1, "Please select report")
Set ImportFile = Application.Workbooks.Open(ImportFileName)
With ImportFile.Worksheets(1)
ImportTable = .Range(.Cells(5, 1), .Cells(.Range("a5").End(xlDown).Row, 5))
End With
Debug.Print "ImportTable tests"
Debug.Print "ImportTable = (" & LBound(ImportTable, 1) & " to " & UBound(ImportTable, 1) _
& ", " & LBound(ImportTable, 2) & " to " & UBound(ImportTable, 2) & ")"
Debug.Print "ImportTable (1, 1) = " & ImportTable(1, 1)
PopulateArrayTest = True
ImportFile.Close
End Function
脚本现在在 PopulateArrayTest 函数中的“Debug.Print ImportTable(1, 1)”行崩溃,并使用 Excel。即时窗口中的输出如下所示:
ImportTable tests
ImportTable = (1 to 143, 1 to 5)
因此 ImportTable 正在根据导入文件中表的大小正确调整大小,但访问它会给出“下标超出范围错误”。我真的看不出这里有什么问题。谁能看到我错过了什么?
【问题讨论】:
-
要真正缩小范围,您只需删除所有
On Error Go To语句,以便宏将在抛出第一个错误的那一行失败并弹出一个对话框,您将在其中按“调试”跳到违规行 -
如果调用
PopulateArray导致 Excel 崩溃,那么这就是您需要发布的代码。 -
@Tim Williams 呼叫
PopulateArray似乎工作正常。当我尝试访问数据时,稍后会发生崩溃。不过,我会进一步调查,看看这是否是个问题。 -
无论如何,您应该发布所有相关代码。你的帖子有太多的文字,没有足够的代码。二手调试不好玩。
-
@Tim Williams 明白了,但我一直在尝试解决这个问题。该错误是间歇性的-有时脚本有效,有时无效-因此我不希望您能够找到甚至重新生成它。相反,我希望找到指针或策略来帮助我理解它为什么会崩溃。