Globale Fehlerbehandlung realisieren

By , 16. Oktober 2008

Die bisherige Vorgehensweise eine Fehlerbehandlung zu realisieren war, einen Error Handler in einer Prozedur einzufügen und dann entweder per MsgBox eine Meldung ausgeben oder eine Funktion aufrufen die den Fehler entsprechend behandelt. Das könnte z.B. so aussehen:

Sub MeineProzedur()
    On Error goto Fehlerbehandlung
    'Programmcode...

Exit_Here:
    Exit sub

Fehlerbehandlung:
    Msgbox Err.description
    Resume Exit_Here
End sub

Der Entwickler wünscht sich natürlich, dass diese Routine automatisch und an zentraler Stelle implementiert wäre, und er nicht in jede Prozedur eine Fehlerbehandlung einbauen müsste. Das war bislang leider nicht möglich – jetzt bietet die Firma iTech Masters (www.everyaccess.com) eine entsprechende Software an, die ich hier vorstelle. Das Produkt steht nach der Installation als AddIn in der VBA IDE zur Verfügung. Das AddIn Menü sieht wie folgt aus:

AddIn Menü

Das Menü zeigt die beiden verschiedenen Modis an:
- Setup installation-free DLL support
- Setup normal COM library DLL support

Man kann entweder die COM Bibliothek als Verweis einbinden, oder ganz ohne einen zusätzlichen Verweis auskommen. Dann wird bei der ersten Methode entsprechende Klassenmodule automatisch in das Projekt eingefügt. Die DLL selbst braucht nicht zu registriert zu werden, solange diese im selben Verzeichnis wie das Projekt liegt. Und die zweite Methode finde ich einfach genial. zusätzliche Verweise sorgen oft für Probleme wenn ein Projekt ausgeliefert wird.

Implementierung

Methode installation-free DLL support:
Tastenkombination ALT + F11 drücken um in die VBA IDE zu gelangen. AddIn Menü öffnen und auf “Setup installation-free DLL support” klicken. Es werden 4 Klassenmodule in das Projekt eingefügt, wie man im Projektexplorer sieht.
Als nächstes ein neues Modul namens z.B. modErrorHandler erstellen. Darin kopiert ihr folgende Funktion:

Public Function EnableErrorHandler(GlobalErrorHandlerMode As Long)
    Dim strGlobalErrorHandlerProcName As String
    If GlobalErrorHandlerMode = 1 Then
        strGlobalErrorHandlerProcName = "MyGlobalErrorHandler_Release"
        Call SetupErrorDialog_Release
    End If
    
    If ErrEx.EnableGlobalErrorHandler(Access.Application, strGlobalErrorHandlerProcName) = False Then
        MsgBox "EnableErrorHandler() failed.  Failed to activate the global error handler."
    End If
End Function

Der Parameter GlobalErrorHandlerMode hat 4 verschiedene Werte:
1: Fehlerausgabe im Vista-Style “Kunden”-Modus
2: Fehlerausgabe im Vista-Style “Entwickler”-Modus
3: Fehlerausgabe im Access-Style “Kunden”-Modus
4: Fehlerausgabe im Access-Style “Entwickler”-Modus

Der Unterschied zwischen Kunden- und Entwickler-Modus liegt in den Möglichkeiten wie man auf das Auftreten eines Fehlers reagieren kann. Beim Kunden-Modus kann der Fehler per E-Mail dem Entwickler zugesendet werden, im Entwickler-Modus dageben hat man die Möglichkeiten:
- Call Stack (zuletzt aufgerufene Funktionen) einzusehen
- den Fehler im Internet zu suchen
(es wird automatisch eine Google-Anfrage mit bestimmten Einstellungen gestartet)
- die gesetzte Variablen mit ihren Inhalten anzusehen
- per Klick in den Quellcode an die fehlerhafte Stelle zu springen
- den Fehler zu ignorieren

Das sind genau die Features die ich mir als Entwickler wünsche.

Um die globalen Fehlerbehandlung zu aktivieren, müsst ihr ein Makro erstellen und als autoexec benennen, falls dieses Makro noch nicht vorhanden. Darin müsst ihr folgendes Einfügen:
AusführenCode und als Code: EnableErrorHandler(Modus)
Ersetzt Modus mit dem gewünschten Modus (1 bis 4).

Für jeden der 4 Modis benötigt ihr eine weitere Prozedur innerhalb des Moduls. In dem Download der kostenlosen Entwicklerversion ist auch eine Beispieldatenbank enthalten, die alles gut beschreibt. Ich möchte mich hier nur auf den 1. Modus beschränken.

Fügt also in das Modul folgende Funktion für den Kunden-Modus im Vista-Style ein:

Public Sub SetupErrorDialog_Release()
    With ErrEx.DialogOptions
        .DebugButtonEnabled = False
        .IgnoreAndContinueButtonEnabled = False
        .EndButtonText = "Close"
        .EndButtonEnabled = True
        .CallStackVisible = False
        .ClearCustomButtons
        .AddCustomButton "Send Error Log to " & CompanyName, "OnSendErrorLog"
        .WindowTitleText = ApplicationName & " - runtime error"
        .WindowFooterText = "For support, please contact " & CompanySupportPhone
        .VariablesButtonEnabled = False
    End With
End Sub

Hier könnt ihr die Befehlsschaltflächen der Fehlerausgabe entsprechend einstellen. Man kann Debug-Button, ignorieren und weiter-Button und einen letzten, benutzerdefinerten Button einfügen. Konstanten wie CompanyName oder ApplicationName sind im Deklarationsteil des Moduls zu definieren:

Public Const ApplicationName As String = "Anwendungsname"
Public Const CompanyName As String = "Firmenname"
Public Const CompanySupportEmail As String = "support@eure_webseite.de"
Public Const CompanySupportPhone As String = "+49 999 123456"

Damit die Fehler entsprechend ausgewertet werden können, bedarf es einer weiteren Funktion – richtig, für jeden der 4 Modis eine – die einerseits für das Logging in einer Tabelle, und andererseits für die Ausgabe der Fehlermeldung zuständig ist. Wir betrachten weiterhin nur den 1. Modus.

Fügt folgende Funktion in das Modul ein:

Public Sub MyGlobalErrorHandler_Release()
    Select Case ErrEx.State
        Case OnErrorGoto0
            LogErrorToTable
            ErrEx.State = ErrEx.ShowErrorDialog
        Case OnErrorGotoLabel
            ' keine Aktion, lokale Fehlerbehandlung
        Case OnErrorResumeNext
            ' keine Aktion bei Resume Next
        Case CalledByLocalHandler
            ' Aufruf durch lokale Fehlerbehandlung
            LogErrorToTable
            ErrEx.State = ErrEx.ShowErrorDialog
            ErrEx.State = CalledByLocalHandler
    End Select
End Sub

ToDo Strings

ErrEx ist ein Objekt eines Klassenmoduls, auf dessen Methoden zugegriffen wird.
Diese Methoden stehen dem Entwickler auch zur Verfügung, z.B. bei benutzerdefinierte Buttons eine eigene Prozedur auszuführen. Z.B. könnte man bei einem Fehler per Klick sogenannte ToDo’s in den Code einfügen, die man mit dem ToDo-Finder von Thomas Möller (www.team-moeller.de) einfach managen kann. Es stehen dem Entwickler folgende Methoden zur Verfügung:

  • ErrEx.Number
  • ErrEx.Description
  • ErrEx.CallStack.FirstLevel
  • ErrEx.CallStack.ProjectName
  • ErrEx.CallStack.ModuleName
  • ErrEx.CallStack.ProcedureName
  • ErrEx.CallStack.lineNumber
  • ErrEx.CallStack.LineCode
  • ErrEx.CallStack.VariablesInspector.DumpAll

Damit steht dem Entwickler sämtliche relevanten Informationen zur Verfügung, um z.B. an der Stelle ErrEx.CallStack.lineNumber ein ToDo abzusetzen und Modulname, Prozedurname uns die Fehlerbeschreibung einzufügen. Der letzte Punkt der Liste ist übrigends die Liste der gesetzten Variablen mit ihren Werten.

Und so könnt ihr eine ToDo Information in den Code einfügen lassen:
Fügt zuerst in das Modul für die Fehlerbehandlung folgenden Code.

Public Sub InsertToDo()
    Dim mdl As Module
    Dim A1 As Long, B1 As Long, A2 As Long, B2 As Long
    Dim strText As String
    
    Set mdl = Modules(ErrEx.CallStack.ModuleName)
    strText = "'ToDo: Nummer: " & ErrEx.Number & ", Fehler: " & ErrEx.Description
    mdl.Find ErrEx.CallStack.ProcedureName, A1, B1, A2, B2
    mdl.InsertLines A1 + 1, strText
    Set mdl = Nothing
End Sub

Danach müsst ihr den benutzerdefinierten Button in den Dialog einfügen. Dazu fügt folgende Zeile in die beiden Prozeduren SetupErrorDialog_Release und SetupErrorDialog_Developer ein:

.AddCustomButton "Insert ToDo String", "InsertToDo"

Fehlerlogging

Jetzt brauchen wir noch die Funktion um das Logging zu realisieren:

