MS-Access, VBA и обработка ошибок - PullRequest
19 голосов
/ 11 декабря 2008

Это скорее наблюдение, чем реальный вопрос: MS-Access (и VBA в целом) отчаянно не хватает инструмента, где код обработки ошибок может генерироваться автоматически, и где номер строки может отображаться при возникновении ошибки. Вы нашли решение? Что это? Я только что понял, сколько сотен часов я потратил с тех пор, как несколько лет назад нашел правильный ответ на эту основную проблему, и я хотел бы узнать, каковы ваши идеи и решения по этому очень важному вопросу.

Ответы [ 5 ]

7 голосов
/ 11 декабря 2008

Как насчет использования "Erl", оно будет отображать последний ярлык перед ошибкой (например, 10, 20 или 30)?

Private Sub mySUB()
On Error GoTo Err_mySUB
10:
    Dim stDocName As String
    Dim stLinkCriteria As String
20:
    stDocName = "MyDoc"
30:
    DoCmd.openform stDocName, acFormDS, , stLinkCriteria    
Exit_mySUB:
    Exit Sub
Err_mySUB:
    MsgBox Err.Number & ": " & Err.Description & " (" & Erl & ")"
    Resume Exit_mySUB
End Sub
6 голосов
/ 11 декабря 2008

Мое решение следующее:

  1. установка MZ-Tools , очень интересное дополнение для VBA. Нет, они не заплатили мне, чтобы написать это. Версия 3 была бесплатной, но начиная с версии 8.0, надстройка продается в коммерческих целях.
  2. запрограммируйте стандартный код обработчика ошибок, такой как этот (см. Меню MZ-Tools / Параметры / Обработчик ошибок):

On Error GoTo {PROCEDURE_NAME}_Error
{PROCEDURE_BODY}
On Error GoTo 0
Exit {PROCEDURE_TYPE}

{PROCEDURE_NAME}_Error:
debug.print "#" & Err.Number, Err.description, "l#" & erl, "{PROCEDURE_NAME}", "{MODULE_NAME}"

Этот стандартный код ошибки может быть автоматически добавлен ко всем вашим процессам и функциям, нажав соответствующую кнопку в меню MZ-Tools. Вы заметите, что мы ссылаемся здесь на скрытую и недокументированную функцию в стандартной библиотеке VBA, «Erl», что означает «строка ошибки». Ты понял! Если вы попросите MZ-Tools автоматически нумеровать ваши строки кода, «Erl» даст вам номер строки, где произошла ошибка. В вашем ближайшем окне вы получите полное описание ошибки, например:

#91, Object variable or With block variable not set, l# 30, addNewField, Utilities

Конечно, как только вы осознаете интерес системы, вы можете подумать о более сложном обработчике ошибок, который будет не только отображать данные в окне отладки, но и:

  1. отобразить его как сообщение на экране
  2. Автоматически вставить строку в файл журнала ошибок с описанием ошибки или
  3. если вы работаете с Access или если вы подключены к базе данных, автоматически добавьте запись в таблицу Tbl_Error!

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

5 голосов
/ 11 декабря 2008

Ну, есть пара инструментов, которые будут делать то, что вы просите MZ Tools и FMS Inc приходят на ум.

В основном они включают добавление:

On Error GoTo ErrorHandler

к началу каждого процесса и в конце они положили:

ErrorHandler:
  Call MyErrorhandler Err.Number, Err.Description, Err.LineNumber

метка, обычно с вызовом глобального обработчика ошибок, где вы можете отображать и регистрировать пользовательские сообщения об ошибках

2 голосов
/ 10 февраля 2019

Нет необходимости покупать инструменты, упомянутые DJ. Вот мой код бесплатно:

