Zur Hauptseite ... Zum Onlinearchiv ... Zum Abonnement ... Zum Newsletter ... Zu den Tools ... Zum Impressum ... Zum Login ...

Gedrucktes Heft

Diesen Beitrag finden Sie in Ausgabe 5/2007.

Unser Angebot für Sie!<

Lesen Sie diesen Beitrag und 1.000 andere sofort im Onlinearchiv, und erhalten Sie alle zwei Monate brandheißes Access-Know-how auf 76 gedruckten Seiten! Plus attraktive wechselnde Präsente, zum Beispiel Bücher wie Anwendungen entwickeln mit Access!

Diesen Beitrag twittern

Zusammenfassung

Erweitern Sie Outlook um Funktionen, die etwa eine automatische Archivierung von Elementen in einer Access-Datenbank erlauben.

Techniken

Outlook, VBA

Voraussetzungen

Access 2000 und höher

Beispieldateien

ThisOutlookSession.cls

Shortlink

500

Outlook-Objekte in Access speichern

André Minhorst, Duisburg

Bereits einige Beiträge in Access im Unternehmen beschäftigt sich mit dem Im- und Export von Outlook-Objekten zwischen Access und Outlook. Dabei erfolgt das Synchronisieren immer zu einem vom Benutzer festgelegten Zeitpunkt. Was aber, wenn man in Access immer auf die aktuell in Outlook gespeicherten Daten zugreifen möchte, ohne die Daten manuell abzugleichen? Ein Blick hinter die Kulissen des Outlook-Objektmodells bringt Lichts ins Dunkel.

Kontakte, E-Mails, Termine und Aufgaben - den Abgleich all dieser Objekte zwischen Access und Outlook haben Sie als fleißiger Leser bereits kennen gelernt. Falls nicht, empfiehlt sich ein Blick auf die im Onlinearchiv gespeicherten Beiträge mit den Shortlinks 290 (E-Mails), 439 (Termine), 113 und 129 (Kontakte) sowie 498 (Aufgaben).

Diese Artikel beschreiben in der Regel, wie Sie die jeweiligen Objekte von Access nach Outlook und zurück bekommen - allerdings immer von Access aus gesteuert. Dementsprechend sollte es auch kein Problem sein, in Access eine Funktion zu implementieren, die neu angelegte oder geänderte Elemente direkt nach dem Anlegen oder Ändern mit Outlook synchronisiert.

Dies funktioniert natürlich auch andersherum: Sie können ohne größeren Aufwand dafür sorgen, dass Outlook, wenn ein Benutzer ein neues Element wie etwa einen Kontakt anlegt, direkt den passenden in einer Datenbank gespeicherten Eintrag ändert.

Beispielhaft

Um die Beispiele nachvollziehen zu können, kopieren Sie einfach den Inhalt der Datei ThisOutlookSession.cls in die gleichnamige Klasse im Outlook-VBA-Editor und passen die darin enthaltenen Pfadangaben an.

Outlook-Ereignisse

Zum Automatisieren von Outlook selbst bedarf es natürlich erstens eines kleinen Blickes in das Objektmodell und dort vor allem auf die Ereignisse, die beim Anlegen oder Ändern von Outlook-Elementen ausgelöst werden - und es muss klar sein, dass Sie die notwendigen Prozeduren natürlich innerhalb von Outlook und nicht in einer Access-Anwendung anlegen. Der Ort für das Deklarieren ereignis-sensitiver Objekte in Outlook ist schnell gefunden: Es handelt sich dabei um ein standardmäßig vorhandenes Klassenmodul namens ThisOutlookSession. Die Ereignisprozeduren des Application-Objekts, also von Outlook selbst, werden hier, soweit vorhanden, automatisch ausgelöst. Das erkennen Sie ganz leicht, wenn Sie zum VBA-Editor wechseln (von Outlook aus am schnellsten per Strg + F11), dort das Modul ThisOutlookSession öffnen und im linken Kombinationsfeld des Codefensters Application auswählen. Das rechte Kombinationsfeld liefert dann alle möglichen Ereignisse. Die leere Ereignisprozedur, die das Öffnen einer Outlook-Instanz auslöst, sieht dann etwa so aus:

Private Sub Application_Startup()

End Sub

Ab jetzt kommt es darauf an, was Sie vorhaben: Soll eine Mail, ein Kontakt, ein Termin oder eine Aufgabe direkt nach dem Anlegen in einer Access-Tabelle gespeichert werden? Oder muss dies auch bei Änderungen geschehen?

Aufgaben nach Access

