Gute Muster für die VBA-Fehlerbehandlung

74

Was sind einige gute Muster für die Fehlerbehandlung in VBA?

Was soll ich insbesondere in dieser Situation tun:

... some code ...
... some code where an error might occur ...
... some code ...
... some other code where a different error might occur ...
... some other code ...
... some code that must always be run (like a finally block) ...

Ich möchte beide Fehler behandeln und die Ausführung nach dem Code fortsetzen, in dem der Fehler auftreten kann. Außerdem muss der endgültige Code am Ende IMMER ausgeführt werden - unabhängig davon, welche Ausnahmen früher ausgelöst wurden. Wie kann ich dieses Ergebnis erzielen?

Jwoolard
quelle

Antworten:

101

Fehlerbehandlung in VBA


  • On Error Goto ErrorHandlerLabel
  • Resume( Next| ErrorHandlerLabel )
  • On Error Goto 0 (Deaktiviert die aktuelle Fehlerbehandlungsroutine)
  • Err Objekt

Die ErrEigenschaften des Objekts werden normalerweise in der Fehlerbehandlungsroutine auf Null oder eine Zeichenfolge mit der Länge Null zurückgesetzt, dies kann jedoch auch explizit mit erfolgen Err.Clear.

Fehler in der Fehlerbehandlungsroutine werden beendet.

Der Bereich 513-65535 ist für Benutzerfehler verfügbar. Bei benutzerdefinierten Klassenfehlern fügen Sie vbObjectErrordie Fehlernummer hinzu. Siehe MS-Dokumentation zu Err.Raiseund die Liste der Fehlernummern .

Für nicht implementierte Schnittstellenelemente in einer abgeleiteten Klasse sollten Sie die Konstante verwenden E_NOTIMPL = &H80004001.


Option Explicit

Sub HandleError()
  Dim a As Integer
  On Error GoTo errMyErrorHandler
    a = 7 / 0
  On Error GoTo 0

  Debug.Print "This line won't be executed."

DoCleanUp:
  a = 0
Exit Sub
errMyErrorHandler:
  MsgBox Err.Description, _
    vbExclamation + vbOKCancel, _
    "Error: " & CStr(Err.Number)
Resume DoCleanUp
End Sub

Sub RaiseAndHandleError()
  On Error GoTo errMyErrorHandler
    ' The range 513-65535 is available for user errors.
    ' For class errors, you add vbObjectError to the error number.
    Err.Raise vbObjectError + 513, "Module1::Test()", "My custom error."
  On Error GoTo 0

  Debug.Print "This line will be executed."

Exit Sub
errMyErrorHandler:
  MsgBox Err.Description, _
    vbExclamation + vbOKCancel, _
    "Error: " & CStr(Err.Number)
  Err.Clear
Resume Next
End Sub

Sub FailInErrorHandler()
  Dim a As Integer
  On Error GoTo errMyErrorHandler
    a = 7 / 0
  On Error GoTo 0

  Debug.Print "This line won't be executed."

DoCleanUp:
  a = 0
Exit Sub
errMyErrorHandler:
  a = 7 / 0 ' <== Terminating error!
  MsgBox Err.Description, _
    vbExclamation + vbOKCancel, _
    "Error: " & CStr(Err.Number)
Resume DoCleanUp
End Sub

Sub DontDoThis()

  ' Any error will go unnoticed!
  On Error Resume Next
  ' Some complex code that fails here.
End Sub

Sub DoThisIfYouMust()

  On Error Resume Next
  ' Some code that can fail but you don't care.
  On Error GoTo 0

  ' More code here
End Sub
guillermooo
quelle
1
Das ist großartig, aber gibt es einen Ort, an dem alle Fehler aufgelistet sind, damit ich weiß, ob meine bereits vorhanden sind oder ob ich sie erstellen muss?
PsychoData
3
@ PsychoData, hier ist eine Liste der Fehlercodes support.microsoft.com/kb/146864
Elias
Wie sollte der obige Code geändert werden, um die Eingabe und jeden Ausgang des aufgerufenen Codes (Prozedur, Funktion, Methode usw.) anzumelden ?
Aleksey F.
36

Ich würde auch hinzufügen:

  • Das globale ErrObjekt kommt einem Ausnahmeobjekt am nächsten
  • Sie können effektiv "eine Ausnahme auslösen" mit Err.Raise

