Language: Deutsch English















Last Update: 2021 - 01 - 04





Rekursion in VBA - Auflisten der Outlook-Ordnerhierarchie

Von Philipp Stiefel, ursprünglich veröffentlicht 2020-12-06

Zuletzt geändert 2020-12-14


Artikel header image - Karussel-Foto als Allegorie fuer Rekursion

Photo by saskia fairfull on Unsplash

Ich habe gerade eine interessante Frage in einem Microsoft Access-Forum entdeckt, in der jemand fragt, wie die gesamte Microsoft Outlook-Ordnerhierarchie mit VBA aufgelistet werden kann. Diese Frage ist so interessant, dass ich nicht nur kurz im Forum antworte, sondern lieber hier einen längeren Text schreibe.

Die Fragestellung ist nicht wegen des Themas selbst interessant, sondern weil sie mir die Gelegenheit bietet, ein wichtiges Programmierkonzept zu erklären: Rekursion

Rekursion in der Theorie

Rekursion in der Programmierung im Allgemeinen, nicht nur in VBA, ist, wenn sich eine Prozedur oder Funktion selbst aufruft. Dies muss immer mit einer Bedingung verbunden sein, die dazu führt, dass die Prozedur sich nicht mehr selbst aufruft. Andernfalls würde dies früher oder später dazu führen, dass deinem Programm der Stack-Space ausgeht und die Prozedur mit einem Fehler beendet wird.

Symbolisierte Rekursion einer VBA procedure

Ein wichtiger Sachverhalt: Wenn eine Prozedur von sich selbst erneut aufgerufen wird, handelt es sich um eine völlig neue „Instanz“ der Prozedur. Lokale Variablen innerhalb der Prozedur werden neu initialisiert und sind völlig unabhängig von ihrem Pendant in der aufrufenden „Instanz“ derselben Prozedur.

Rekursion ist ein hilfreicher Ansatz, wenn du für jedes Element in einer Elementhierarchie eine Aktion ausführen musst. Es ist nur wenig Code erforderlich, damit Rekursion funktioniert, und dieser Code fühlt sich für mich meist auch recht elegant an.

Beachte jedoch, dass die Rekursion auch Nachteile hat. Die Tatsache, dass alle Argumente und die lokalen Variablen (zumindest ihre Zeiger) auf dem Aufrufstapel (Call Stack) gespeichert sind, kann ziemlich viel Stack-Speicher verbrauchen und führt nach mehreren tausend Aufrufen zu einem Laufzeitfehler 28 - Nicht genügend Stapelspeicher. - Dies sollte eigentlich ein normaler VBA-Laufzeitfehler sein, aber während meiner Tests für diesen Artikel wurde dieser Fehler nicht angezeigt, sondern es passierter ein vollständiger Absturz von VBA und seiner Hostanwendung (ich habe sowohl in Access als auch Excel probiert). In vielen Programmierumgebungen ist dies keine ungewöhnliche Reaktion auf einen Stapelüberlauf (Stack overflow), aber in VBA habe ich das so nicht erwartet.

Ein geringerer Nachteil ist die zusätzliche Ausführungszeit, die für den Kontextwechsel zu einer anderen Prozedur (-„Instanz“) erforderlich ist. Z.B. für das Kopieren der Argumentwerte in den Stack und dem Aufrufen der neuen "Instanz" der Funktion oder Prozedur.

Die meiste, wahrscheinlich sogar alle, mit Rekursion implementierte Logik kannst du auch mit einem iterativen Ansatz implementieren, z. B. mit einer For-Next- oder Do-Until-Schleife in VBA. Das benötigt weniger Speicher und wird wahrscheinlich schneller ausgeführt. Abhängig von der jeweiligen Aufgabe ist der Code für eine iterative Implementierung jedoch oft viel länger, weniger elegant und schwerer zu verstehen.

Die Outlook-Ordnerhierarchie

Wenn du Microsoft Outlook verwendest, kennst du die Outlook-Ordnerhierarchie. - Wenn du das nicht tust, ist das auch kein Problem. Es ist nicht erforderlich, um diesen Text zu verstehen, sondern lediglich die Problemstellung für meinen Beispielcode.

Die Outlook-Ordnerhierarchie hat einen Wurzelknoten, den Namespace. Der Namespace enthält eine Collection-Eigenschaft Folder. Jedes Folder-Objekt in der Collection besitzt wiederum auch eine eigene Collection-Eigenschaft Folder. Diese Hierarchie kann sich über eine beliebige Anzahl von Verschachtelungsebenen erstrecken. (Es gibt sicherlich eine Begrenzung der Verschachtelungsebenen, aber ich weiß nicht, wie tief diese ist.)

Outlook Folder zu Folders Beziehung im VBA Object Browser Fenster illustriert

Die ursprüngliche Frage, die ich am Anfang erwähnte, war also, wie man den Namen jedes Ordners in dieser Hierarchie auflisten kann.

Rekursion in VBA in der Praxis

