MS Office Automation

Gespeichert von Lemmy am So., 16.09.2018 - 19:40

Wer Delphi 5 (oder neuer) sein Eigen nennt, kann damit sehr einfach und schnell das komplette Office fernsteuern, angefangen vom Starten der Applikationen bis hin zu Aufrufen verschiedener Funktionen.

Word - Die erste Anwendung
In eine neue Anwendung werden zwei TButtons sowie eine TWordApplication hinzugefügt, der erste bekommt die Caption "Starten" und der andere "Beenden". Die Eigenschaft FormStyle des Formulars wird auf "fsStayOnTop" gesetzt. In die Ereignisroutine OnClick der Buttons kommt folgender Code: Button Starten:


procedure TForm1.Button1Click(Sender: TObject);
begin
WordApplication1.Connect;
WordApplication1.Visible:=true;
end;

Button Beenden:

procedure TForm1.Button2Click(Sender: TObject);
begin
WordApplication1.Quit;
WordApplication1.Disconnect;
end;

Anschließen kannst Du die Mini-Applikation gleich ausprobieren. Nach einem Klick auf den Button "Starten" wird Word gestartet und wartet auf weitere Aktionen. Nach einem Klick auf "Beenden" wird Word wieder geschlossen. Ist Word schon offen wird keine neue Instanz geöffnet. Wurde eine Instanz manuell (über das Startmenü) geöffnet, wird diese beim Klick auf "Beenden" auch geschlossen. Bei Word97 funktioniert der Wechsel zwischen automatischer und manueller Bedienung allerdings nicht. Das Problem liegt in einer fehlerhaften Implementierung bei Word. In einem solchen Fall bleibt nur die Lösug das Delphi-Programm zu schließen bzw. diesen Mischmasch gar nicht zu machen Ach ja, ich glaube Anmerkungen zu den 4 Zeilen Code kann ich mir sparen....

Datenübergabe an Word
Zwei der wichtigsten Anwendungen der Automation-Server ist der Seriendruck und die Erstellung eines Dokuments, das Daten aus einer Delphi-Anwendung erhält.

Der Seriendruck
Als Grundlage hierzu benötigt man ein entsprechend vorbereitetes Dokument und die dazugehörige Datendatei, am einfachsten eine CSV-Datei, die sehr einfach mit Delphi erstellt werden kann. Als Vorlage kannst Du die beiden mitgelieferten Dateien (Daten.txt und SerienDruck.doc) im Sourceverzeichnis verwenden. Evtl. musst Du das *.doc vorher noch in Word öffnen und die Datendatei wegen der Pfadänderung noch mal neu verknüpfen. Wenn beim Öffnen des Dokumentes eine Fehlermeldung kommt, einfach auf "Datenquelle suchen" klicken und "Date.txt" im Projektverzeichnis auswählen. Nun geht's an die Anwendung. Füge in ein neues Projekt eine TWordApplication, eine TWordDocument, ein TOpenDialog und eine TButton-Komponente ein. Die Caption des Buttons wird in "Seriendruck" geändert. In das OnClick-Ereignis des Buttons kommt:

procedure TForm1.Button1Click(Sender: TObject);
var
FileName, NewFile : OleVariant;
Mail : MailMerge;
Pause : OleVariant;
begin
if OpenDialog1.Execute then
FileName:=OpenDialog1.FileName
else
exit;
NewFile:=ExtractFilePath(FileName)+'Brief.doc';
WordApplication1.Connect;
WordApplication1.Documents.OpenOld(FileName, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam,
EmptyParam);
WordDocument1.ConnectTo(WordApplication1.ActiveDocument);
WordApplication1.Visible:=True;
Pause:=True;
Mail:=WordDocument1.MailMerge;
Mail.Destination := wdSendToNewDocument;
Mail.Execute(Pause);
ShowMessage('Fertig');
WordDocument1.Close;
WordDocument1.Disconnect;
WordDocument1.ConnectTo(WordApplication1.ActiveDocument);
WordDocument1.SaveAs(newFile);
WordDocument1.Disconnect;
WordApplication1.Quit;
WordApplication1.Disconnect;
end;

Die Parameter die bei COM Verwendung finden, sind vom Typ OleVariant. Ab Delphi 4 steht für leere Parameter der spezielle Platzhalter EmptyParam zur Verfügung.
Als erstes wird die Anwendung mit Word verbunden und das vorgefertigte Dokument geöffnet. Anschließend wird TWordDocument mit dem Dokument verbunden. Nun wird ein Inteface-Zeiger auf das Mail-Objekt gesetzt (Mail:=WordDocument1.MailMerge;), mit dem die eigentliche Funktion schließlich aufgerufen wird (Mail.Execute(Pause);). Nun kann das Original geschlossen werden und die TWordDocument Komponente mit dem fertigen Serienbrief verknüpft werden, das unter dem angegebenen Namen abgespeichert wird. Zum Schluss wird Word geschlossen.

