Fehlerbehandlung per VBA hinzufügen

Eine Fehlerbehandlung ist Teil einer professionellen Datenbankanwendung auf Basis von Microsoft Access. Sobald wir eine Datenbank an einen Kunden oder Mitarbeiter weitergeben, also an einen anderen Benutzer als uns selbst, ist dies praktisch ein Pflichtprogramm. Die Fehlerbehandlung soll den Benutzer über einen Fehler informieren und diesem die Möglichkeit geben, dem Entwickler Informationen über den Fehler zukommen zu lassen. In diesem Beitrag wollen wir die Hauptarbeit bei der Implementierung einer Fehlerbehandlung erledigen. Dazu wollen wir eine Prozedur schreiben, die beliebige Routinen, also Sub-, Function- und Property-Prozeduren, mit einer einfachen Fehlerbehandlung ausstattet – und überdies noch mit einer Zeilennummerierung. Diese ist wichtig, wenn wir schnell herausfinden wollen, an welcher Stelle ein Fehler aufgetreten ist. Zusammen mit dem Namen des Moduls, dem Namen der Prozedur, der Fehlernummer und der Fehlerbeschreibung erhalten wir so Informationen, die in der Regel zum Aufdecken des Fehlers führen.

Wir wollen in diesem Beitrag eine minimale Fehlerbehandlung verwenden, die nur die nötigsten Informationen aufnimmt. Dazu gehören die folgenden:

  • Fehlernummer
  • Fehlerbeschreibung
  • Zeile, in welcher der Fehler aufgetreten ist
  • Prozedur, in welcher der Fehler aufgetreten ist
  • Modul, in dem der Fehler aufgetreten ist

Woher bekommen wir diese Informationen?

Die Fehlernummer und die Fehlerbeschreibung erhalten wir per VBA grundsätzlich nur, wenn wir die eingebaute Fehlerbehandlung von VBA ausgeschaltet haben. Das erledigen wir mit einer der folgenden Anweisungen:

On Error Resume Next
On Error GoTo Sprungmarke

Dabei ist Sprungmarke eine Zeile, die den Namen der Sprungmarke und einen Doppelpunkt enthält, zum Beispiel:

Errorhandling:

Wenn wir die eingebaute Fehlerbehandlung wieder einschalten wollen, können wir dies mit der folgenden Anweisung erledigen:

On Error GoTo 0

Während die eingebaute Fehlerbehandlung ausgeschaltet ist, werden Fehler entweder einfach ignoriert (On Error Resume Next) oder der Code wird an der angegebenen Sprungmarke fortgesetzt, wenn eine angegeben wurde (On Error Goto Errorhandler).

Fehlernummer und Fehlerbeschreibung ermitteln

In jedem Fall können wir in den darauffolgenden Zeilen die Eigenschaften des Err-Objekts auslesen. Das können wir zwar immer, aber wenn kein unbehandelter Fehler aufgetreten ist, liefert dies auch keine Fehlerinformationen.

Gehen wir jedoch davon aus, dass wir die Informationen nach Auftreten eines Fehlers abfragen, können wir dem Err-Objekt die folgenden Informationen entnehmen:

  • Err.Number: Liefert die Fehlernummer, zum Beispiel 11.
  • Err.Description: Liefert die Fehlerbeschreibung, zum Beispiel Division durch Null.

Name des VBA-Projekts ermitteln

Wir könnten mit der Err-Eigenschaft Err.Source sogar noch den Namen des VBA-Projekts ermitteln, in dem der Fehler ausgelöst wurde. Dies ist jedoch nicht unbedingt notwendig, da sich die Fehlerbehandlung meist auf das gleiche VBA-Projekt bezieht, in dem sich diese befindet.

Zeilennummer ermitteln

