Home > Artikel > Ausgabe 3/2013 > Debugging im VBA-Editor, Teil 2

Debugging im VBA-Editor, Teil 2

  PDF ansehen

  Download PDF

Nachdem Sie im ersten Teil dieser Artikelreihe einige codebasierten Debugging-Techniken kennengelernt haben, schauen wir uns in diesem Teil weitere VBA-gesteuerte Features an. Außerdem werfen wir einen Blick auf die Tools, die der VBA-Editor uns zum Debuggen bietet. Dazu gehören beispielsweise das Lokalfenster und die Überwachungen.

Anhalten bei bestimmtem Wert

Wenn Sie eine Stelle im Code zur Laufzeit untersuchen möchten, fügen Sie dort entweder einen Haltepunkt oder die Stop-Anweisung ein. Beides hält den Code bei jedem Erreichen der entsprechenden Stelle an.

Manchmal wird die betroffene Codestelle jedoch sehr oft durchlaufen, sodass der Code entsprechend oft angehalten und beispielsweise die Variablen untersucht werden müssen. In vielen Fällen wissen Sie jedoch, dass ein Problem nur unter bestimmten Bedingungen auftaucht. So könnte es sein, dass Sie in einer Schleife alle Datensätze der Tabelle tblArtikel durchlaufen, aber schon wissen, dass ein Problem nur bei einem bestimmten Datensatz auftaucht.

Wenn Sie wissen, dass ein Problem immer in Zusammenhang mit dem Datensatz mit dem Wert 20 im Feld ArtikelID auftaucht, können Sie gezielt einen Haltepunkt setzen. Damit dieser auch nur für den betroffenen Datensatz erreicht wird, fassen Sie diesen in eine entsprechende If...Then-Bedingung ein. Dies sieht beispielsweise wie in Bild 1 aus, wobei die Bedingung rst!ArtikelID = 20 lautet. Nur wenn diese Bedingung erfüllt ist, wird die innerhalb der If...Then-Bedingung enthaltene und mit einem Haltepunkt versehene Anweisung erreicht. Nun können Sie beispielsweise weitere Werte des aktuellen Datensatzes im Direktfenster ausgeben – etwa so:

Anhalten des Codes bei Erreichen eines bestimmten Wertes

Bild 1: Anhalten des Codes bei Erreichen eines bestimmten Wertes

Debug.Print rst!Artikelbestand

Haltepunkt per Assert

Die Debug-Klasse bietet neben der Print-Methode noch eine weitere, relativ unbekannte Methode. Diese heißt Assert und erwartet einen Ausdruck als Parameter, der entweder den Wert True oder False zurückliefert. Wenn der Ausdruck den Wert False zurückgibt, hält die Prozedur automatisch in der Zeile mit der Debug.Assert-Anweisung an.

Im Gegensatz zum vorherigen Beispiel, wo die Debug.Print mit dem Haltepunkt genau beim Eintreten der gewünschten Bedingung ausgelöst wird, müssen Sie bei Debug.Assert also genau dem umgekehrten Fall formulieren.

Auf jeden Fall brauchen Sie mit Debug.Assert nur eine statt drei Zeilen, um den Code beim Eintreten der gewünschten Bedingung anzuhalten:

Public Sub GezielterHaltepunkt_II()

     Dim db As DAO.Database

     Dim rst As DAO.Recordset

     Set db = CurrentDb

     Set rst = db.OpenRecordset( _

         "SELECT * FROM tblArtikel", dbOpenDynaset)

     Do While Not rst.EOF

         Debug.Assert Not (rst!ArtikelID = 20)

         rst.MoveNext

     Loop

End Sub

Sie müssen lediglich beachten, dass Sie den Ausdruck durch Voranstellen des Schlüsselworts Not ins Gegenteil umkehren.

Das Lokal-Fenster

Wenn Sie eine Prozedur per Einzelschritt durchlaufen oder diese an der gewünschten Stelle auf eine der oben angegebenen Arten angehalten haben, wissen Sie in vielen Fällen noch nicht, wonach Sie suchen müssen. Da hilft es oft, sich einfach einmal einen Überblick über die aktuellen Werte aller derzeit verwendeten Variablen zu verschaffen.

Dabei ist das Lokal-Fenster eine große Hilfe. Sie blenden es mit dem Menübefehl Ansicht|Lokal-Fenster ein. Wenn aktuell kein Code durchlaufen wird, ist das Fenster leer. Deshalb schauen wir uns nun an, was das Lokalfenster beim Durchlaufen der Prozedur GezielterHaltepunkt_II tut.

Lassen wir die Prozedur ruhig genau an der mit Debug.Assert festgelegten Position anhalten, indem wir die Einfügemarke an beliebiger Stelle innerhalb der Prozedur platzieren und dann auf F5 drücken.