Der Vollständigkeit halber beginnen wir mit etwas „boiler-plate“ Code, um eine Outlook-Instanz zu erstellen, den MAPI-Namespace als Wurzel der Ordnerhierarchie abzurufen und schließlich ein Folder-Objekt abzurufen, das eines der E-Mail-Konten in dem aktuellen Outlook-Profil darstellt.

Public Sub ListOutlookFolderHiearchy() Const ACCOUNT_NAME As String = "Philipp Stiefel (Codekabinett)" Dim outlookApp As Outlook.Application Dim rootNamespace As Outlook.NameSpace Dim accountFolder As Outlook.Folder Set outlookApp = CreateObject("Outlook.Application") Set rootNamespace = outlookApp.GetNamespace("MAPI") Set accountFolder = rootNamespace.Folders(ACCOUNT_NAME) Debug.Print accountFolder.Name PrintSubFolders accountFolder, 1 End Sub

Für unsere Lektion zur Rekursion konzentrieren wir uns jetzt auf die PrintSubFolders-Unterprozedur, die oben in der letzten Codezeile aufgerufen wird. Der Wurzelordner des E-Mail-Kontos wird als Argument an die Prozedur übergeben.

Private Sub PrintSubFolders(ByVal parentFolder As Object, ByVal subLevel As Integer) Dim subFolder As Outlook.Folder For Each subFolder In parentFolder.Folders Debug.Print String(subLevel, vbTab) & subFolder.Name PrintSubFolders subFolder, subLevel + 1 Next subFolder End Sub

Innerhalb der Prozedur durchlaufen wir die (Unter-) Ordner des übergebenen Wurzelordners und geben die Namen jedes Ordners im VBA-Direktfenster aus. (Um diese Ausgabe anzuzeigen, musst du evtl. [STRG] + [G] drücken, um das Direktfenster anzuzeigen, falls es noch nicht sichtbar ist.)

Soweit ist das einfach. In der nächsten Codezeile rufen wir die PrintSubFolders-Prozedur erneut auf und übergeben die Referenz auf den aktuellen Ordner. Hier beginnt die Rekursion. Die Prozedur wird erneut ausgeführt und gibt nun die Namen der nächstniedrigeren Ordnerebene aus. Und wieder wird für jeden Ordner die PrintSubFolders, für den jetzt aktuellen Ordner aufgerufen. Dies wird wiederholt, bis wir einen Ordner erreichen, der keine Unterordner hat. In diesem Fall wird die aktuelle „Instanz“ der Prozedur abgeschlossen und die Prozedur-„Instanz“, die auf der nächsthöheren Ebene der Ordnerhierarchie arbeitet, setzt die Verarbeitung des nächsten Ordners fort. Dies wird fortgesetzt, bis alle Ordner verarbeitet sind.

Das Argument subLevel für die PrintSubFolders gibt die Verschachtelungstiefe der Ordner an und für jeden Aufruf der Prozedur inkrementiert. Es wird nur verwendet, um die Ausgabe abhängig von der aktuellen Verschachtelungsebene einzurücken.

In meiner obigen Implementierung der PrintSubFolders-Prozedur habe ich das Argument parentFolder bewusst als Object deklariert. Das ermöglicht es alternativ zu einem Folder Objekt auch direkt den root Namespace an die Prozedur zu übergeben und somit die komplette Ordnerstruktur des aktuellen Outlook-Profils auszugeben.

Anwendungsfälle in Microsoft Access

Der häufigste Anwendungsfall für Rekursion in Access ist die Verarbeitung von Formularsteuerelemente. Z.B. möchtest du alle Steuerelemente in einem Formular (de)aktivieren. Wenn das Formular ein Unterformular enthält, kannst du Rekursion einsetzen, um die Steuerelemente im Unterformular zu durchlaufen.

Ein weiteres Beispiel wären hierarchische Daten, wie z.B. eine Organisationstruktur oder eine Vorgesetzter-Untergebener-Hierarchie.

Fazit

Dies mag ein abruptes Ende sein, aber das ist es im Grunde schon. Das ist alles, was Rekursion ausmacht.

Sobald du das Grundkonzept verstanden hast, ist Rekursion ziemlich einfach zu verwenden. Du wirst Rekursion nicht sehr oft verwenden, aber sobald du auf ein Problem, wie das im obigen Beispiel, stößt, ist die Rekursion eine einfache und effiziente Lösung (aus Sicht des Programmierers). In den meisten Szenarien ist es nicht erforderlich, die komplexere und effizientere (aus Sicht des Computers) iterative Implementierung zu programmieren.

Share this article: Share on Facebook Tweet Share on LinkedIn Share on XING

Abonniere meinen Newsletter

*

Ich werde Deine Email-Addresse niemals weitergeben. Du kannst den Newsletter jederzeit abbestellen.
Die Emailliste wird bei Mailchimp in den USA gespeichert. Diese Auftragsverarbeitung ist vertraglich geregelt. Weitere Details in der Datenschutzerklärung.



© 1999 - 2021 by Philipp Stiefel - Datenschutzerklärung