Home » Tipps & Tricks » COM/OLE/DDE » Word » Word mit OLE-Automation steuern

Word mit OLE-Automation steuern

Wie kann ich Word starten?

Mit den D5-Komponenten:

WordApplication1.Connect;
WordApplication1.Visible := True;

Wenn die Verbindung steht, kann die ConnectTo-Methode der anderen Word-Komponenten verwendet werden, um sie mit anderen Word-Elementen, wie z.B. einem Word-Dokument, zu verbinden:

WordDocument1.ConnectTo(WordApplication1.ActiveDocument);

Mit der Typbibliothek (frühe Bindung):

Bevor Sie diese Methode verwenden können, müssen Sie die Typbibliothek (MSWord8.olb für Word 97) importiert haben.
Eine Art, Word zu starten, ist den Aufruf von GetActiveObject auszuprobieren (try-Abschnitt), um eine bereits laufende Word-Instanz zu erhalten, es sollte aber ein Aufruf von CoApplication.Create im except-Teil stehen. Aber except-Klauseln sind langsam und können bei Leuten, die gerne „Bei Exceptions anhalten“ aktiviert haben, Probleme innerhalb der IDE auslösen. Der folgende Code benötigt keine try-except-Konstruktion, weil die Verwendung von OleCheck bei GetActiveObject im Fall, dass Word nicht läuft, vermieden wird.

uses ComObj, ActiveX,
       Word_TLB; // or Word97; or Word2000; for D5 users

var
  Word: _Application;
  AppWasRunning: boolean; // tells you if you can close Word when you've finished
  Unknown: IUnknown;
  Result: HResult;
begin
  AppWasRunning := False;

  {$IFDEF VER120}      // Delphi 4
  Result := GetActiveObject(CLASS_Application_, nil, Unknown);
  if (Result = MK_E_UNAVAILABLE) then
    Word := CoApplication_.Create

  {$ELSE}              // Delphi 5
  Result := GetActiveObject(CLASS_WordApplication, nil, Unknown);
  if (Result = MK_E_UNAVAILABLE) then
    Word := CoWordApplication.Create
  {$ENDIF}

  else begin
    { make sure no other error occurred during GetActiveObject }
    OleCheck(Result);
    OleCheck(Unknown.QueryInterface(_Application, Word));
    AppWasRunning := True;
  end;
  Word.Visible := True;
  ...

Ohne Verwendung der Typbibliothek:

Automation ist sehr viel schneller und einfacher, wenn Typbibliotheken (frühe Bindung) verwendet werden, deshalb sollten Sie es, wenn immer möglich, vermeiden, ohne sie zu arbeiten. Aber wenn es wirklich nicht anders geht, hier, wie vorzugehen ist:

var
  Word: Variant;
begin
  try
    Word := GetActiveOleObject('Word.Application');
  except
    Word := CreateOleObject('Word.Application');
  end;
  Word.Visible := True;

Oder mit früheren Word-Versionen:

var
  Word: Variant;
begin
  try
    Word := GetActiveOleObject('Word.Basic');
  except
    Word := CreateOleObject('Word.Basic');
  end;
  Word.Visible := True;

Durch die Verwendung von GetActiveOleObject verwenden Sie eine bereits laufende Instanz von Word, sofern es eine gibt.

Wie kann ich Word schließen?

Hier die schnelle Variante:

var
  SaveChanges: OleVariant;
begin
  SaveChanges := wdDoNotSaveChanges;
  Word.Quit(SaveChanges, EmptyParam, EmptyParam);

Andere mögliche Werte für die SaveChanges-Parameter sind wdSaveChanges und wdPromptToSaveChanges – eigentlich selbsterklärend, aber wenn Sie die späte Bindung verwenden, müssen Sie sie in Ihrem eigenen Code etwa so definieren:

const
    wdDoNotSaveChanges = $00000000;
    wdSaveChanges = $FFFFFFFF;
    wdPromptToSaveChanges = $FFFFFFFE;

Der zweite Parameter wird für Dokumente, die nicht im Word-Format sind, genutzt. Mögliche Werte sind wdOriginalDocumentFormat, wdPromptUser oder wdWordDocument. Wiederum müssen Sie diese bei später Bindung selbst deklarieren:

const
    wdWordDocument = $00000000;
    wdOriginalDocumentFormat = $00000001;
    wdPromptUser = $00000002;