Werfen Sie zunächst einen Blick auf das Anlegen einer neuen Aufgabe in Outlook. Diese soll direkt nach dem Erzeugen in eine Access-Tabelle wie die aus dem Beitrag Outlook-Aufgaben (Shortlink 498) exportiert werden.

Was für ein Ereignis benötigen Sie hier? Eines, das in Zusammenhang mit dem neuen Element (hier einer Aufgabe) selbst ausgelöst wird? Nein! Das neue Element existiert ja zu dem Zeitpunkt, an dem Sie die Ereigniseigenschaft schreiben, die ein neues Aufgaben-Element nach Access schieben soll, noch gar nicht. Ein "New"- oder "Add"-Ereignis steht auch so gut wie nie für ein einzelnes Objekt zur Verfügung, sondern meist für die Auflistung, die das zu erzeugende Element einmal aufnehmen wird. Und das ist in diesem Falle die Items-Auflistung des Aufgaben-Ordners.

Damit Sie die Ereignisse eines Elements durch entsprechende Ereignisprozeduren abfangen können, müssen Sie dieses - wenn es nicht wie das Application-Element bereits vorhanden ist - zunächst deklarieren und instanzieren, wobei Sie beim Deklarieren das Schlüsselwort WithEvents verwenden. Die folgende Anweisung deklariert zunächst einen handelsüblichen Outlook-Ordner:

Dim WithEvents objItems As Outlook.Items

Damit dieses Objekt explizit beim Anlegen eines bestimmten Outlook-Elements Ereignisse auslöst, instanzieren Sie es mit dem entsprechenden Typ, hier der Items-Auflistung des Aufgaben-Ordners:

Private Sub Application_Startup()

Set objItems = Application.Session.GetDefaultFolder(olFolderTasks).Items

End Sub

Im Gegensatz zum Verwenden einer Outlook-Instanz von Access aus benutzen Sie hier nicht die GetDefaultFolder-Methode von Application.GetNamespace("MAPI"), sondern von Application.Session, was einen expliziten Zugriff auf die in der aktuellen Sitzung erzeugten und bearbeiteten Objekte zulässt.

Wenn Sie nun einen Blick auf die Ereignisse der oben deklarierten Auflistung objItems werfen, finden Sie auch direkt etwas Passendes (s. Abb. 1).

pic001.tif

Abb. 1: Mit diesen Ereignissen lassen sich Outlook-Elemente nach dem Anlegen, Ändern oder Entfernen mit einer passenden Access-Datenbank synchronisieren.

Für einen Test verwenden Sie zunächst das ItemAdd-Ereignis. Folgende Implementierung zeigt in einem Meldungsfenster den Betreff und den Inhalt einer frisch angelegten Aufgabe an, wobei der Parameter Item einen Verweis auf das passende Element liefert:

Private Sub objItems_ItemAdd(ByVal Item As _
Object)

   Dim objTaskItem As Outlook.TaskItem

   Set objTaskItem = Item

   With objTaskItem

     MsgBox .Subject & " " & .Body

   End With

End Sub

Um diese Routine zu testen, schließen Sie Outlook nach der Eingabe, bestätigen das Speichern des Moduls VbaProjekt.OTM und öffnen Outlook erneut. Bereits beim Öffnen instanziert Outlook die festgelegte Aufgaben-Auflistung und ist von nun an bereit, auf neu angelegte Elemente mit der oben beschriebenen Routine zu reagieren. Beachten Sie, dass Outlook die Ereignisse immer erst beim Speichern des neu angelegten oder geänderten Elements auslöst.

Die Methode ItemChange können Sie genauso wie ItemAdd verwenden, um geänderte Elemente mit der Datenbank zu synchronisieren.

Allein die ItemRemove-Methode vermag ihre Aufgabe nicht recht zu lösen - das geht allein aus ihrer Deklaration hervor. Die Parameterliste ist nämlich leer, das heißt, dass die Routine keine Informationen über das gelöschte Element liefert, sondern allein über den Löschvorgang selbst informiert:

Private Sub objItems_ItemRemove()

End Sub

Löschsynchronisation

Um ein innerhalb von Outlook gelöschtes Element auch in der passenden Access-Tabelle zu löschen, müssen Sie zu anderen Mitteln greifen. Die richtige Methode namens Delete liefert nämlich das TaskItem-Objekt, für andere Elemente gibt es Objekte wie MailItem (E-Mail), ContactItem (Kontakt) oder AppointmentItem (Termine).

Also deklarieren Sie zunächst im gleichen Modul eine Objektvariable mit Ereignisbehandlung zum Verweis auf das zu löschende Element:

Dim WithEvents objTaskItem As Outlook.TaskItem

