2016-06-07 3 views
2

Я работаю над сценарием Visual Basic для коллеги некоторое время, которое проявляет странную ошибку, которую я просто не могу получить до конца. При запуске сценарий иногда работает нормально, но время от времени дает мне ошибку «Subscript out of range», которая быстро приводит к сбою Excel.VBA - ошибка индексации вне диапазона 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 по-прежнему терпит крах, хотя ошибка была поймана и очищена? Это первое, что не имеет смысла.

Что касается самого скрипта, то, что я пытаюсь сделать, это заполнить таблицу основных данных на первом листе из таблицы с одинаковой структурой в файле импорта, проверяя фактические и потенциальные повторяющиеся строки. Что должен произойти что-то вроде этого:

  • Пользователь запустить сценарий и выбирает файл импорта через диалоговое окно,

  • Если действительный файл выбран, скрипт запускает некоторые основные проверяет, соответствует ли таблица на этом листе заданному формату,

  • Если эта проверка проходит, сценарий затем заполняет массив (ImportArray), используя эту таблицу, и второй массив из основной таблицы (DataArray).

  • Сценарий также инициализирует два пустых массива: один для элементов, которые будут добавлены в основную таблицу (AddArray), и один для фактического и потенциального дубликатов, которые будут добавлены ко второй таблице в одной и той же электронной таблице (LogArray) ,

  • Затем скрипт проходит через ImportArray, выполняет ряд проверок фактических и потенциальных дубликатов строк между этим и DataArray и добавляет строку в AddArray или LogArray или и то, и другое в случае потенциального дубликаты.

  • Наконец, как только он достигнет конца ImportArray, скрипт добавляет AddArray в главную таблицу и LogArray в таблицу дубликатов, печатает дружественное сообщение и завершает работу.

Это может быть не самый лучший или самый эффективный способ сделать это, но я думаю, что логика достаточно прочная, и когда она работает, она работает очень хорошо.Однако в коде есть странная, прерывистая ошибка, которую я не могу объяснить.

Когда я впервые создал это, код работал нормально на моей машине, но быстро разбил компьютер моих коллег. Мы оба используем Excel 2013 на Windows 7 в компании comuters, поэтому нет большого количества возможностей для настроек или вариантов, но сценарий отлично работал на моем компьютере, но разбился на нем. Сообщение об ошибке всегда одно и то же, некоторая форма ошибки «Subscript out the range», но я не смог объяснить, почему, тем более, что тот же самый скрипт смог импортировать тот же самый файл на моем компьютере без проблем ,

Запуск еще нескольких тестов и добавление кода отладки, теперь я смог надежно заново создать ошибку на своем компьютере. Я сузил крушение до одной строки, но теперь он имеет еще меньший смысл, чем раньше. В последней строке в следующем фрагменте кода происходит сбой не только сценарий, но 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) «вне диапазона»? Я пробовал различные фрагменты кода в разных частях скрипта, чтобы попытаться объяснить, что происходит, но безрезультатно. Кажется, что массив случайно исчезает.

Может кто-нибудь объяснить, что здесь происходит, или, по крайней мере, дать мне несколько указателей, чтобы попытаться исследовать это дальше. Несмотря на то, что я сузил крушение в одну строку, я не вижу абсолютно никакой причины, почему эта линия вызывает крушение. Я также не могу понять, почему он работал нормально, но теперь он сбой, когда все, что я сделал, это добавить код отладки.

Пожалуйста, помогите мне понять, что происходит, если можете.


EDIT:

ОК, я сузил это вниз совсем немного и добавил некоторые проверки ошибок кода функции 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 идет правильно повторно размер в зависимости от размера таблицы в файле импорт, но доступ к ней дает «Подстрочную из ошибок диапазона. " Я действительно не понимаю, в чем проблема. Может ли кто-нибудь увидеть то, что мне не хватает?

+1

к на самом деле сузить его, вы просто удаляете любые операторы «On Error Go To», чтобы макрос не сработал в самой строке, бросая первую ошибку и всплывая диалоговое окно, в котором вы нажмете «Debug», чтобы перейти на строку нарушения – user3598756

+0

Если вызов 'PopulateArray' приводит к сбою Excel то это код, который вам нужно отправить. –

+0

@Tim Williams Вызов 'PopulateArray', кажется, работает нормально. Сбой происходит позже, когда я пытаюсь получить доступ к данным. Тем не менее, я рассмотрю это больше, чтобы узнать, не проблема. – xarxziux

ответ

1

Проблема в том, что ваши типы не совпадают полностью.Правило здесь состоит в том, что тип данных массива, объявленного в вызывающей процедуре, должен соответствовать типу данных, объявленному в списке параметров вызываемой процедуры. Вы передаете Variant Array в параметр Variant. Это не работает в VBA с параметром ByRef, поэтому ImportArray будет пустым в вашем методе ImportArrayTest.

Чтобы избежать этих проблем, необходимо изменить функцию, чтобы вернуть массив Variant вместо передачи его обратно в качестве ByRef параметра, как это:

Function PopulateArrayTest() As Variant() 

и назвать его так:

Dim ImportArray() As Variant 
ImportArray = PopulateArrayTest() 
+0

Хорошо, я думаю, что возможно. Я быстро скорректировал код там, и он прошел. Я должен буду более внимательно посмотреть, все ли работает, как ожидалось, но выглядит многообещающим. Большое вам спасибо за то, что нашли время, чтобы посмотреть на это. Вы не представляете, как долго я пытался это исправить. – xarxziux

+0

Я знаю, сначала это звучит странно. Но, похоже, это ограничение для параметров ByRef в VBA. Ссылка, которая обрабатывает эту тему, приведена здесь: http://www.cpearson.com/excel/passingandreturningarrays.htm – Mono

+0

Я принял ваш ответ как правильный, так как код теперь работает так, как ожидалось. У меня возникла небольшая проблема с возвратом пустого массива в случае сбоя выбора пользователя или проверки, но я завернул строку 'ImportArray = PopulateArrayTest()' в инструкции 'On Error Resume Next', которая улавливает проблему. Возможно, это не лучший способ сделать это, но пока достаточно хорошо. Сценарий используется только один файл импорта один раз в месяц, поэтому работающий хак подходит для моих целей. Большое спасибо за вашу помощь в этом. Я бы не подумал об этом сам. – xarxziux

Смежные вопросы