VBA-Code manipulieren mit der CodeModule-Klasse

Wenn Sie sich mit den anderen Beiträgen dieser Reihe bis zum VBComponent-Objekt eines Moduls vorgearbeitet haben, ist es nur noch ein Katzensprung bis zur CodeMod-ule-Klasse. Damit können Sie dann die Inhalte eines VBA-Moduls auslesen und bearbeiten. Dieser Beitrag zeigt, welche Methoden die CodeModule-Klasse bietet und wie Sie diese für die verschiedenen Anwendungszwecke einsetzen können.

Vorbereitung

Um die Elemente der Klasse VBE nutzen zu können, benötigen Sie einen Verweis auf die Bibliothek Microsoft Visual Basic for Applications Extensibility 5.3 Object Library, den Sie im Verweise-Dialog des VBA-Editors hinzufügen können (Menüeintrag Extras|Verweise).

Vorbereitende Beiträge

Wenn Sie erfahren wollen, wie Sie überhaupt bis zu der hier beschriebenen Klasse gelangen, helfen die folgenden Beiträge weiter:

  • VBA-Projekt per VBA referenzieren (www.access-im-unternehmen.de/1337)
  • Zugriff auf den VBA-Editor mit der VBE-Klasse (www.access-im-unternehmen.de/1350)
  • Zugriff auf VBA-Projekte per VBProject (www.access-im-unternehmen.de/1351)
  • Module und Co. im Griff mit VBComponent (www.access-im-unternehmen.de/1352)

Elemente der VBComponent-Klasse

Die CodeModule-Klasse und ihre Eigenschaften, Methoden und Auflistungen können Sie im Objektkatalog im Überblick ansehen, wenn Sie dort nach CodeModule suchen (siehe Bild 1). Hier sehen wir neben den Elementen dieser Klasse auch, dass diese sowohl ein Unterelement von VBComponent als auch von CodePane ist. Als Element von VBComponent können Sie es anlegen, und CodePane ist die Schnittstelle zwischen dem anzeigenden Window-Element im VBA-Editor und dem CodeModule-Objekt, das einige Möglichkeiten für den Zugriff auf den Code über die Benutzeroberfläche ermöglicht.

Die CodeModule-Klasse im Objektkatalog

Bild 1: Die CodeModule-Klasse im Objektkatalog

Die Klasse CodeModule bietet folgende Elemente:

  • AddFromFile: Fügt VBA-Code aus der per Parameter angegebenen Textdatei hinzu.
  • AddFromString: Fügt VBA-Code aus der per Parameter übergebenen Zeichenkette hinzu.
  • CodePane: Liefert einen Verweis auf das CodePane-Element, mit dem Sie speziell Zugriffsmöglichkeiten auf die angezeigte Version des CodeModule-Objekts haben – beispielsweise um Markierungen abzufragen oder zu setzen.
  • CountOfDeclarationLines: Liefert die Anzahl der Zeilen im Deklarationsbereich des Moduls.
  • CountOfLines: Liefert die gesamte Anzahl der Zeilen im Modul.
  • CreateEventProc: Erstellt eine Ereignisprozedur für das mit den beiden Parametern angegebene Ereignis und Objekt.
  • DeleteLines: Löscht die mit dem zweiten Parameter angegebene Anzahl von Zeilen ab der mit dem ersten Parameter angegebenen Zeile.
  • Find: Sucht nach dem mit dem ersten Parameter angegebenen Ausdruck und liefert mit den folgenden Parametern die Position des Fundorts zurück.
  • InsertLines: Fügt ab der mit dem ersten Parameter angegebenen Zeile den mit dem zweiten Parameter angegebenen Text im Modul ein.
  • Lines: Liefert den Inhalt einer oder mehrerer Zeilen, wobei der erste Parameter die Nummer der ersten Zeile und der zweite die Anzahl der Zeilen angibt.
  • Parent: Referenziert das übergeordnete Objekt, in diesem Fall ein Objekt des Typs VBComponent.
  • ProcBodyLine: Liefert die Nummer der Zeile der angegebenen Prozedur mit dem Sub|Function|Property-Schlüsselwort.
  • ProcCountLines: Liefert die Anzahl der Zeilen einer Prozedur.
  • ProcOfLine: Gibt die Prozedur und den Typ der Prozedur für eine bestimmte Zeile zurück.
  • ProcStartLine: Liefert die Nummer der ersten Zeile nach der letzten Zeile der vorherigen Prozedur oder des allgemeinen Deklarationsteils.
  • ReplaceLine: Ersetzt die Zeile mit der im ersten Parameter angegebenen Nummer durch den mit dem zweiten Parameter angegebenen Text.
  • VBE: Referenziert das VBA-Editor-Objekt des CodeModule-Objekts.