Datenübergabe mittels Textmarken
Im letzten Beispiel soll eine Rechnung erstellt werden. Als Datengrundlage steht hier normalerweise eine Datenbank. Hier werde ich aber "nur" hart-codierte Daten verwenden. Zuerst musst Du aber das Dokument vorbereiten. Um Daten empfangen zu können, müssen in das Dokument Textmarke eingefügt werden. Diese Textmarke bekommen eindeutige Namen, über die auf die Textmarken zugegriffen werden können. Positioniere den Cursor im Dokument an der Stelle, an der die Daten erscheinen sollen. Klicke anschließend im Menü auf Einfügen -> Textmarke. Gib einen Namen ein und klicke auf "Hinzufügen". Das Fenster schließt sich wieder. Wenn im Dokument nichts zu sehen ist, klicke im Hauptmenü auf Extras -> Optionen und aktiviere unter "Anzeigen" die Textmarken. Nun müsste an der Stelle, an der Du die Textmarke eingefügt hast, ein senkrechter Strich erscheinen. Füge nun weitere Textmarken in das Dokument ein. Die Textattribute an der Stelle der Textmarken können natürlich nach Belieben gesetzt werden. Speichere anschließend das Dokument ab.

Öffne in Delphi eine neue Anwendung und füge wieder eine TWordApplication, eine TWordDocument, ein TOpenDialog und eine TButton Komponente in das Formular ein. In das OnClick-Ereignis kommt:


procedure TForm1.Button1Click(Sender: TObject);
var FileName:OleVariant;
vWhat, vBookmark:OleVariant;
begin
if OpenDialog1.Execute then
FileName := OpenDialog1.FileName
else
exit;
WordApplication1.Connect;
WordApplication1.Documents.OpenOld(FileName, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam);
WordDocument1.ConnectTo(WordApplication1.ActiveDocument);
WordApplication1.Visible := True;