Die Nummer der Zeile, in welcher der Fehler aufgetreten ist, finden wir offiziell gar nicht. Allerdings gibt es eine nicht dokumentierte Funktion namens Erl, die uns im Falle eines Fehlers die Nummer der Zeile mit der auslösenden Anweisung liefert. Dies geschieht jedoch nur, wenn es auch eine Zeilennummerierung gibt. Diese müssen wir selbst hinzufügen, es gibt keine eingebaute Funktion, um dies einfach zu erledigen.

Wie wir die Zeilennummer hinzufügen, haben wir deshalb ausführlich beschrieben, und zwar im Beitrag Zeilennummern per VBA hinzufügen (www.access-im-unternehmen.de/1515). Hier finden Sie sogar Prozeduren, mit denen Sie die Zeilennummern für eine Prozedur, alle Prozeduren eines Moduls und sogar für alle Module in einem VBA-Projekt per Mausklick anlegen können.

Prozedurname und Modulname ermitteln

Den Prozedurnamen und den Modulnamen können wir ebenfalls nicht automatisch ermitteln. Es ist jedoch dennoch sinnvoll, diesen in einer Fehlerbehandlung auszugeben – dabei spielt es keine Rolle, ob die Fehlerbehandlung nur eine Meldung anzeigt, die Fehlerinformationen in eine Tabelle schreibt oder direkt eine E-Mail an den Entwickler der Anwendung schickt.

In jedem Fall werden wir in einer Fehlerbehandlung landen, die sich innerhalb der Prozedur befindet, in welcher der Fehler ausgelöst wurde. Diese befindet sich in der Regel hinter einer Sprungmarke am Ende der jeweiligen Prozedur. Und wenn wir ohnehin für jede Prozedur eine eigene Fehlerbehandlung hinzufügen müssen, dann können wir hier auch direkt die Information unterbringen, in welchem Modul und in welcher Prozedur wir uns gerade befinden.

Das gilt auch, wenn sich die Fehlerbehandlungsanweisungen nicht selbst in der Prozedur befinden, sondern in einer eigenen Routine. Dann müssen wir dafür sorgen, dass der Modul- und der Prozedurname zur dortigen Routine gelangen und können diese im Aufruf der fehlerauslösenden Prozedur platzieren.

Das sieht beispielsweise wie folgt aus:

Public Sub Test_WriteError()
10    On Error GoTo Errorhandling
20    Debug.Print 1 / 0
30    Exit Sub
Errorhandling:
     HandleError Err.Number, Err.Description, Erl, _
         "Test_WriteError", "mdlErrors"
End Sub

Die Prozedur hat bereits Zeilennummern und die eingebaute Fehlerbehandlung wird mit On Error Goto Errorhandling deaktiviert. Der Fehler durch die Division durch 0 in Zeile 20 führt somit dazu, dass die Prozedur direkt zur Sprungmarke Errorhandling springt. Hier rufen wir eine Prozedur namens HandleError auf, die unsere Fehlerbehandlungsroutine enthält. Dieser übergeben wir alle Daten, die wir in der Fehlerbehandlungsroutine verarbeiten wollen – die Fehlernummer, die Fehlerbeschreibung, die Zeilennummer, den Modulnamen und den Prozedurnamen. An dieser Stelle wird klar: Wenn wir diese Fehlerbehandlung zu vielen Prozeduren hinzufügen wollen, können wir zwar mit Copy und Paste arbeiten, aber wir müssen dennoch viele Anpassungen vornehmen. In diesem Fall müssen wir jeweils den Modulnamen und den Prozedurnamen anpassen. Beim Modulnamen muss man dies nur einmal pro Modul erledigen und kann die entsprechenden Zeilen dann kopieren und braucht nur noch den Prozedurnamen anzupassen. Viel Aufwand bleibt es dennoch, und es ist auch nicht wenig fehleranfällig.

Fehlerbehandlungsroutine

Die Routine namens HandleError, die wir von allen Prozeduren mit einer Fehlerbehandlung aus aufrufen wollen, finden Sie in Listing 1. In diesem Fall wollen wir aufgetretene Fehler einfach in eine Tabellenamens tblErrors schreiben, die sich in der gleichen Datenbank befindet. Diese enthält Felder für alle erwähnten Fehlerinformationen und zuzüglich noch ein Feld mit Datum und Uhrzeit.