Das CodeModule-Objekt referenzieren

Um das CodeModule-Objekt eines Moduls zu referenzieren, benötigen Sie zuerst Zugriff auf das entsprechende VBComponent-Element. Meist wollen Sie direkt auf ein bestimmtes Objekt zugreifen, dessen Namen Sie kennen. Dann können Sie dieses über die VBComponents-Auflistung des VBProject-Elements referenzieren.

Das VBComponent-Element bietet dann über die CodeModule-Eigenschaft die Möglichkeit des Zugriffs auf das CodeModule-Objekt an. Im folgenden Beispiel referenzieren wir dieses und geben dann die Anzahl der Codezeilen in diesem CodeModule-Objekt aus:

Public Sub CodeModuleReferenzieren()
     Dim objVBProject As VBProject
     Dim objVBComponent As VBComponent
     Dim objCodeModule As CodeModule
     Set objVBProject = VBE.ActiveVBProject
     Set objVBComponent =  objVBProject.VBComponents("mdlVBE")
     Set objCodeModule = objVBComponent.CodeModule
     Debug.Print objCodeModule.CountOfLines
End Sub

Code aus einer Textdatei hinzufügen

Mit der Export-Methode des VBComponent-Objekts können Sie eine Textdatei mit dessen Inhalt exportieren. Diese können Sie beispielsweise mit der AddFromFile-Methode der CodeModule-Klasse wieder einlesen.

Wie das gelingt, zeigen wir in folgendem Beispiel. Hier legen wir ein neues, leeres VBComponent-Objekt an und nutzen dann die AddFromFile-Methode seines CodeModule-Objekts, um den Inhalt des exportierten Moduls in das neue Modul einzulesen:

Public Sub CodeModuleAddFromFile()
     Dim objVBProject As VBProject
     Dim objVBComponent As VBComponent
     Dim objCodeModule As CodeModule
     Set objVBProject = VBE.ActiveVBProject
     Set objVBComponent =  objVBProject.VBComponents.Add(vbext_ct_StdModule)
     Set objCodeModule = objVBComponent.CodeModule
     objCodeModule.AddFromFile CurrentProject.Path  & "\Neu.txt"
End Sub

Zu beachten ist hier, dass bei exportierten Modulen auch die Attribute mit exportiert werden, also zum Beispiel der Modulname.

Dieser wird beim Importieren in ein vorhandenes Modul dann für das übergeordnete VBComponent-Objekt verwendet.

Sie können mit AddFromFile jedoch auch Textdateien mit dem reinen Inhalt des Moduls laden.

Code per Zeichenkette hinzufügen

Gegebenenfalls stellen Sie den Code für ein Modul in einer Textvariablen zusammen oder lesen diesen von anderer Stelle ein, beispielsweise aus einem Feld einer Datenbanktabelle. Wenn Sie den Inhalt der Variablen schnell in ein neues, leeres Modul einfügen möchten, bietet sich die Methode AddFromString an. Diese schreibt den Code direkt in das CodeModule-Objekt.

Im folgenden Beispiel stellen wir den einzufügenden Code zuvor in der Variablen strCode zusammen und weisen diesen dann mit AddFromString dem CodeModule-Objekt zu:

Public Sub CodeModuleAddFromString()
     Dim objVBProject As VBProject
     Dim objVBComponent As VBComponent
     Dim objCodeModule As CodeModule
     Dim strCode As String
     Set objVBProject = VBE.ActiveVBProject
     Set objVBComponent = objVBProject.VBComponents. Add(vbext_ct_StdModule)
     objVBComponent.Name = "mdlAddFromString"
     Set objCodeModule = objVBComponent.CodeModule
     strCode = "Dim strTest As String" & vbCrLf & vbCrLf
     strCode = strCode & "Public Sub Test()" & vbCrLf
     strCode = strCode & "    Debug.Print ""Test"""  & vbCrLf
     strCode = strCode & "End Sub"
     objCodeModule.AddFromString strCode
End Sub