Und nur zum Spaß:

  • On Error Resume Next ist der inkarnierte Teufel und zu vermeiden, da er Fehler stillschweigend verbirgt
Joel Goodwin
quelle
11
+1 für die Warnung zu On Eror Resume Next. Wahrscheinlich einer der Hauptgründe, warum VB-Programme im Allgemeinen so voller Fehler sind.
Makis
13
Nicht wahr. Bei korrekter Verwendung entspricht On Error Resume Next einem Versuch / Fang. Für eine korrekte Verwendung muss lediglich der Fehlerstatus nach jeder Zeile überprüft oder gespeichert werden . Komplexe Fehlerprüfungen werden dadurch weniger ausführlich. Bei falscher Verwendung gilt jedoch alles oben Genannte.
Ben McIntyre
3
Ich denke, jeder würde zustimmen, dass On Error das Äquivalent von Try / Catch ist, ja ... aber On Error Resume Next? Dadurch verschwinden alle Fehler - auch die, die wir nie erwartet haben. Es ist besser, Fehler wochenlang ausbluten zu lassen, als sich zu kratzen, warum etwas Seltsames vor sich geht [das ist mir beim Debuggen des Codes eines anderen passiert]. Ich benutze es nur unter ganz besonderen Umständen, bei engen kleinen Funktionen, bei denen eine Kuriosität Sie zu einem Fehler zwingt (z. B. existiert dieser Gegenstand in einer Sammlung).
Joel Goodwin
2
Wenn Sie zu viel Code in errMyErrorHandler einfügen, besteht die Gefahr, dass in Ihrem Fehlerhandler ein Fehler auftritt, der eine Endlosschleife erzeugt. Wenn Sie On Error Resume Next aktivieren, bevor Sie den Fehler in errMyErrorHandler verarbeiten, wird das Err-Objekt zurückgesetzt, und Sie verlieren die Fehlerinformationen. Ich verschiebe meine Fehlerverarbeitung in ein Sub und übergebe die err.num und die Beschreibung als Parameter, damit ich On On Error Resume Next verwenden kann, wenn ich alles wie Screenupdating und Cursor usw. zurücksetze und den Fehler mit den Parameterwerten zeige ...Call mdl_val.usr_sub_handle_error(Err.Source, Err.Description)
DWiener
1
"vermieden werden" ist nicht genau. Es sind viele Fälle erforderlich On Error Resume Next. Das gemeinsame Prinzip dieser Fälle ist, wenn einige Ergebnisse durch Auslösen einer Ausnahme zurückgegeben werden. Der häufigste Fall ist der Zugriff auf ein CollectionObjekt über den Zeichenfolgenschlüssel: In diesem Fall kann der Aufrufer nicht wissen, ob sich im CollectionObjekt ein Element mit diesem Schlüssel befindet .
Aleksey F.
18

Sie könnten also so etwas tun

Function Errorthingy(pParam)
On Error GoTo HandleErr

 ' your code here

    ExitHere:
    ' your finally code
    Exit Function

    HandleErr:
        Select Case Err.Number
        ' different error handling here'
        Case Else
            MsgBox "Error " & Err.Number & ": " & Err.Description, vbCritical, "ErrorThingy"
        End Select


   Resume ExitHere

End Function

Wenn Sie benutzerdefinierte Ausnahmen backen möchten. (z. B. solche, die gegen Geschäftsregeln verstoßen) Verwenden Sie das obige Beispiel, aber verwenden Sie das Goto, um den Ablauf der Methode nach Bedarf zu ändern.

Johnno Nolan
quelle
1
So haben wir damals mit Fehlern in einer großen VB6-Anwendung umgegangen. Funktionierte relativ gut und war einfach zu bedienen. IIRC, wir hatten eine Fehlerbehandlungsklasse, die aufgerufen wurde, anstatt den Fehlercode in der Funktion zu haben. Auf diese Weise war es auch viel einfacher, das Verhalten zu ändern.
Makis
Im Allgemeinen ist es eine gute Idee, "On Error GoTo 0" nach dem Codeblock zu setzen, in dem Sie eine Fehlerbehandlung benötigen. Außerdem wird jeder Fehler im Fehlerbehandlungscode beendet.
Guillermooo
4
Keine Ahnung, ob dies eine idiomatische VBA ist, aber für .NET-Entwickler, wenn Sie "HandleErr" in "Catch" und "ExitHere" in "Endlich" umbenennen und blinzeln ...
user1454265
@ user1454265 ... dann können Sie leicht das übersehen Resume ExitHere, was einen großen Unterschied zwischen den beiden Paradigmen macht.
AntoineL
12