Wie Bild 2 zeigt, geschieht in der Prozedur doch mehr als erwartet – es gibt mehr Variablen als gedacht. Das liegt daran, dass die beiden in der Prozedur verwendeten Objektvariablen db und rst jeweils auf Objekte verweisen, die eine ganze Reihe von Eigenschaften enthalten. Im Lokal-Fenster können Sie all diese Werte zum aktuellen Zeitpunkt prüfen. Sie brauchen also nicht jede Eigenschaft mit Debug.Print im Direktbereich auszugeben, sondern können die Eigenschaften im Lokal-Fenster verfolgen.

Das Lokal-Fenster liefert eine Reihe Informationen.

Bild 2: Das Lokal-Fenster liefert eine Reihe Informationen.

Die Stärke des Lokal-Fensters liegt dabei darin, immer alle aktuell verfügbaren Eigenschaften abzubilden. Der Nachteil ist, dass dies mitunter recht viele werden können – und darunter leidet natürlich die Übersicht.

Bevor wir uns die Alternative anschauen, werfen wir noch einen genaueren Blick auf das Lokal-Fenster. Dieses zeigt im oberen Bereich den Namen der aktuellen Prozedur an sowie das Modul und das Objekt, aus dem die Prozedur stammt.

Darunter folgen die eigentlich interessanten Informationen, aufgeteilt in drei Spalten:

  • Ausdruck: In dieser Spalte finden Sie die Namen von Objekten und ihren Eigenschaften beziehungsweise untergeordneten Auflistungen oder Objekten. Einfachen Variablen etwa vom Typ String oder Long, die keine Objekte sind, werden immer direkt unterhalb des Standard- oder Klassenmoduls angezeigt, in dem sie sich befinden – hier wäre dies mdlDebugging. Ein Objekt wie das Recordset-Objekt rst ist schon recht komplex und enthält nicht nur eigene Eigenschaften, sondern auch noch Verweise auf weitere Objekte, die wiederum Eigenschaften und Objekte enthalten können.
  • Wert: Diese Spalte enthält den aktuellen Wert von Eigenschaften. Das heißt, dass der Wert dieser nächsten Spalte leer ist, wenn die aktuelle Zeile ein Objekt und keine Eigenschaft enthält.
  • Typ: Diese Spalte liefert den Datentyp der in der aktuellen Zeile abgebildeten Eigenschaft beziehungsweise des Objekts.

Die Bezeichnung Lokal ist übrigens wörtlicher zu nehmen als man vielleicht zunächst annimmt: Das Lokal-Fenster zeigt tatsächlich nur die Variablen der aktuellen Routine an. Dies zeigt Bild 3: Dort ruft deklariert und füllt eine erste Prozedur eine Variable und übergibt diese dann an die zweite Prozedur. Dort angelangt, zeigt das Lokal-Fenster auch nur noch den Wert der in der zweiten Prozedur per Parameter gefüllten Variablen an.

Lokal heißt lokal

Bild 3: Lokal heißt lokal

Zusammenfassend lässt sich das Lokal-Fenster praktisch einsetzen, wenn man noch nicht genau weiß, welche Werte es zu beobachten gilt. Andererseits ist die Beobachtung hiermit auf die aktuell ausgeführte Prozedur eingeschränkt.

Überwachungsfenster

Und damit kommen wir zu einem weiteren Werkzeug – dem Überwachungsfenster. Dieses blenden Sie mit dem Menübefehl An­sicht|Über­wachungsfenster ein. Im Gegensatz zum Lokal-Fenster zeigt es, auch während des Ablaufs einer Prozedur, standardmäßig erst einmal gar nichts an. Der Unterschied zum Lokal-Fenster ist, dass Sie zuerst festlegen müssen, welche Objekte oder Ausdrücke im Überwachungsfenster beobachtet werden sollen.

Um dies zu erledigen, bietet das Überwachungsfenster den Kontextmenüeintrag Überwachung hinzufügen... an (siehe Bild 4).

Hinzufügen einer Überwachung

Bild 4: Hinzufügen einer Überwachung

Hier können Sie sowohl alle als Variable deklarierten Objekte angeben als auch beliebige weitere Ausdrücke wie etwa Forms!frmTest.Name. Der wesentliche Unterschied zum Lokal-Fenster ist dabei, dass Sie immer auch die aktuellen Werte von Variablen erhalten, die nicht zur aktuell durchlaufenen Routine gehören (siehe Bild 5).

Definieren des Überwachungsausdrucks

Bild 5: Definieren des Überwachungsausdrucks

Ein passendes Beispiel sind die beiden Prozeduren Lokal_I und Lokal_II, die Sie bereits in Zusammenhang mit dem Lokal-Fenster kennengelernt haben.