Das Ergebnis finden Sie in Bild 2.

Per AddFromString initial hinzugefügter Code

Bild 2: Per AddFromString initial hinzugefügter Code

Sie können AddFromString auch nutzen, um Code in ein Modul einzufügen, das bereits Code enthält. Der neu einzufügende Code landet dann genau hinter der letzten Deklarationszeile im Modul.

Das macht Sinn, denn wenn der einzufügende Code auch im oberen Bereich Deklarationszeilen und im unteren Routinen enthält, dann gibt es weiterhin eine Trennung zwischen den Deklarationen im oberen Bereich und der Programmlogik im unteren Bereich. Die folgende Prozedur fügt eine Deklarationszeile zum bestehenden Code aus dem vorherigen Beispiel hinzu:

Public Sub CodeModuleAddMoreFromString()
     Dim objVBProject As VBProject
     Dim objCodeModule As CodeModule
     Dim strCode As String
     Set objVBProject = VBE.ActiveVBProject
     Set objCodeModule = objVBProject.VBComponents( "mdlAddFromString").CodeModule
     strCode = "Dim strTest2 As String"
     objCodeModule.AddFromString strCode
End Sub

Dieser wird dann im Modul wie in Bild 3 eingefügt.

Per AddFromString nachträglich hinzugefügter Code

Bild 3: Per AddFromString nachträglich hinzugefügter Code

Das CodePane-Objekt eines Moduls referenzieren

Im Beitrag Zugriff auf den VBA-Editor mit der VBE-Klasse (www.access-im-unternehmen.de/1350) haben wir den Unterschied und die Zusammenhänge zwischen VBComponent, Window und CodePane erläutert. Das CodePane ist das Element, in dem das CodeModule-Objekt im Window-Objekt angezeigt wird.

Deshalb können wir vom CodeModule-Element über die Eigenschaft CodePane auch auf das betroffene Code-Pane-Element zugreifen. Das CodePane-Element referenzieren wir dabei wie folgt:

Public Sub CodePaneReferenzieren()
     Dim objVBProject As VBProject
     Dim objCodeModule As CodeModule
     Dim objCodePane As CodePane
     Set objVBProject = VBE.ActiveVBProject
     Set objCodeModule = objVBProject.VBComponents( "mdlCodeModule").CodeModule
     Set objCodePane = objCodeModule.CodePane
     ''... Dinge mit dem CodePane erledigen
End Sub

Welche Möglichkeiten die CodePane-Klasse bietet, lesen Sie im Beitrag Auf VBA-Code zugreifen per CodePane (www.access-im-unternehmen.de/1354).

Schneller Zugriff auf das CodeModule per CodePane

Das CodePane-Objekt hat eine Eigenart, die wir uns in den folgenden Beispielen zunutze machen wollen: Sie können das aktive CodePane-Objekt, also den Container im aktuell aktiven VBA-Fenster mit dem CodeModule-Objekt, auch direkt mit der Eigenschaft ActiveCodePane der übergeordneten VBE-Klasse referenzieren.

Zeilen zählen im Modul

Es gibt einige Eigenschaften, mit denen Sie verschiedene Zeilenanzahlen ermitteln können.

Diese schauen wir uns in den nächsten Abschnitten an.

Anzahl aller Zeilen im Modul

Am einfachsten ist das Zählen aller Zeilen. Dies erledigen wir mit der Eigenschaft CountOfLines. Diese liefert die Anzahl der Zeilen von der ersten bis zur letzten Zeile des Moduls.

Wir gehen davon aus, dass das zu untersuchende Modul geöffnet ist und dass das entsprechende VBA-Fenster den Fokus hat.

Dann können wir nämlich ganz einfach wie folgt über den Direktbereich auf zu die untersuchenden Eigenschaften zugreifen – hier auf die Anzahl der Codezeilen:

  VBE.ActiveCodePane.CodeModule.CountOfLines
  9

Die Eigenschaft CountOfLines liefert die Anzahl der Zeilen, wobei auch solche Zeilen ohne Inhalt mitgezählt werden. In Bild 4 ist die Zeile mit dem Kommentar ”09 die letzte Zeile. Wenn wir hinter ”09 noch einmal die Eingabetaste betätigen und somit einen Zeilenumbruch hinzufügen, liefert CountOfLines folglich den Wert 10.

Abfragen von CodeModule-Eigenschaften per Direktbereich