Für andere Elemente deklarieren Sie dieses als eines der oben genannten Objekte. Nun müssen Sie allerdings noch einen Weg finden, einen Verweis auf das zu löschende Objekt zu erstellen. Was passiert den überhaupt im Verlauf eines Löschvorgangs? Zunächst markiert man das zu löschende Objekt und initialisiert dann den Löschvorgang selbst, indem man beispielsweise auf die Entf-Taste klickt oder den Löschen-Eintrag aus dem Kontextmenü auswählt.

Interessant ist die Auswahl des zu löschenden Objekts: Forschen wir also nach einem Ereignis, das beim Auswählen eines Outlook-Elements ausgelöst wird, und fangen ganz oben an: bei den Ereignissen des Application-Objekts. Mmmh ... viel versprechend sieht das nicht aus; vielleicht hilft Application_ItemLoad weiter.

Um dies zu testen, legen Sie einfach die passende Ereignisprozedur an und fügen eine simple Anweisung wie folgt hinzu:

Private Sub Application_ItemLoad(ByVal _
Item As Object)

   MsgBox "ItemLoad aufgerufen"

End Sub

Klicken Sie dann in eine der Listen (beispielsweise E-Mails, Kontakte etc.) und seien Sie erfreut: Die Auswahl eines der Einträge löst dieses Ereignis aus. Das ist perfekt, Sie müssen also nur noch prüfen, ob es sich beim ausgewählten Element um den richtigen Typ handelt (immerhin wollen wir hier erstmal nur Aufgaben behandeln) und diesen gegebenenfalls der Objektvariablen objTaskItem zuweisen:

Private Sub Application_ItemLoad(ByVal _
Item As Object)

   If Item.Class = olTask Then

     Set objTaskItem = Item

   End If

End Sub

Zu beachten ist hier, dass das mit dem Parameter Item referenzierte Objekt zu diesem Zeitpunkt nur zwei Eigenschaften liefert: Class und MessageClass, wobei in diesem Fall Class die interessantere ist, weil sie Informationen über den Typ des Outlook-Elements liefert und wie in obiger Routine ausgewertet werden kann. Die möglichen Werte für die Class-Eigenschaft finden Sie übrigens, indem Sie im Objektkatalog zunächst nach dem Begriff Class suchen und, wenn möglich, die Zielbibliothek einschränken, womit in diesem Fall die Outlook-Bibliothek gemeint ist. Finden Sie dann das passende Objekt - hier das TaskItem-Objekt - und klicken Sie in der Objektliste auf die Eigenschaft (Class). Der Objektkatalog zeigt dann wie in Abb. 2 den Datentyp dieser Eigenschaft an, in diesem Fall OlObjectClass. Klicken Sie auf den grünen Link zu diesem Datentyp, zeigt der Objektkatalog eine Liste aller für diesen Datentyp verfügbaren Werte an (s. Abb. 3).

pic002.tif

Abb. 2: Über die Eigenschaft ...

pic003.tif

Abb. 3: ... finden sich meist auch ihre Konstanten.

Wenn Sie nun wissen wollen, welcher dem TaskItem entspricht, müssen Sie der LoadItem-Ereignisprozedur nur eine Anweisung hinzufügen, die den Wert der Class-Eigenschaft des aktuell geladenen Elements liefert:

Private Sub Application_ItemLoad(ByVal _
Item As Object)

   MsgBox Item.Class

End Sub

Bei einer Aufgabe erscheint hier etwa der Wert 48, bei einer E-Mail der Wert 43 und so weiter. Beachtenswert ist, dass ItemLoad in manchen Fällen nicht allein durch das Markieren ausgelöst wird, da Outlook nicht für all diese Aktionen Informationen über das jeweilige Element laden muss. Wenn Sie etwa auf einen Termin im Kalender klicken, wird dieser noch nicht geladen, wenn Sie ihn per Doppelklick öffnen oder auch nur das Kontextmenü anzeigen, dann schon.

Die zum Wert passende Konstante finden Sie nun im Objektkatalog, wenn Sie die vorhandenen Werte für die Class-Eigenschaft durchlaufen.

Da Sie nun einen Verweis auf das zu löschende TaskItem-Element besitzen, können Sie auch dessen Ereignisse nutzen: In diesem Fall hilft das BeforeDelete-Ereignis weiter, das vor dem Löschen ausgelöst wird und diesen Vorgang noch abbrechen kann. Dazu müssen Sie innerhalb der Ereignisprozedur nur den Wert des Parameters Cancel auf True einstellen.

In diesem Fall wollen wir jedoch zunächst einen einfachen Hinweis auf das Löschen einer Outlook-Aufgabe erhalten, was sich mit folgender Routine bewerkstelligen lässt:

Private Sub objTaskItem_BeforeDelete(ByVal _
Item As Object, Cancel As Boolean)

   MsgBox "Delete " & objTaskItem.Subject _
& " " & objTaskItem.Body

End Sub

Synchronisieren geht über Studieren

Nachdem Sie alle Ereignisse beisammen haben, die beim Hinzufügen, Löschen und Ändern von Outlook-Elementen ausgelöst werden, müssen Sie diese nur noch so mit Leben füllen, dass sie die vorgenommenen Änderungen in die Access-Tabelle übertragen.

Das ist für einen Access-Entwickler nur noch Routinearbeit, wenn man einmal vom Instanzieren der Ziel-Datenbank absieht. Sie verwenden nämlich nicht einfach die folgenden Anweisungen:

Dim db As DAO.Database

Set db = CurrentDB

Stattdessen kommt die OpenDatabase-Methode zum Einsatz:

Dim db As DAO.Database

Set db = DBEngine.OpenDatabase("<Pfad>\<Datei>")

Natürlich müssen Sie dazu im Outlook-VBA-Projekt einen Verweis auf die DAO-Bibliothek oder, wenn Sie eine Datenbank im Format von Access 2007 (.accdb) verwenden, einen Verweis auf die Bibliothek Microsoft Office 12.0 Access Database Engine Object Library hinzufügen.

Anschließend können Sie wie gewohnt auf die Tabellen der referenzierten Datenbank zugreifen. Aus Platzgründen soll dieser Artikel nicht alle Aktionen (anlegen, löschen, ändern) beschreiben, sondern beschränkt sich auf das Anlegen eines neuen TaskItem-Elements in Outlook und dessen Pendant in der Access-Tabelle.

Wie dies funktioniert, zeigt Listing 1. Die Routine öffnet die Zieldatenbank, erzeugt ein Recordset auf Basis der Zieltabelle und schreibt die Eigenschaftswerte des neu erzeugten TaskItem-Elements in diese Tabelle. Schließlich fragt sie noch den Primärschlüsselwert dieser Tabelle ab und schreibt ihn in die Eigenschaft BillingInformation der neuen Aufgabe.

Listing 1: Diese Ereignisprozedur schreibt eine in Outlook frisch angelegte Aufgabe in die passende Access-Tabelle.

Private Sub objItems_ItemAdd(ByVal Item As Object)

   Dim db As DAO.Database

   Dim objTaskItem As Outlook.TaskItem

   Dim rst As DAO.Recordset

  Set db = DBEngine.OpenDatabase("<Pfad>\<Datei>")

   Set objTaskItem = Item

   Set rst = db.OpenRecordset("SELECT * FROM tblAufgaben WHERE 1=2", _
dbOpenDynaset)

  With objTaskItem

     rst.AddNew

     With rst

       !Subject = objTaskItem.Subject

       !Body = objTaskItem.Body

       !StartDate = objTaskItem.StartDate

       !DueDate = objTaskItem.DueDate

       !DateCompleted = objTaskItem.DateCompleted

       !PercentComplete = objTaskItem.PercentComplete

       !Importance = objTaskItem.Importance

     End With

     If objTaskItem.BillingInformation = "" Then

       objTaskItem.BillingInformation = rst!ID

     End If

     rst.Update

   End With

   Set db = Nothing

End Sub

Dies dient dem späteren Synchronisieren von Aufgaben zwischen Outlook und Access; weitere Informationen dazu finden Sie im Beitrag Outlook-Aufgaben (Shortlink 498).

Die übrigen Ereignisprozeduren, die beim Ändern und Löschen für eine Synchronisation mit der Access-Tabelle sorgen, finden Sie im Beispielmodul.

Zusammenfassung und Ausblick

Outlook-Objekte lassen sich auch von Outlook aus beim Anlegen direkt mit den Daten in entsprechenden Access-Tabellen synchronisieren.

Sie haben die dazu notwendigen Techniken kennen gelernt und einen kleinen Einblick in das Objektmodell von Outlook und seine Ereignisse erhalten.

Was hier am Beispiel von Aufgaben exemplarisch gezeigt wurde, lässt sich leicht auf Basis anderer Objekte wie E-Mails, Kontakte oder Termine nachstellen.

Download

Download

Die .zip-Datei enthält folgende Dateien:

Outlookaufgaben.accdb

Outlookaufgaben.mdb

ThisOutlookSession.cls

Beispieldateien downloaden

© 2003-2018 André Minhorst Alle Rechte vorbehalten.