Der letzte Parameter sollte auf true gesetzt werden, wenn Sie wollen, dass das Dokument an den nächsten Empfänger in der Reihe weitergeleitet werden soll.

Wie kann ich ein neues Dokument erzeugen?

In Word 97:

Word.Documents.Add(EmptyParam, EmptyParam);

Wenn Sie wollen, dass das neue Dokument auf einer anderen Vorlage als der normalen Vorlage (normal.dot) basiert, übergeben Sie den Namen (und den Pfad) der Vorlage als ersten Parameter. Wenn Sie wollen, dass das Dokument als Vorlage geöffnet wird, übergeben Sie true als zweiten Parameter.
In Word 2000 hat die Documents.Add-Methode zwei zusätzliche Parameter, für den Dokumententyp und für die Festlegung, ob das Dokument auf dem Bildschirm sichtbar sein soll. Die Verwendung dieser Methode auf einem Word 97-Rechner verursacht allerdings eine Exception. Verwenden Sie deshalb Word 2000’s Document.AddOld-Methode, wenn Ihr Code mit Word 97 kompatibel sein soll. Diese verwendet die gleichen Parameter wie die Add-Methode von Word 97.

Wie kann ich ein bestehendes Dokument öffnen?

In Word 97:

var
  FileName: OleVariant;
begin
  FileName := 'C:My DocumentsThe file I want to open.doc';
  Word.Documents.Open(FileName, EmptyParam, EmptyParam, EmptyParam,
                      EmptyParam, EmptyParam, EmptyParam, EmptyParam,
                      EmptyParam, EmptyParam);

Die optionalen Parameter hier stehen für ReadOnly (dritter Parameter, Standard false), PasswordDocument (fünfter Parameter, übergeben Sie den für das Dokument gültigen Passwort-String) und Format (der letzte Parameter, lässt Sie den Dateikonverter angeben, der verwendet werden soll).
In Word 2000 hat die Documents.Open-Methode zwei zusätzliche Parameter für Verschlüsselung und für die Festlegung, ob das Dokument auf dem Bildschirm sichtbar sein soll. Die Verwendung dieser Methode auf einem Word 97-Rechner verursacht allerdings eine Exception. Verwenden Sie deshalb Word 2000’s Document.OpenOld-Methode, wenn Ihr Code mit Word 97 kompatibel sein soll. Diese verwendet die gleichen Parameter wie die Open-Methode von Word 97.

Wie kann ich ein Dokument schließen?

var
  SaveChs: olevariant;
begin
  SaveChs := wdSaveChanges;
  Word.ActiveDocument.Close(SaveChs, EmptyParam, EmptyParam);

Die Parameter sind die gleichen wie bei der Word-Schließen-Methode, aber mit einer unangenehmen Ausnahme: Es gibt einen Bug, der verhindert, dass der wdPromptToSaveChanges-Wert in dieser Methode funktioniert. Wenn Sie also wollen, dass der Anwender gefragt wird, ob die Änderungen gespeichert werden sollen, verwenden Sie stattdessen die ActiveWindow.Close-Methode.

Wie kann ich Text einfügen?

var
    S: Selection;
  ...
    S :=Word.Selection;
    S.TypeText('Here is some text');
    S.TypeParagraph;
    S.TypeParagraph;
    S.TypeText('And there was a blank line.');

Wenn die Application.Options.ReplaceSelection-Eigenschaft true ist, wird jeder Text durch den neuen Text überschrieben.

Wie kann ich Text formatieren?

var
    S: Selection;
  ...
    S := Word.Selection;

    {Write the next sentence in bold type}
    S.Font.Bold := integer(True);
    S.TypeText('Be bold!');
    S.Font.Bold := integer(False);
    S.TypeParagraph;


    {Write the next sentence in italic type}
    S.Font.Italic := integer(True);
    S.TypeText('Be daring!');
    S.Font.Italic := integer(False);

Denken Sie bei der Verwendung des Selection-Objekts daran, dass jeder Text durch den neuen Text überschrieben wird, wenn die Eigenschft Application.Options.ReplaceSelection true ist.

Wie kann ich Tabellen erzeugen und auf sie zugreifen?

Sie können Tabellen auf diese Art erzeugen (getestet in Word 97):

var
  Doc: _Document;
  T: Table;
begin
  Doc := Word.ActiveDocument;
  T := Doc.Tables.Add(Word.Selection.Range, 5, 3);
  T.Cell(1, 1).Range.Text := 'January';
  T.Cell(1, 2).Range.Text := 'February';
  T.Cell(1, 3).Range.Text := 'March';
  T.Columns.Width := 72; // in points

Die Daten können Sie auf die gleiche Art lesen:

Caption := T.Cell(1, 3).Range.Text;

Das Verwenden von Tabellen in Word ist allerdings sehr langsam (noch schlimmer in Word 2000). Wenn möglich, sollten Sie zuerst den Text einfügen und diesen im letzt möglichen Moment in eine Tabelle umwandeln, etwa so:

const
  Line1 = 'January,February,March';
  Line2 = '31,28,31';
  Line3 = '31,59,90';
var
  R: Range;
  Direction, Separator, Format: OleVariant;
begin
  Doc := Word.ActiveDocument;
  R := Word.Selection.Range;
  Direction := wdCollapseEnd;
  R.Collapse(Direction);
  R.InsertAfter(Line1);
  R.InsertParagraphAfter;
  R.InsertAfter(Line2);
  R.InsertParagraphAfter;
  R.InsertAfter(Line3);
  R.InsertParagraphAfter;
  Separator := ',';
  Format := wdTableFormatGrid1;
  R.ConvertToTable(Separator, EmptyParam, EmptyParam,
                   EmptyParam, Format, EmptyParam,
                   EmptyParam, EmptyParam, EmptyParam,
                   EmptyParam, EmptyParam, EmptyParam,
                   EmptyParam, EmptyParam);

Wie kann ich die Eigenschaften eines Dokuments erhalten?

Verwenden Sie dafür Varianten. (Sehr viele der DocumentProperties-Aufrufe geben IDispatch-Interfaces zurück statt eines spezifischen Interfaces, wie Sie es wollen. Das bei früher Bindung hinzubekommen ist zu kompliziert, um den Aufwand zu rechtfertigen.)

var
  Doc: OleVariant;
...
  Doc := Word.ActiveDocument;
  Caption := Doc.BuiltInDocumentProperties['Template'].Value;
  ShowMessage(Doc.BuiltInDocumentProperties[wdPropertyTitle].Value);
  ShowMessage(Doc.BuiltInDocumentProperties[wdPropertyAuthor].Value);

Wie Sie sehen können, kann auf die Eigenschaften entweder über ihren Namen oder über eine der wdProperty-Konstanten zugegriffen werden. Sie können ebenso eine Schleife über die BuiltInDocumentProperties-Sammlung machen – aber tun Sie dies nur, wenn es sein muss, weil es bewirkt, dass die Wort- und Seitenzahl neu berechnet wird. Wenn das Dokument etwas länger ist, werden sich die Anwender darüber nicht sehr freuen 😉

Wie kann ich die Position des Cursors erhalten?

Das geht über die Information-Eigenschaft des Selection-Objekts. Hier ein Beispiel:

VertPos := Word.Selection.Information[wdVerticalPositionRelativeToPage];
   HorizPos := Word.Selection.Information[wdHorizontalPositionRelativeToPage];

Dieser Code wird Ihnen die vertikale Position der Auswahl mitteilen – welches der Cursor (Einfügepunkt) ist, wenn kein Text markiert wurde. Die Antwort erfolgt in twips oder 1/1440 eines Inchs. Um die Zeilenzahl, in der sich der Cursor befindet, zu bekommen, verwenden Sie stattdessen dies:

Word.Selection.Information[wdFirstCharacterLineNumber];

Schauen Sie in der VBAWord-Hilfe nach der Information-Eigenschaft, um alle anderen Dinge herauszufinden, die Sie auf diesem Weg ermitteln können. Eine ziemlich lange Liste.
Beispiel-Projekte auf der Website von Deborah Pate (TeamB).

In .NET funktioniert das Öffnen einer Word-Datei so:

var
  WordApp    : Word.ApplicationClass;
  FileName   : System.object;
  EmptyParam : System.object;
begin
  WordApp := Word.ApplicationClass.Create;
  FileName := 'C:beispiel.doc';
  EmptyParam := System.Reflection.Missing.Value;
  WordApp.Documents.Open(FileName, EmptyParam, EmptyParam, EmptyParam,
    EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam,
    EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam,
    EmptyParam);
  WordApp.Visible := True;