Hier ist meine Standardimplementierung. Ich mag es, wenn die Etiketten selbstbeschreibend sind.

Public Sub DoSomething()

    On Error GoTo Catch ' Try
    ' normal code here

    Exit Sub
Catch:

    'error code: you can get the specific error by checking Err.Number

End Sub

Oder mit einem FinallyBlock:

Public Sub DoSomething()

    On Error GoTo Catch ' Try

    ' normal code here

    GoTo Finally
Catch:

    'error code

Finally:

    'cleanup code

End Sub
LimaNightHawk
quelle
1
Was passiert, wenn danach eine Ausnahme ausgelöst wird Finally:? Also On Error GoTo 0sofort danach muss Finally:vielleicht die unerwünschte Rekursion behoben werden.
Aleksey F.
2
Wenn nach dem FinallyBlock ein Fehler auftritt, wird nur der Fehler ausgegeben. Es wird nicht wieder zum FinallyBlock zurückgeschleift. (Probieren Sie es aus, Sie werden sehen.) Wenn Sie einen Fehler nach dem Block "finally" behandeln möchten, müssen Sie einen weiteren hinzufügen On Error GoTo, wahrscheinlich jedoch mit einem anderen Label, z Catch2. Aber hier fangen wir an, uns mit der Clean Code-Methodik zu befassen -> eine Clean-Methode benötigt nur einen Fehlerbehandler (und sollte sogar eine eigene Methode zur Fehlererkennung haben).
LimaNightHawk
1
@LimaNightHawk: Ich glaube, was danach passiert, Finally:hängt davon ab, ob Sie es betreten, nachdem Sie umgeleitet wurden Catch:(dann wirft es ja einfach raus) ... oder nicht ! Und in diesem letzteren Fall, dh wenn Sie es durchlaufen GoTo Finallyhaben, ist das On Error GoTo Catchnoch in Kraft, sodass die Steuerung umgeleitet wird Catch:(könnte eine gute Sache sein) und dann Finally:erneut eingegeben wird, wahrscheinlich nicht das, was Sie ursprünglich erwartet haben.
AntoineL
Wenn Sie eine weitere hinzufügen , On Error GoTo Catch2in Finally:Code, wird es in diesem letzteren Fall wirksam gewesen , aber nicht , wenn Sie ging durch Catch:vor, weil es keine On Error GoTo -1noch ein Resume; Das Hinzufügen des ersteren bringt uns so weit vom Normalen weg, try catch finallydass man erwägen könnte, zweifelhafte Analogien vor diesem Punkt zu beenden.
AntoineL
@AntoineL Ja! Stimmen Sie mit beiden überein, gute Beobachtung und Klarstellung.
LimaNightHawk
4

Professionelle Excel-Entwicklung hat ein ziemlich gutes Fehlerbehandlungsschema . Wenn Sie Zeit in VBA verbringen möchten, lohnt es sich wahrscheinlich, das Buch zu bekommen. Es gibt eine Reihe von Bereichen, in denen VBA fehlt, und dieses Buch enthält gute Vorschläge für die Verwaltung dieser Bereiche.

PED beschreibt zwei Fehlerbehandlungsmethoden. Das wichtigste ist ein System, bei dem alle Einstiegspunktprozeduren Unterprozeduren und alle anderen Prozeduren Funktionen sind, die Boolesche Werte zurückgeben.

Die Einstiegspunktprozedur verwendet On Error-Anweisungen, um Fehler so gut wie geplant zu erfassen. Die Prozeduren ohne Einstiegspunkt geben True zurück, wenn keine Fehler aufgetreten sind, und False, wenn Fehler aufgetreten sind. Prozeduren, die keine Einstiegspunkte sind, verwenden ebenfalls On Error.

Beide Arten von Prozeduren verwenden eine zentrale Fehlerbehandlungsprozedur, um den Fehler im Status zu halten und den Fehler zu protokollieren.

Dick Kusleika
quelle
3