vWhat:=wdGoToBookmark;
vBookmark:='Name';
WordApplication1.Selection.GoTo_(vWhat,emptyParam,emptyParam,vBookmark);
WordApplication1.Selection.TypeText('Max Mustermann'#13'Dorfstraße 100');
End;

Nach dem altbekannten Aufruf von Word und dem Laden des vorbereiteten Dokuments, werden die benötigten Variablen vorbereitet. vWhat bezeichnet die Art des Objektes zu dem gesprungen werden soll und vBookmark bezeichnet den Namen des Objektes, in unserem Fall den Namen der Textmarke. Mit dem Funktionsaufruf WordApplication1.Selection.GoTo_ wird zu dem Objekt gesprungen und der Text mit WordApplication1.Selection.TypeText der Text an Word übergeben. Dabei können auch mehrzeilige Texte übergeben werden, indem #13 mit in den String eingebaut wird.

Fernsteuerung mit Excel
Als zweite Applikation stelle ich noch kurz Excel vor. Excel besitzt im Office-Packet eine Sonderstellung. Da es schon immer eigene Wege gegangen ist (die Makrosprache ist zum Beispiel nicht mit Word kompatibel), gibt es auch bei der Automation große Unterschiede zu Excel. Bei der ersten Anwendung soll zunächst nur Excel geöffnet werden. Füge eine TExcelApplication und 2 TButton Komponenten in das Formular ein. In das OnClick Ereignis des "Starten" Buttons kommt:


procedure TForm1.Button1Click(Sender: TObject);
begin
flcid:=GetUserDefaultLCID;
ExcelApplication1.Connect;
ExcelApplication1.Visible[flcid]:=true;
ExcelApplication1.UserControl:=true;
end;

und in den "Beenden" Button:


procedure TForm1.Button2Click(Sender: TObject);
begin
ExcelApplication1.Quit;
ExcelApplication1.Disconnect;
end;

Du siehst, die Startprozedur von Excel unterscheidet sich schon sehr von Word. Als erstes benötigt man einen locale-identifier, eine Sammlung von sprachspezifischen Daten, die Windows über die API-Funktion GetUserDefaultLCID zur Verfügung stellt (flcid ist vom Typ Integer). Zusätzlich sollte immer neben der Eigenschaft visible auch die Eigenschaft UserControl gesetzt werden.

Daten an Excel übergeben
Nachdem wir Excel aufgerufen haben, können wir Daten an Excel übergeben. Dazu hier ein kleiner Einschub:
Wie oben schon angedeutet, ist Excel einfach anders als Word. Das betrifft auch die Objektstruktur. Gibt es bei Word eine TWordApplikation und ein TWordDocument, sieht die Unterteilung in Excel so aus:
Eine ExcelApplication hat eine Sammlung von Workbooks. Jedes Workbook hat wiederum eine Sammlung von WorkSheets. Diese Worksheets sind schließlich gleichbedeutend wie das Dokument in Word, dort werden also die Daten eingetragen. Das Worksheet hat allerdings wiederum eine große Anzahl von weiteren Objekten z.B. Shapes, auf die zugegriffen werden kann. Füge eine TExcelWorkbook-, eine TExcelWorksheet-Komponente und einen weiteren TButton in die Applikation ein. Der Button bekommt die Caption "Öffnen" und folgenden Code in das OnClick-Ereignis:


procedure TForm1.Button3Click(Sender: TObject);
var sValue,filename:String;
begin
filename:=ExtractFilePath(ParamStr(0))+'Mappe1.xls';
ExcelWorkbook1.ConnectTo(ExcelApplication1.Workbooks.Open(filename,
emptyParam,emptyParam,emptyParam,emptyParam,emptyParam,emptyParam,
emptyParam,emptyParam,emptyParam, emptyParam, emptyParam,
emptyParam, flcid));
ExcelWorksheet1.ConnectTo(ExcelWorkbook1.Sheets.Item[1] as ExcelWorkSheet);
sValue:=ExcelWorksheet1.Range['B1','B1'].Value;
messagedlg(sValue,mtInformation,[mbOK],0);
end;

Die Methode ExcelApplication1.Workbooks.Open hat als Rückgabewert ein Objekt vom Typ TWorkBook. Dadurch kann man unsere TExcelWorkbook Instanz direkt mit der geöffneten Datei verbinden. Bei dieser Methode muss wieder die flcid mit übergeben werden! Anschließend kann das WorkSheet verknüpft werden. Da aber ExcelWorkbook.Sheets.Items[] als Rückgabewert eine Variable des Typs IDispatch besitzt, TExcelWorksheet..ConnectTo() aber einen Parameter vom Typ _WorkSheet benötigt, muss eine Typumwandlung stattfinden. Dies geschieht durch den Aufruf von as ExcelWorkSheet. Nun kann mit ExcelWorksheet1.Range[].Value der Wert der einzelnen Zellen herausgelesen werden.

Da wir nun Zugriff auf die Zellen haben, können wir daran gehen, Daten an Excel zu übergeben: Setzte einen weiteren TButton in das Formular mit der Caption "Datenübergabe". In das OnClick-Ereignis kommt:


procedure TForm1.Button4Click(Sender: TObject);
var oleArray:OleVariant;
begin
OleArray:=VarArrayCreate([0,3],varVariant);
OleArray[0]:=10;
OleArray[1]:=20;
OleArray[2]:=30;
OleArray[3]:=40;
ExcelWorksheet1.Range['B3','E3'].Value:=OleArray;
ExcelWorksheet1.Range['F3','F3'].Formula:='=SUM(B3..E3)';
end;

Zunächst wird ein Array vom Typ OleVariant definiert. Dieses wird dann mit den Werten gefüllt. Mit einer einfachen Zuweisung (ExcelWorksheet1.Range['B3','E3'].Value:=OleArray;) werden die Daten an Excel übergeben. Neben Zahlen und Buchstaben kannst Du natürlich auch eine Formel an Excel übergeben. Dabei hast Du auf alle in Excel definierten Funktionen zugriff, Du musst lediglich die Notation kennen.

Zusammenfassung
So, die grundsätzlichen Zugriffsmöglichkeiten sind hiermit aufgeführt. Alles aufzuführen würde den Rahmen eines Einführungstutorial sprengen, vor allem aber meine zur Verfügung stehende Zeit. Wer sich dafür mehr interessiert, sollte das Buch [1] lesen, bzw. die beiden Artikel in der Zeitschrift "Der Entwickler" [2,3].

Hier sei mir auch ein Abschweif erlaubt: OpenOffice/LibreOffice fühlt sich hier wesentlich integrierter an. Der Aufruf der Anwendung ist immer identisch, die unterschiedlichen Dokumententypen (Tabelle, Schriftstück, usw.) sind lediglich unterschiedliche Typen. Wer sich dafür näher interessiert, ich habe inzwischen bei Sourceforge ein Projekt eingerichtet.

Wer Fehler findet, Anmerkungen oder Anregungen hat sowie Kritik äußern will, kann sich vertrauensvoll an die unten angegeben Email wenden.

Wolfgang Lemmermeyer, 17.06.2001 überarbeitet 03.10.2006, überarbeitet 2.4.2011

Literatur:
[1] Andreas Kosch "COM / DCOM / COM+ mit Delphi", erschienen im Software & Support Verlag
http://www.amazon.de/dp/3935042019?tag=wwwdelphituto-21&camp=1410&creati...

Quellenangabe:
[2] Andreas Kosch "Objekte zu vermieten", Software & Support Verlag, Zeitschirft "Der Entwickler" Ausgabe 2.2000 März/April
[3] Andreas Kosch "Tabellen Automat", Software & Support Verlag, Zeitschrift "Der Entwickler" Ausgabe 3.2001 Mai/Juni

lemmy @delphi-tutorials.de