Public Sub HandleError(lngNumber As Long, strMessage As String, lngLine As Long, strProcedure As String, _
         strModule As String)
     Dim db As DAO.Database
     Set db = CurrentDb
     db.Execute "INSERT INTO tblErrors(ErrorNumber, ErrorMessage, ErrorLine, ErrorProcedure, ErrorModule) VALUES(" _
         & lngNumber & ", ''" & Replace(strMessage, "''", "''''") & "'', " & lngLine & ", ''" & strProcedure & "'', ''" _
         & strModule & "'')", dbFailOnError
End Sub

Listing 1: Fehlerbehandlungsroutine

Für dieses legen wir als Standardwert Jetzt() fest, damit wir dieses Feld nicht per Code füllen müssen (siehe Bild 1).

Tabelle zum Speichern der Fehlerinformationen

Bild 1: Tabelle zum Speichern der Fehlerinformationen

Die Fehlerbehandlungsroutine enthält im Wesentlichen eine INSERT INTO-Anweisung, die einen neuen Datensatz in die Tabelle tblErrors schreibt und die mit der Execute-Methode des Database-Objekts ausgeführt wird.

Wenn wir unsere Fehlerbehandlung einige Male mit der obigen Beispielprozedur auslösen, finden wir Einträge wie in Bild 2 in der Tabelle tblErrors vor.

Tabelle zum Speichern der Fehlerinformationen mit einige Fehlern

Bild 2: Tabelle zum Speichern der Fehlerinformationen mit einige Fehlern

Alternativen zum Eintrag in die Fehlertabelle

Wenn Sie in Ihrer Anwendung einmal alle Prozeduren, bei denen es sinnvoll ist (in der Regel alle), mit einer Fehlerbehandlung ausgestattet haben, können Sie die im Falle eines Fehlers durchzuführenden Aktionen einfach ändern. Dazu brauchen Sie nur die Anweisungen in der Prozedur HandleError anzupassen. Der Fantasie sind hier keine Grenzen gesetzt – Sie können die Daten wir hier in eine Tabelle schreiben, eine E-Mail mit Fehlerinformationen an den Entwickler senden, einfach nur eine Fehlermeldung anzeigen oder auch Fehlermeldungen in eine Textdatei außerhalb der Datenbankdatei schreiben.

Sie können auch verschiedene dieser Vorschläge kombinieren. In der Regel ist es immer von Vorteil, wenn man den Benutzer über einen Fehler informiert, damit dieser gegebenenfalls weitere Schritte durchführen kann – wie den Entwickler zu informieren.

Fehlerbehandlung anwendungsweit integrieren

Nun stehen wir nur noch vor einer Fleißaufgabe. Wir müssen die Zeilen, die für die Funktion der Fehlerbehandlung nötig sind, in jede Prozedur eintragen.

Das sind aus der Beispielprozedur von oben alle Anweisungen außer Prozedurkopf, -fuß und der eigentlichen Anweisung:

Public Sub Test_WriteError()
10    On Error GoTo Errorhandling
20    Debug.Print 1 / 0
30    Exit Sub
Errorhandling:
     HandleError Err.Number, Err.Description, Erl, _
         "Test_WriteError", "mdlErrors"
End Sub

Und wenn wir, wie im Beitrag Zeilennummern per VBA hinzufügen (www.access-im-unternehmen.de/1515) beschrieben, auch Zeilennummern automatisiert zu Prozeduren hinzufügen können, warum sollten wir dann nicht automatisch die immer wiederkehrenden Zeilen hinzufügen?

Prozedur zum automatisierten Hinzufügen einer Fehlerbehandlung

Hier verwenden wir die Prozedur AddErrorHandler aus Listing 2. Sie erwartet die folgenden Parameter:

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

den kompletten Artikel im PDF-Format mit Beispieldatenbank

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar