Word automatisieren

Word bietet als Textverarbeitung ganz andere Möglichkeiten als Access-Berichte, wenn es um die Ausgabe von Texten geht. Natürlich liegen die Schwerpunkte bei Word auch ganz anders – so ist es grundsätzlich dafür ausgelegt, seine Texte nacheinander zu erfassen und nicht, wie etwa ein Access-Bericht, in einer durch die verschiedenen Berichtsbereiche vorgegebenen Struktur. Wir schauen uns in diesem Beitrag an, wie Sie Texte von Access nach Word bewegen und umgekehrt.

Im Gegensatz etwa zu Outlook ist Word eine Anwendung, von der man mehrere Instanzen erzeugen kann. Diese Erkenntnis ist wichtig, wenn Sie entscheiden, ob Sie für den VBA-gesteuerten Zugriff auf Word eine bestehende Instanz verwenden oder eine neue Instanz erstellen möchten. Dazu müssen Sie natürlich erst einmal herausfinden, ob auf dem Rechner bereits eine Word-Instanz geöffnet ist.

Da man grundsätzlich sagen kann, dass eine eigene Instanz einfacher zu handhaben ist, legen wir uns gleich darauf fest, jeweils eine eigene Instanz zu erzeugen. So können Sie diese Instanz bei der Erzeugung referenzieren und, wenn Sie diese nicht mehr benötigen, auch wieder beenden.

Wenn Sie von Access aus eine bestehende Instanz nutzen, müssten Sie sich diese gegebenenfalls mit einer anderen Anwendung teilen, die darauf zugreift, oder auch mit dem Benutzer, der gerade vor dem Rechner sitzt. Um eventuelle Seiteneffekte zu vermeiden, rufen wir für die Automation von Access aus lieber gleich eine eigene Instanz auf. Der einzige offensichtliche Nachteil ist, dass dies mehr Ressourcen benötigt als eine einzige Instanz.

Early Binding oder Late Binding

Die immerwährende Frage, ob Sie mit Early oder Late Binding arbeiten, kann man nur unter Betrachung des jeweiligen Kontext beurteilen. Wer eine Automation einer Office-Anwendung programmieren möchte, die unter allen gängigen Anwendungen läuft, sollte dies ohne Verwendung eines Verweises und dementsprechend mit Late Binding erledigen. Auf diese Weise verhindern Sie Probleme, die sonst beim Antreffen der falschen Version des Verweises auftreten.

Allerdings nehmen Sie sich damit auch die Möglichkeit, auf die Ereignisse zu reagieren, die vom Word-Objekt oder vom Document-Objekt ausgelöst werden. Interessant ist dies beispielsweise, wenn Sie beobachten wollen, ob der Benutzer ein Dokument öffnet oder schließt oder dieses speichert.

Sollten Sie solche Funktionen nutzen wollen, arbeiten Sie mit Early Binding, also unter Verwendung eines fest integrierten Verweises auf die jeweils aktuelle Version der Word-Objektbibliothek.

Diesen stellen Sie im Verweise-Dialog ein, den Sie über den Menüpunkt Extras|Verweise des VBA-Editors (Strg + G) öffnen – s. Bild 1. Anschließend können Sie mit der folgenden Anweisung eine Word-Instanz erstellen und mit einer entsprechenden Objektvariablen referenzieren:

Verweis auf die Word-Bibliothek

Bild 1: Verweis auf die Word-Bibliothek

Dim objWord As Word.Application
Set objWord = New Word.Application
Sleep 3000
objWord.Quit
Set objWord = Nothing

Dies erstellt eine Word-Instanz und schließt diese nach drei Sekunden wieder. Die gleiche Variante sieht beim Late Binding so aus:

Dim objWord As Object
Dim objDocument As Object
Set objWord = _
     CreateObject("Word.Application")
Set objDocument = objWord.Documents.Add

Um das Word-Fenster anzuzeigen und in den Vordergrund zu holen, sind ein paar Zeilen mehr nötig. Wir erzeugen zusätzlich ein neues, leeres Word-Dokument, machen die Word-Instanz mit der Visible-Eigenschaft sichtbar und holen das Anwendungsfenster mit der AppActivate-Methode nach vorn:

Dim objWord As Word.Application
Dim objDocument As Word.Document
Set objWord = New Word.Application
Set objDocument = objWord.Documents.Add
objWord.Visible = True
AppActivate objDocument.Name
Sleep 3000
objWord.Quit
Set objWord = Nothing

Auch diese Instanz soll nach drei Sekunden wieder verschwinden. Sie können auch ohne explizites Erzeugen eines Word-Objekts ein Dokument in Word erzeugen oder öffnen. Das geht schlicht so:

Dim objDocument As Word.Document
Set objDocument = New Word.Document
objDocument.Parent.Visible = True
AppActivate objDocument.Name
Sleep 3000
objDocument.Close

Nach dem Schließen bleibt die Word-Instanz allerdings bestehen. Sie müssen diese dann manuell schließen oder per Code über die Parent-Eigenschaft des Word-Dokuments:

objDocument.Parent.Quit

Dazu muss das Dokument natürlich noch geöffnet sein. Wenn das Dokument vom Erzeugen beziehungsweise öffnen bis zum Schließen noch bearbeitet wird, erscheint beim Versuch, Word zu schließen, ein Dialog, der fragt, ob das Dokument gespeichert werden soll (s. Bild 2).

Rückfrage vor dem Schließen eines Dokuments

Bild 2: Rückfrage vor dem Schließen eines Dokuments

Dies können Sie verhindern, indem Sie festlegen, was beim Schließen geschehen soll: Soll Word das Dokument ohne Rückfrage speichern Oder die änderungen verwerfen Dies legen Sie mit einem der folgenden Werte für den ersten Parameter der Close-Methode des Document-Objekts fest:

  • wdDoNotSaveChanges: Schließt das Dokument, ohne zu speichern.
  • wdPromptToSaveChanges: Fragt den Benutzer, ob das Dokument gespeichert werden soll (Standardwert).
  • wdSaveChanges: Speichert die änderungen.

Wenn Sie das Speichern-Verhalten auf diese Weise beeinflussen möchten, müssen Sie die Word-Instanz allerdings explizit instanzieren.

Anderenfalls könnten Sie diese nach dem Schließen des Document-Objekts nicht mehr refenzieren und müssten Word manuell schließen (sofern sichtbar) oder über den Task-Manager terminieren (wenn das Word-Fenster nicht eingeblendet wurde).

Wenn Sie selbst das Dokument per VBA mit Text füllen oder vorhandenen Text bearbeiten, werden Sie die änderungen vor dem Schließen speichern wollen:

Dim objWord As Word.Application
Dim objDocument As Word.Document
Set objWord = New Word.Application
Set objDocument = objWord.Documents.Add
objWord.Visible = True
AppActivate objDocument.Name
objDocument.Range = "Hallo"
Sleep 3000
objDocument.Close, 
objWord.Quit
Set objWord = Nothing

Haben Sie ein neues Dokument erstellt, wurde dies allerdings zuvor noch nicht gespeichert – ein Versuch, das Dokument zu schließen und automatisch zu speichern, schlägt fehl, da Word noch keinen Speicherort kennt. In diesem Fall speichern Sie es zuvor manuell unter dem gewünschten Namen. Dabei geben Sie optimalerweise direkt das gewünschte Format an, hier als Word-Dokument:

objDocument.SaveAs2 CurrentProject.Path 
& "\word.doc", wdFormatDocument

Dies verwendet das ältere .doc-Format. Wenn Sie das neue XML-Format verwenden möchten (Dateiendung .docx), verwenden Sie diese Anweisung:

objDocument.SaveAs2 CurrentProject.Path 
& "\word.docx", wdFormatXMLDocument

Beide Anweisungen speichern das Dokument im Verzeichnis der aktuellen Access-Datenbank.

Bestehendes Dokument öffnen

Sie können auch auf ein bereits bestehendes Dokument zugreifen. Dazu verwenden Sie die Open-Methode der Documents-Auflistung des Word-Objekts:

Set objDocument = objWord.Documents.Open(CurrentProject.Path & "\word.doc")

Auch dies gelingt mit Late Binding – in diesem Fall ohne vorherige Instanzierung eines Word-Objekts:

Set objDocument = GetObject( CurrentProject.Path & "\word.doc")

Sie müssen also einfach nur den Namen des zu öffnenden Dokuments als Parameter der GetObject-Methode angeben.

Text einfügen

Nachdem Sie ein Word-Dokument erstellt oder geöffnet haben, möchten Sie Text einfügen.

Dies gelingt am einfachsten, indem Sie dem mit der Range-Eigenschaft geliefernten Objekt des Word-Dokuments einen Text zuweisen:

objDocument.Range.Text = "Range-Objekt gefüllt"

Was aber ist dieses Range-Objekt überhaupt

Ein Range-Objekt markiert verschiedene Bereiche eines Dokuments. Das Range-Objekt des Document-Objekts etwa markiert den kompletten Inhalt. Wenn Sie der Text-Eigenschaft dieses Range-Objekts einen Text zuweisen, wird der komplette Bereich mit dem angegebenen Text überschrieben.

Sie können dies einfach experimentell prüfen, indem Sie eine Objektvariable für ein Document-Objekt im Kopf eines Standardmoduls deklarieren:

Public objDoc As Word.Document

Dieses füllen Sie dann mit der folgenden Prozedur:

Public Sub TextExperimente()
     Dim objWord As Word.Application
     Set objWord = New Word.Application
     Set objDoc = objWord.Documents.Add
     objWord.Visible = True
     AppActivate objDoc.Name
End Sub

Das Dokument bleibt geöffnet und Sie können über das Direktfenster mit der Variablen objDoc auf das Dokument zugreifen.

Wenn Sie dort beispielsweise die folgende Zeile eingeben, wird der entsprechende Text angelegt (s. Bild 3):

Einfügen von Texten über den Direktbereich

Bild 3: Einfügen von Texten über den Direktbereich

objDoc.Range.Text = "Text aus dem Direktbereich"

Um zu erkennen, welchen Bereich die Range-Eigenschaft jeweils zurückgibt, können Sie den Bereich per VBA markieren:

objDoc.Range.Select

Die Markierung ist nicht direkt sichtbar, also aktivieren Sie entweder manuell das Word-Fenster oder Sie aktivieren dieses mit dieser Anweisung:

AppActivate objDoc.Name

Tippen Sie einmal einige Absätze in das Dokument und wiederholen das Markieren des Range-Objekts von objDoc, erkennen sie, dass dieses Range-Objekt immer den kompletten Dokumentinhalt betrifft.

Beim Experimentieren werden Fehler auftreten, was dazu führt, dass die Objektvariable objDoc ihren Inhalt verliert.

Mit der folgenden kleinen Prozedur füllen Sie diese wieder – vorausgesetzt, während der Experimente gibt es nur eine Word-Instanz mit nur einem Dokument (s. Listing 1).

Public Sub AktuellesDokumentReferenzieren()
     Dim objWord As Word.Application
     Set objWord = GetObject(, "Word.Application")
     Set objDoc = objWord.Documents(1)
End Sub

Listing 1: Referenzieren des aktuellen Dokuments

Dokumentinhalt einlesen

Andersherum können Sie den Inhalt eines Range-Objekts auch über das Direktfenster auslesen. Dazu geben Sie beispielsweise mit der Debug.Print-Anweisung den Inhalt der Eigenschaft Text des aktuellen Range-Objekts aus.

Absätze

Ein Absatz in einem Word-Dokument ist ein Text, der mit dem Zeilenumbruch abgeschlossen wird, also dem Zeichen, das Sie unter VBA mit vbCr beziehungsweise Chr(13) darstellen können. Die durch dieses Zeichen voneinander getrennten Absätze können Sie mit der Paragraphs-Auflistung erfassen und mit einer Objektvariablen des Typs Paragraph referenzieren. In Bild 4 haben wir beispielsweise den Inhalt des zweiten Absatzes im Direktfenster ausgegeben.

Zugriff auf einen Absatz per Paragraphs-Auflistung

Bild 4: Zugriff auf einen Absatz per Paragraphs-Auflistung

Wollen Sie den Text eines Absatzes verändern, können Sie diesen gezielt referenzieren und anpassen – und zwar so:

objdoc.Paragraphs(2).Range.Text = "Neuer Text in Absatz 2"

Das Ergebnis fällt allerdings nicht wie gewünscht aus: Der Text des zweiten Absatzes wird zwar ersetzt, aber der zweite Absatz verschmilzt mit dem dritten Absatz. Der Grund ist einfach: Sie haben einen Absatz, dessen Text mit einem Zeilenumbruch abgeschlossen wurde, durch einen Text ohne Zeilenumbruch ersetzt. Die folgende Anweisung ersetzt den Absatz schließlich wie gewünscht:

objDoc.Paragraphs(2).Range.Text = "Neuer Text in Absatz 2" & vbCr

Sie haben das Ende des frei verfügbaren Textes erreicht. Möchten Sie ...

TestzugangOder bist Du bereits Abonnent? Dann logge Dich gleich hier ein. Die Zugangsdaten findest Du entweder in der aktuellen Print-Ausgabe auf Seite U2 oder beim Online-Abo in der E-Mail, die Du als Abonnent regelmäßig erhältst:

Schreibe einen Kommentar