Public Sub LogErrorToTable()
    ' Hier kann man obige Methoden einsetzen und per Recordset in eine Tabelle schreiben.
    ' Zum Testen verzichten wir auf das Logging.
    ' Wie das Logging funktioniert sieht ihr in der Beispiel Datenbank Sample.mdb 
    ' die dem Produkt beiliegt
End Sub

Testen

Jetzt haben wir die globale Fehlerbehandlung fertiggestellt, aktiviert und “scharf” gestellt. Kopiert jetzt die DLL VBAGlobalErrorHandler.dll die ihr im Programm-Ordner findet, in das Verzeichnis wo euer Projekt liegt. Jetzt sollten wir sie mal testen ob es überhaupt funktioniert.

Schreibt dazu folgende Funktionen in einem Test-Modul:
Überlauf-Test:

Sub ErrTest1()
    Dim i As Integer
    i = 100000
End Sub

Access Objekte Test

Sub ErrTest2()
    Dim frm1 As String
    frm1 = "ABC"
    DoCmd.openForm frm1
End sub

Recordset-Test

Sub ErrTest3()
    Dim db AS DAO.Database
    Dim rs As DAO.Recordset
    set db = Currentdb
    set rs = db.openRecordset("Select IDFeld From TabelleA", dbopenDynaset)
    rs.close
End Sub

Doppelklick auf das autoexec Makro aktiviert das Fehlerhandling. Markiert jeweils den Prozedurnamen ErrTest1 bis ErrTest3 in der VBA IDE, und klickt in der Menüleiste auf Ausführen.
Hab ihr nur die kostenlose Developer Version zum Testen, entfernt die eingefügten Klassenmodule und klickt im AddIn Menü die Option “Setup normal COM Library DLL support”, welche euch den Verweis auf die COM-Bibliothek einfügt. Jetzt aber könnt ihr Testen. Erscheint dabei eine Access-Fehlermeldung, müsst ihr das autoexec Makro nochmals ausführen.

Die Fehlermeldung beim 3. Test sieht dann sinngemäß so aus:

Ausgabe der Fehlermeldung

Ausgabe der Fehlermeldung

Bei mir haben alle 3 Tests einwandfrei geklappt. Ich bin auf jedenfall mit dem Produkt sehr zufrieden, und werde das bei meinen Kundenprojekten einsetzen.

Es gäbe noch viel über dieses Tool zu berichten, z.B. dass es automatisch die Zeilennummern einblenden kann, oder dass es den Fehlerort zeilengenau ermittelt, ohne dass man extra Zeilennummern eintragen muss etc. Dieser Artikel kann auch nur auf Teilaspekte eingehen, der gesteckte Rahmen würde sonst gesprengt werden. Es ist auch nicht als Ersatz für die Anleitung und die Beispiel-Datenbank gedacht gewesen.

Fazit

Das Tool “SimplyVBA Global Error Handler” ist ein wirklich mächtiges Werkzeug, das dem Entwickler wertvolle Dienste liefert bei der Entwanzung seiner Projekte. Allein durch die eingesparte Zeit bei der Fehlersuche lohnt sich der Kauf schon alle mal.
Die kostenlose Entwickler-Version ist nicht dafür gedacht, in produktiven Anwendungen eingesetzt zu werden. Dann benötigt ihr die 50 User Lizenz für 65,- Euro, bzw. 130,- Euro für unlimitierte User Anzahl.
Ihr könnt ruhig zuerst die günstigere 50er Lizenz erwerben, nach Aussage von Wayne Phillips kann man zum Differenzbetrag auf die Unlimitierte Version upgraden.

Infos zum Produkt erhaltet ihr hier:
http://www.everythingaccess.com/simplyvba-global-error-handler.htm

AV 2008

2 Responses to “Globale Fehlerbehandlung realisieren”

  1. Andreas Vogt sagt:

    Hallo Klaus,
    da irrst du dich aber. MZTools fügt per Mausklick lediglich einen Errorhandler in jede Prozedur ein. Das ist das genaue Gegenteil.
    Siehe auch hier: http://www.mztools.com/v3/features.aspx#CodeFaster

    Aber das soll nicht die Leistung von MZTools schmälern, es ist eine verdammt gute Tool-Sammlung.

    Gruß Andreas Vogt

  2. Klaus Oberdalhoff sagt:

    Hallo,

    is ja nett, aber das für VBA kostenfreie Tool MZTools kann das ebenfalls und noch VIEL mehr

    http://www.mztools.com/v3/download.aspx

    mfg

    Klaus Oberdalhoff

Leave a Reply

*

OfficeFolders theme by Themocracy