In Bild 6 haben wir zwei Überwachungsausdrücke zum Überwachungsfenster hinzugefügt – die Variable strTest_I der Prozedur Lokal_I und die Variable strTest_II der Prozedur Lokal_II. Beim Durchlaufen der beiden Prozeduren füllt das Überwachungsfenster zunächst die Variable strTest_I. Beim Eintreten in die Prozedur Lokal_II wird dann auch strTest_II gefüllt, strTest_I bleibt erhalten.

Überwachungsausdrücke können sich auch auf nicht aktive Prozeduren beziehen.

Bild 6: Überwachungsausdrücke können sich auch auf nicht aktive Prozeduren beziehen.

Da der Parameter strTest_II nicht mit dem Schlüsselwort ByVal versehen haben, wird der Wert der übergebenen Variablen strTest_I bei Änderungen von strTest_II ebenfalls geändert. Auch solche Änderungen erfasst das Überwachungsfenster.

Anhalten per Überwachungsfenster

Beim Anlegen eines Überwachungsausdrucks können Sie auch festlegen, ob die aktuelle Prozedur beim Erreichen eines bestimmten Wertes für eine Variable angehalten werden soll – Sie können damit also prinzipiell die Debug.Assert-Methode ersetzen.

Um eine solche Überwachung zu erstellen, legen Sie wiederum eine neue Überwachung mit dem entsprechenden Kontextmenüeintrag des Überwachungsfensters an. Geben Sie den Ausdruck in das Feld Ausdruck ein, in diesem Fall den Folgenden:

rst!ArtikelID = 20

Wählen Sie unten die Option Unterbrechen, wenn der Wert True ist aus (siehe Bild 7). Ein solcher Überwachungsausdruck wird im Überwachungsfenster mit einem anderen Symbol dargestellt.

Überwachungsausdruck zum Anhalten bei einer bestimmten Bedingung

Bild 7: Überwachungsausdruck zum Anhalten bei einer bestimmten Bedingung

Wenn Sie die Prozedur nun starten, hält die Überwachung diese genau in der Zeile nach rst.MoveNext an, also wenn der Datensatzzeiger auf den Datensatz mit dem Wert 20 im Feld ArtikelID verschoben wurde.

Bei jeder Änderung anhalten

Sie können auch festlegen, dass die Anwendung bei jeder Änderung des Wertes eines Ausdrucks angehalten wird. Dazu aktivieren Sie die dritte Option Unterbrechen, wenn Wert geändert wurde.

Dies ist besonders wichtig, wenn ein Ausdruck irgendwann einen Wert enthält, den Sie sich nicht erklären können – dann können Sie zumindest schrittweise prüfen, um die einzelnen Änderungen des Wertes zu analysieren.

Überwachung einfach hinzufügen

Es gibt eine sehr einfache Art, einen Überwachungsausdruck zum Überwachungsfenster hinzuzufügen. Dazu markieren Sie einfach im VBA-Editor den kompletten Ausdruck, der überwacht werden soll, und wählen dann den Kontextmenüeintrag Überwachung hinzufügen... aus.

Der VBA-Editor trägt die relevanten Daten dann gleich in das Fenster zum Hinzufügen einer Überwachung ein (siehe Bild 8).

Überwachungsausdruck einfach hinzufügen

Bild 8: Überwachungsausdruck einfach hinzufügen

Eine weitere Möglichkeit ist es, zunächst den aktuellen Wert des im VBA-Editor markierten Ausdrucks mit dem Menüeintrag Debuggen|Aktuellen Wert anzeigen... anzuzeigen und im dann erscheinenden Dialog die Schaltfläche Hinzufügen anzuklicken (siehe Bild 9).

Ausdruck erst ermitteln, dann zur Überwachung hinzufügen

Bild 9: Ausdruck erst ermitteln, dann zur Überwachung hinzufügen

Nur debuggen, wenn ...

Mit den Optionen im Bereich Unterbrechen bei Fehlern auf der Seite Allgemein des Optionen-Dialogs (Extras|Optionen) legen Sie fest, wann der Debugger beim Auftreten eines Fehlers einschreiten soll (siehe Bild 10).

Optionen für das Debugging

Bild 10: Optionen für das Debugging

Normalerweise hat diese Option den Wert Bei nicht verarbeiteten Fehlern. Dann läuft der Code einfach weiter, wenn die Fehlerbehandlung beispielsweise mit der folgenden Zeile deaktiviert wurde:

On Error Resume Next

Wenn der Debugger auch in diesem Fall anspringen soll, stellen Sie die Option einfach auf den Wert Bei jedem Fehler ein.

Zusammenfassung und Ausblick

Der VBA-Editor ist zwar nicht die modernste Entwicklungsumgebung und wird tendenziell nicht mehr erweitert, aber die vorhandenen Mittel erfüllen ihren Zweck.