Bild 4: Abfragen von CodeModule-Eigenschaften per Direktbereich

Beispielmodul für die folgenden Beispiele

Damit Sie Beispielmaterial haben, anhand dessen Sie die folgenden Beispiele nachvollziehen können, haben wir das Modul mdlBeispielcode aus Bild 5 zum Projekt hinzugefügt. Mit der CountOfLines-Eigenschaft erhalten Sie für dieses Modul den Wert 28.

Beispielmodul

Bild 5: Beispielmodul

Anzahl der Deklarationszeilen

Die Eigenschaft CountOfDeclarationLines liefert die Anzahl der Zeilen bis zur letzten Deklarationsanweisung im Modul. Da Sie keine Deklarationszeilen hinter der ersten Routine mehr verwenden dürfen, können Sie beide Bereiche somit sehr gut voneinander unterscheiden.

Im Gegensatz zu CountOfLines kümmert sich CountOfDeclarationLines situationsbedingt nicht um nachfolgende Leerzeilen:

  • Wenn nach der letzten Deklarationszeile mindestens eine Sub-, Function– oder Property-Prozedur folgt, dann gibt CountOfDeclarationLines die Anzahl der Zeilen bis zur letzten Deklarationszeile aus.
  • Wenn nach der letzten Deklarationszeile keine Sub-, Function– oder Property-Prozedur folgt, wenn das Modul also nur einen Deklarationsteil enthält, dann liefert CountOfDeclarationsLines die Anzahl der Zeilen bis zur letzten Zeile des Moduls.

Im Fall des Moduls aus dem Beispiel erhalten wir also folgendes Ergebnis:

  VBE.ActiveCodePane.CodeModule.CountOfDeclarationLines
  4

Anzahl der Zeilen einer Prozedur

Wenn Sie die Anzahl der Zeilen einer speziellen Prozedur ermitteln wollen, nutzen Sie die Eigenschaft ProcCountLines. Diese Eigenschaft erwartet zwei Parameter:

  • ProcName: Name der zu untersuchenden Prozedur
  • ProcKind: Art der zu untersuchenden Prozedur. Mögliche Werte: vbext_pk_Get (Property Get-Prozedur), vbext_pk_Let (Property Let-Prozedur), vbext_pk_Proc (Sub– oder Function-Prozedur) oder vbext_pk_Set (Property Set-Prozedur)

Um diese Eigenschaft nutzen zu können, müssen Sie sowohl den Namen als auch den Typ der Prozedur kennen. Ein Beispielaufruf aus dem Direktbereich heraus lautet:

  VBE.ActiveCodePane.CodeModule.ProcCountLines("Testsub", vbext_pk_Proc)
  5 

Warum erscheint hier der Wert 5 Weil sowohl die Kommentarzeile als auch die leeren Zeilen unmittelbar vor der untersuchten Prozedur mitgezählt werden – also alle seit dem allgemeinen Deklarationsteil oder der vorherigen Prozedur inklusive Kommentarzeilen.

Alle Zeilen eines Moduls ausgeben

Wenn Sie eine oder mehrere Zeilen eines Moduls ausgeben wollen, referenzieren Sie als erstes das CodeModule-Objekt. Dann können Sie mit der Lines-Methode gezielt den Inhalt einer oder mehrerer Zeilen gleichzeitig abfragen.

Im ersten Beispiel geben wir für das erste Argument der Lines-Methode den Wert 1 für die erste Zeile und den Wert der Eigenschaft CountOfLines des CodeModule-Objekts für den zweiten Parameter an. Lines sollte hier also alle Zeilen in einem Rutsch liefern:

Public Sub AlleZeilenGleichzeitigAusgeben()
     Dim objCodeModule As CodeModule
     Set objCodeModule = VBE.ActiveVBProject. VBComponents("mdlBeispielcode").CodeModule
     Debug.Print objCodeModule.Lines(1,  objCodeModule.CountOfLines)
End Sub

Das Ergebnis finden Sie in Bild 6.

Ausgabe aller Zeilen

Bild 6: Ausgabe aller Zeilen

Nun wollen wir die Prozedur inklusive Zeilennummern ausgeben. Dazu referenziert die folgende Prozedur das Modul mdlBeispielcode und durchläuft in einer For Next-Schleife die Zahlen von 1 bis zu der mit der Eigenschaft CountOfLines ermittelten Anzahl der Zeilen.

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