Ich verwende einen Code, den ich selbst entwickelt habe und der für meine Codes ziemlich gut ist:

Am Anfang der Funktion oder des Sub definiere ich:

On error Goto ErrorCatcher:

und dann behandle ich die möglichen Fehler

ErrorCatcher:
Select Case Err.Number

Case 0 'exit the code when no error was raised
    On Error GoTo 0
    Exit Function
Case 1 'Error on definition of object
    'do stuff
Case... 'little description here
    'do stuff
Case Else
    Debug.Print "###ERROR"
    Debug.Print "   • Number  :", Err.Number
    Debug.Print "   • Descrip :", Err.Description
    Debug.Print "   • Source  :", Err.Source
    Debug.Print "   • HelpCont:", Err.HelpContext
    Debug.Print "   • LastDLL :", Err.LastDllError
    Stop
    Err.Clear
    Resume
End Select
Thiago Cardoso
quelle
3

Hier ist ein ziemlich anständiges Muster.

Zum Debuggen: Wenn ein Fehler auftritt, drücken Sie Strg-Pause (oder Strg-Pause), ziehen Sie die Unterbrechungsmarkierung (oder wie auch immer sie heißt) nach unten in die Zeile Fortsetzen, drücken Sie F8 und Sie gelangen zu der Zeile, die "geworfen" hat. der Fehler.

Der ExitHandler ist Ihr "Endlich".

Sanduhr wird jedes Mal getötet. Der Text in der Statusleiste wird jedes Mal gelöscht.

Public Sub ErrorHandlerExample()
    Dim dbs As DAO.Database
    Dim rst As DAO.Recordset

    On Error GoTo ErrHandler
    Dim varRetVal As Variant

    Set dbs = CurrentDb
    Set rst = dbs.OpenRecordset("SomeTable", dbOpenDynaset, dbSeeChanges + dbFailOnError)

    Call DoCmd.Hourglass(True)

    'Do something with the RecordSet and close it.

    Call DoCmd.Hourglass(False)

ExitHandler:
    Set rst = Nothing
    Set dbs = Nothing
    Exit Sub

ErrHandler:
    Call DoCmd.Hourglass(False)
    Call DoCmd.SetWarnings(True)
    varRetVal = SysCmd(acSysCmdClearStatus)

    Dim errX As DAO.Error
    If Errors.Count > 1 Then
       For Each errX In DAO.Errors
          MsgBox "ODBC Error " & errX.Number & vbCrLf & errX.Description
       Next errX
    Else
        MsgBox "VBA Error " & Err.Number & ": " & vbCrLf & Err.Description & vbCrLf & "In: Form_MainForm", vbCritical
    End If

    Resume ExitHandler
    Resume

End Sub



    Select Case Err.Number
        Case 3326 'This Recordset is not updateable
            'Do something about it. Or not...
        Case Else
            MsgBox "VBA Error " & Err.Number & ": " & vbCrLf & Err.Description & vbCrLf & "In: Form_MainForm", vbCritical
    End Select

Es werden auch DAO- und VBA-Fehler abgefangen. Sie können einen Auswahlfall in den Abschnitt VBA-Fehler einfügen, wenn Sie nach bestimmten Fehlernummern suchen möchten.

Select Case Err.Number
    Case 3326 'This Recordset is not updateable
        'Do something about it. Or not...
    Case Else
        MsgBox "VBA Error " & Err.Number & ": " & vbCrLf & Err.Description & vbCrLf & "In: Form_MainForm", vbCritical
End Select
pfeifen Briten
quelle
3

Der folgende Code zeigt eine Alternative, die sicherstellt, dass es nur einen Austrittspunkt für das Unter / die Funktion gibt.

sub something()
    on error goto errHandler

    ' start of code
    ....
    ....
    'end of code

    ' 1. not needed but signals to any other developer that looks at this
    ' code that you are skipping over the error handler...
    ' see point 1...
    err.clear

errHandler:
    if err.number <> 0 then
        ' error handling code
    end if
end sub
nickD
quelle
3

Ebenfalls relevant für die Diskussion ist die relativ unbekannte ErlFunktion. Wenn Ihre Code-Prozedur numerische Beschriftungen enthält, z.

Sub AAA()
On Error Goto ErrorHandler

1000:
' code
1100:
' more code
1200:
' even more code that causes an error
1300:
' yet more code
9999: ' end of main part of procedure
ErrorHandler:
If Err.Number <> 0 Then
   Debug.Print "Error: " + CStr(Err.Number), Err.Descrption, _
      "Last Successful Line: " + CStr(Erl)
End If   
End Sub 

Die ErlFunktion gibt die zuletzt gefundene Beschriftung der numerischen Zeilen zurück. Wenn im obigen Beispiel ein Laufzeitfehler nach dem Beschriften, 1200:aber vorher auftritt 1300:, wird die ErlFunktion zurückgegeben 1200, da dies die am häufigsten auftretende Zeilenbeschriftung ist. Ich halte es für eine gute Praxis, eine Zeilenbeschriftung direkt über Ihrem Fehlerbehandlungsblock anzubringen. Ich benutze normalerweise, 9999um anzuzeigen, dass der Hauptteil der Prozedur zu seinem erwarteten Konkuls lief.

ANMERKUNGEN:

  • MadeItHere:Zeilenbeschriftungen MÜSSEN positive ganze Zahlen sein - eine Beschriftung wie wird von nicht erkannt Erl.

  • Zeilenbeschriftungen haben nichts mit den tatsächlichen Zeilennummern von a zu tun VBIDE CodeModule. Sie können beliebige positive Zahlen in beliebiger Reihenfolge verwenden. Im obigen Beispiel gibt es nur etwa 25 Codezeilen, aber die Zeilennummern beginnen bei 1000. Es gibt keine Beziehung zwischen den Zeilennummern des Editors und den mit verwendeten Zeilennummern Erl.

  • Die Zeilenbeschriftungsnummern müssen nicht in einer bestimmten Reihenfolge angegeben werden. Wenn sie jedoch nicht in aufsteigender Reihenfolge von oben nach unten angeordnet sind, ist die Wirksamkeit und der Nutzen von Erlstark beeinträchtigt, es Erlwird jedoch weiterhin die richtige Nummer angegeben.

  • Linienbeschriftungen sind spezifisch für das Verfahren, in dem sie angezeigt werden. Wenn die Prozedur ProcAdie Prozedur aufruft ProcBund ein Fehler auftritt ProcB, der die Steuerung an zurückgibt, ProcAgibt Erl(in ProcA) die zuletzt angetroffene Zeilennummer zurück, ProcAbevor sie aufgerufen wird ProcB. Von innen ProcAkönnen Sie die Zeilenbeschriftungsnummern, die möglicherweise in angezeigt werden, nicht abrufen ProcB.

Seien Sie vorsichtig, wenn Sie Zeilennummern in eine Schleife einfügen. Zum Beispiel,

For X = 1 To 100
500:
' some code that causes an error
600:
Next X

Wenn der Code nach der Zeilenbezeichnung, 500jedoch vorher, 600einen Fehler verursacht und dieser Fehler bei der 20. Iteration der Schleife auftritt , Erlwird er zurückgegeben 500, obwohl 600er in den vorherigen 19 Interaktionen der Schleife erfolgreich aufgetreten ist.

Die richtige Platzierung von Linienbeschriftungen innerhalb des Verfahrens ist entscheidend für die Verwendung der ErlFunktion, um wirklich aussagekräftige Informationen zu erhalten.

Es gibt eine beliebige Anzahl kostenloser Dienstprogramme im Internet, die automatisch numerische Zeilenbeschriftungen in eine Prozedur einfügen, sodass Sie beim Entwickeln und Debuggen feinkörnige Fehlerinformationen erhalten und diese Beschriftungen entfernen, sobald der Code live geschaltet wird.

Wenn Ihr Code dem Endbenutzer Fehlerinformationen anzeigt, wenn ein unerwarteter Fehler auftritt, kann die Angabe des Werts aus Erldiesen Informationen das Auffinden und Beheben des Problems VAST einfacher machen, als wenn der Wert von Erlnicht gemeldet wird.

Chip Pearson
quelle
3

Ich finde, dass Folgendes am besten funktioniert, der als zentraler Ansatz zur Fehlerbehandlung bezeichnet wird.

Leistungen

Sie haben zwei Möglichkeiten, Ihre Anwendung auszuführen : Debug und Produktion . Im Debug- Modus stoppt der Code bei jedem unerwarteten Fehler und ermöglicht Ihnen ein einfaches Debuggen, indem Sie durch zweimaliges Drücken von F8 zu der Zeile springen, in der er aufgetreten ist. Im Produktionsmodus wird dem Benutzer eine aussagekräftige Fehlermeldung angezeigt.

Sie können absichtliche Fehler wie diesen auslösen, wodurch die Ausführung des Codes mit einer Nachricht an den Benutzer gestoppt wird:

Err.Raise vbObjectError, gsNO_DEBUG, "Some meaningful error message to the user"

Err.Raise vbObjectError, gsUSER_MESSAGE, "Some meaningful non-error message to the user"

'Or to exit in the middle of a call stack without a message:
Err.Raise vbObjectError, gsSILENT

Implementierung

Sie müssen alle Unterprogramme und Funktionen mit einer signifikanten Menge an Code mit den folgenden Kopf- und Fußzeilen "umschließen" und dabei sicherstellen, dass Sie ehCallTypeEntryPointalle Ihre Einstiegspunkte angeben . Beachten Sie auch die msModuleKonstante, die in alle Module eingefügt werden muss.

Option Explicit
Const msModule As String = "<Your Module Name>"

' This is an entry point 
Public Sub AnEntryPoint()
    Const sSOURCE As String = "AnEntryPoint"
    On Error GoTo ErrorHandler

    'Your code

ErrorExit:
    Exit Sub

ErrorHandler:
    If CentralErrorHandler(Err, ThisWorkbook, msModule, sSOURCE, ehCallTypeEntryPoint) Then
        Stop
        Resume
    Else
        Resume ErrorExit
    End If
End Sub

' This is any other subroutine or function that isn't an entry point
Sub AnyOtherSub()
    Const sSOURCE As String = "AnyOtherSub"
    On Error GoTo ErrorHandler

    'Your code

ErrorExit:
    Exit Sub

ErrorHandler:
    If CentralErrorHandler(Err, ThisWorkbook, msModule, sSOURCE) Then
        Stop
        Resume
    Else
        Resume ErrorExit
    End If
End Sub

Der Inhalt des zentralen Fehlerbehandlungsmoduls ist folgender:

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Comments: Error handler code.
'
'           Run SetDebugMode True to use debug mode (Dev mode)
'           It will be False by default (Production mode)
'
' Author:   Igor Popov
' Date:     13 Feb 2014
' Licence:  MIT
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Option Explicit
Option Private Module

Private Const msModule As String = "MErrorHandler"

Public Const gsAPP_NAME As String = "<You Application Name>"

Public Const gsSILENT As String = "UserCancel"  'A silent error is when the user aborts an action, no message should be displayed
Public Const gsNO_DEBUG As String = "NoDebug"   'This type of error will display a specific message to the user in situation of an expected (provided-for) error.
Public Const gsUSER_MESSAGE As String = "UserMessage" 'Use this type of error to display an information message to the user

Private Const msDEBUG_MODE_COMPANY = "<Your Company>"
Private Const msDEBUG_MODE_SECTION = "<Your Team>"
Private Const msDEBUG_MODE_VALUE = "DEBUG_MODE"

Public Enum ECallType
    ehCallTypeRegular = 0
    ehCallTypeEntryPoint
End Enum

Public Function DebugMode() As Boolean
    DebugMode = CBool(GetSetting(msDEBUG_MODE_COMPANY, msDEBUG_MODE_SECTION, msDEBUG_MODE_VALUE, 0))
End Function

Public Sub SetDebugMode(Optional bMode As Boolean = True)
    SaveSetting msDEBUG_MODE_COMPANY, msDEBUG_MODE_SECTION, msDEBUG_MODE_VALUE, IIf(bMode, 1, 0)
End Sub

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Comments: The central error handler for all functions
'           Displays errors to the user at the entry point level, or, if we're below the entry point, rethrows it upwards until the entry point is reached
'
'           Returns True to stop and debug unexpected errors in debug mode.
'
'           The function can be enhanced to log errors.
'
' Date          Developer           TDID    Comment
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 13 Feb 2014   Igor Popov                  Created

Public Function CentralErrorHandler(ErrObj As ErrObject, Wbk As Workbook, ByVal sModule As String, ByVal sSOURCE As String, _
                                    Optional enCallType As ECallType = ehCallTypeRegular, Optional ByVal bRethrowError As Boolean = True) As Boolean

    Static ssModule As String, ssSource As String
    If Len(ssModule) = 0 And Len(ssSource) = 0 Then
        'Remember the module and the source of the first call to CentralErrorHandler
        ssModule = sModule
        ssSource = sSOURCE
    End If
    CentralErrorHandler = DebugMode And ErrObj.Source <> gsNO_DEBUG And ErrObj.Source <> gsUSER_MESSAGE And ErrObj.Source <> gsSILENT
    If CentralErrorHandler Then
        'If it's an unexpected error and we're going to stop in the debug mode, just write the error message to the immediate window for debugging
        Debug.Print "#Err: " & Err.Description
    ElseIf enCallType = ehCallTypeEntryPoint Then
        'If we have reached the entry point and it's not a silent error, display the message to the user in an error box
        If ErrObj.Source <> gsSILENT Then
            Dim sMsg As String: sMsg = ErrObj.Description
            If ErrObj.Source <> gsNO_DEBUG And ErrObj.Source <> gsUSER_MESSAGE Then sMsg = "Unexpected VBA error in workbook '" & Wbk.Name & "', module '" & ssModule & "', call '" & ssSource & "':" & vbCrLf & vbCrLf & sMsg
            MsgBox sMsg, vbOKOnly + IIf(ErrObj.Source = gsUSER_MESSAGE, vbInformation, vbCritical), gsAPP_NAME
        End If
    ElseIf bRethrowError Then
        'Rethrow the error to the next level up if bRethrowError is True (by Default).
        'Otherwise, do nothing as the calling function must be having special logic for handling errors.
        Err.Raise ErrObj.Number, ErrObj.Source, ErrObj.Description
    End If
End Function

Führen Sie im Sofortfenster Folgendes aus, um sich in den Debug- Modus zu versetzen :

SetDebugMode True
igorsp7
quelle
2

Vorsicht vor der Elefantenfalle:

Ich habe dies in dieser Diskussion nicht erwähnt. [Zugriff 2010]

Wie ACCESS / VBA mit Fehlern in CLASS-Objekten umgeht, wird durch eine konfigurierbare Option bestimmt:

VBA-Code-Editor> Extras> Optionen> Allgemein> Fehlerbehebung:

Geben Sie hier die Bildbeschreibung ein

JoeRobbins
quelle
1

Meine persönliche Meinung zu einer Aussage, die früher in diesem Thread gemacht wurde:

Und nur zum Spaß:

On Error Resume Next ist der inkarnierte Teufel und sollte vermieden werden, da er Fehler stillschweigend verbirgt.

Ich verwende die On Error Resume Nexton-Prozeduren, bei denen ich nicht möchte, dass ein Fehler meine Arbeit beendet, und bei denen eine Anweisung nicht vom Ergebnis der vorherigen Anweisungen abhängt.

Wenn ich das mache, füge ich eine globale Variable hinzu debugModeOnund setze sie auf True. Dann benutze ich es so:

If not debugModeOn Then On Error Resume Next

Wenn ich meine Arbeit liefere, setze ich die Variable auf false, wodurch die Fehler nur dem Benutzer ausgeblendet und während des Tests angezeigt werden.

Verwenden Sie es auch, wenn Sie etwas tun, das möglicherweise fehlschlägt, z. B. den DataBodyRange eines ListObject aufrufen, das möglicherweise leer ist:

On Error Resume Next
Sheet1.ListObjects(1).DataBodyRange.Delete
On Error Goto 0

Anstatt:

If Sheet1.ListObjects(1).ListRows.Count > 0 Then 
    Sheet1.ListObjects(1).DataBodyRange.Delete
End If

Oder die Existenz eines Artikels in einer Sammlung überprüfen:

On Error Resume Next
Err.Clear
Set auxiliarVar = collection(key)

' Check existence (if you try to retrieve a nonexistant key you get error number 5)
exists = (Err.Number <> 5)
Jordi
quelle
> If not debugModeOn Then On Error Resume NextIn diesem Fall ist es besser, die bedingte Kompilierung wie zu verwenden #If Hide_Errors > 0 Then On Error Resume Nextund Hide_Errorsin den VBA-Projekteigenschaften Conditional Complication Argumentsentsprechend festzulegen .
Aleksey F.