Public Sub InsertErrHandling(modName As String)
    Dim Component As Object
    Dim Name As String
    Dim Kind As Long
    Dim FirstLine As Long
    Dim ProcLinesCount As Long
    Dim Declaration As String
    Dim ProcedureType As String
    Dim Index As Long, i As Long
    Dim LastLine As Long
    Dim StartLines As Collection, LastLines As Collection, ProcNames As Collection, ProcedureTypes As Collection
    Dim gotoErr As Boolean

    Kind = 0
    Set StartLines = New Collection
    Set LastLines = New Collection
    Set ProcNames = New Collection
    Set ProcedureTypes = New Collection

    Set Component = Application.VBE.ActiveVBProject.VBComponents(modName)
        With Component.CodeModule

            ' Remove empty lines on the end of the code
            For i = .CountOfLines To 1 Step -1
                If Component.CodeModule.Lines(i, 1) = "" Then
                  Component.CodeModule.DeleteLines i, 1
                Else
                    Exit For
                End If
            Next i

            Index = .CountOfDeclarationLines + 1
            Do While Index < .CountOfLines
                gotoErr = False
                Name = .ProcOfLine(Index, Kind)
                FirstLine = .ProcBodyLine(Name, Kind)
                ProcLinesCount = .ProcCountLines(Name, Kind)
                Declaration = Trim(.Lines(FirstLine, 1))
                LastLine = FirstLine + ProcLinesCount - 2
                If InStr(1, Declaration, "Function ", vbBinaryCompare) > 0 Then
                    ProcedureType = "Function"
                Else
                    ProcedureType = "Sub"
                End If
                Debug.Print Component.Name & "." & Name, "First: " & FirstLine, "Lines:" & ProcLinesCount, "Last: " & LastLine, Declaration
                Debug.Print "Declaration: " & Component.CodeModule.Lines(FirstLine, 1), FirstLine
                Debug.Print "Closing Proc: " & Component.CodeModule.Lines(LastLine, 1), LastLine

                ' do not insert error handling if there is one already:
                For i = FirstLine To LastLine Step 1
                    If Component.CodeModule.Lines(i, 1) Like "*On Error*" Then
                        gotoErr = True
                        Exit For
                    End If
                Next i
                If Not gotoErr Then
                    StartLines.Add FirstLine
                    LastLines.Add LastLine
                    ProcNames.Add Name
                    ProcedureTypes.Add ProcedureType
                End If

                Index = FirstLine + ProcLinesCount + 1
            Loop

            For i = LastLines.Count To 1 Step -1
                If Not (Component.CodeModule.Lines(StartLines.Item(i) + 1, 1) Like "*On Error GoTo *") Then
                    Component.CodeModule.InsertLines LastLines.Item(i), "ExitProc_:"
                    Component.CodeModule.InsertLines LastLines.Item(i) + 1, "    Exit " & ProcedureTypes.Item(i)
                    Component.CodeModule.InsertLines LastLines.Item(i) + 2, "ErrHandler_:"
                    Component.CodeModule.InsertLines LastLines.Item(i) + 3, "    Call LogError(Err, Me.Name, """ & ProcNames.Item(i) & """)"
                    Component.CodeModule.InsertLines LastLines.Item(i) + 4, "    Resume ExitProc_"
                    Component.CodeModule.InsertLines LastLines.Item(i) + 5, "    Resume ' use for debugging"

                    Component.CodeModule.InsertLines StartLines.Item(i) + 1, "    On Error GoTo ErrHandler_"
                End If
            Next i
        End With
End Sub

Поместите его в модуль и вызывайте его из Immediate Window каждый раз, когда вы добавляете новую функцию или подчиненную форму в форму или модуль, подобный этому (Form1 - это имя вашей формы):

MyModule.InsertErrHandling "Form_Form1"

Это изменит вашу оду в Form1 из этого:

Private Function CloseIt()
    DoCmd.Close acForm, Me.Name
End Function

к этому:

Private Function CloseIt()
    On Error GoTo ErrHandler_
        DoCmd.Close acForm, Me.Name
ExitProc_:
Exit Function
ErrHandler_:
    Call LogError(Err, Me.Name, "CloseIt")
    Resume ExitProc_
    Resume ' use for debugging
End Function

Создайте сейчас в модуле подпрограмму, в которой будет отображаться диалоговое окно с сообщением об ошибке и куда можно добавить вставку ошибки в текстовый файл или базу данных:

Public Sub LogError(ByVal objError As ErrObject, moduleName As String, Optional procName As String = "")
    On Error GoTo ErrHandler_
    Dim sql As String
    MsgBox "Error " & Err.Number & " Module " & moduleName & Switch(procName <> "", " in " & procName) & vbCrLf & " (" & Err.Description & ") ", vbCritical
Exit_:
    Exit Sub
ErrHandler_:
    MsgBox "Error in LogError procedure " & Err.Number & ", " & Err.Description
    Resume Exit_
    Resume ' use for debugging
End Sub

Этот код не вводит обработку ошибок, если в процедуре уже есть оператор "On Error".

2 голосов
/ 30 июня 2014

Вы всегда можете свернуть свой собственный инструмент, как Чип Пирсон . VBA может получить доступ к своей собственной среде IDE через библиотеку Microsoft Visual Basic для приложений, расширяемость 5.3 . Я написал несколько модулей классов, которые облегчают работу с самим собой. Их можно найти на Code Review SE .

Я использую его для вставки On Error GoTo ErrHandler операторов и соответствующих меток и констант, связанных с моей схемой обработки ошибок. Я также использую его для синхронизации констант с реальными именами процедур (если имена функций должны измениться).

...