我一直在为一位同事制作一个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附加到duplicates表,打印友好消息并退出。
这可能不是最好或最有效的方法,但我认为逻辑相当合理,当它工作时它运作得很好。但是,代码中存在一个奇怪的,间歇性的错误,我无法解释。
当我第一次创建它时,代码在我的机器上正常运行,但很快就崩溃了我的同事计算机。我们俩都在公司计算机上使用Windows 7上的Excel 2013,因此自定义或变体的范围不是很大,但脚本在我的计算机上工作正常,但在他的计算机上崩溃了。错误消息总是相同的,某些形式的"下标超出范围"错误,但我无法解释原因,特别是因为完全相同的脚本能够在我的计算机上导入完全相同的文件而没有任何问题。
运行更多测试并添加一些调试代码,我现在能够在我的计算机上可靠地重新创建错误。我已经将碰撞缩小到一条线,但它现在比以前更没意义了。以下代码段中的最后一行不仅崩溃了脚本,还崩溃了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,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
脚本现在崩溃了" Debug.Print ImportTable(1,1)"在PopulateArrayTest函数中并使用Excel。立即窗口中的输出如下所示:
ImportTable tests
ImportTable = (1 to 143, 1 to 5)
因此,根据导入文件中表的大小正确地重新调整了ImportTable的大小,但访问它会导致"下标超出范围错误。"我真的不知道这里的问题是什么。谁能看到我失踪的东西?
答案 0 :(得分:1)
问题是您的类型不完全匹配。这里的规则是在调用过程中声明的数组的数据类型必须与在被调用过程的参数列表中声明的数据类型匹配。您将Variant数组传递给Variant参数。这在带有ByRef参数的VBA中不起作用,因此ImportArray在ImportArrayTest方法中将为空。
要避免这些问题,您应该更改函数以返回Variant数组,而不是将其作为ByRef参数传回,如下所示:
Function PopulateArrayTest() As Variant()
并将其称为:
Dim ImportArray() As Variant
ImportArray = PopulateArrayTest()