Session D-WORD

OLE-Automation mit WinWord und Excel

Rolf Riethmüller
Wizards & Builders GmbH


Abstract

Die Session zeigt die Möglichkeiten der OLE Integration von MS Office Produkten in Visual FoxPro. Im Vordergrund steht die objektbasierte Steuerung von MS WinWord und MS Excel aus Visual FoxPro Anwendungen. Demonstriert wird der Einsatz von OLE und die grundlegende Technik. Gezeigt wird die Ausgabe von Daten in Winword und die Benutzung von Excel als Taschenrechner.

Einführung

Auf vielen PC-Systemen sind die Standardprogramme für Textverarbeitung, Tabellenkalkulation und Terminplanung installiert. Zusätzlich finden wir je nach Aufgabenbereich noch Speziallösungen wie Auftragsbearbeitung und Finanzbuchhaltung. Häufig wurden in diese Individuallösungen auch Funktionen integriert, die auch in den Standardanwendungen zur Verfügung stehen und sind somit in einem EDV-System mehrfach vorhanden.

Das Ziel der Office Automation  ist die Integration der einzelnen Anwendungen eines EDV-Systems. Der Zugriff auf diese Anwendungen soll für den Anwender transparent erfolgen. Die einzelnen Anwendungen sind auf ihren Aufgabenbereich spezialisiert und stellen ihre Funktionalität anderen Anwendungen zur Verfügung. In Verbindung mit einem Dokumentenmanagementsystem können so auch Arbeitsabläufe abgebildet werden.

Einen Ansatz für die Office Automation ist die von Microsoft entwickelte Technik zur Kommunikation zwischen Anwendungen (IAC Interapplication communication) die als DDE und OLE bekannt ist. Diese Techniken stehen jedoch nur unter den Betriebssystemen ab Windows 3.0 zur Verfügung. Die erste verfügbare Technik zur IAC von Microsoft war DDE. OLE ist eine Weiterentwicklung von DDE und stellt einen objektbasierten Ansatz dar, der im Rahmen des COM (component object model) beschrieben ist. Die Integration von Anwendungen in einem Netzwerk ist ebenfalls vorgesehen und steht als Service innerhalb von DCOM (distributet component object model) zur Verfügung.

OLE ist die Kurzform für Object Linking and Embedding. Diese Technik beschreibt die objektbasierte Verknüpfung und Integration von Dokumenten der unterschiedlichsten Anwendungen. Die Version OLE 1.0 unterstützte dies in der Form, daß die Bearbeitung der Dokumente - z. B. ausgelöst durch einen Doppelklick mit der Maus auf das eingebettete Objekt - in den entsprechenden Anwendungen erfolgte. In der Version OLE 2.0 ist das Inplace Editing möglich - die Bearbeitung eines eingebetteten Dokuments erfolgt im Hauptdokument, im Anwendungsfenster des Hauptdokuments erscheint  die Menüleiste der Anwendung des eingebetteten Dokuments.

Mit Hilfe der OLE Technik können wir nun aus den einzelnen Anwendungen eine Gesamtlösung zusammenstellen. Es ist nicht mehr notwendig, Funktionalitäten, die schon in anderen Anwendungen implementiert sind, in eigenen Anwendungen nochmals zu programmieren.

Bei der  DDE und OLE Technik ist zwischen einer Client und Server Applikation zu unterscheiden. Eine Client Applikation ist in der Lage, eine Server Applikation zu steuern. Steht eine Anwendung nur als OLE oder DDE Server zur Verfügung, können deren Objekte nur in Dokumenten von Anwendungen integriert werden, die auch OLE/DDE- Client sind.

Durch die Verbreitung des Internets hat Microsoft nun den Begriff ActiveX eingeführt. Ein ActiveX Control ist nichts anderes als ein COM bzw. OLE Objekt. ActiveX wurde nur aus Marketing Gründen definiert, da der Begriff OLE schon viele Jahre verwendet wird.

Der dynamische Datenaustausch mit DDE

DDE steht für Dynamic Data Exchange. Diese Technik beschreibt die ursprüngliche Möglichkeit zur Kommunikation von Anwendungen unter Windows. Anwendung die noch mit FP 2.6 erstellt sind, haben häufig nur diese Möglichkeit der anwendungsübergreifenden Kommunikation - DDE ist jedoch auch unter VFP verwendbar.

Die Kommunikation per DDE erfolgt über einen Kanal, der mit einem File Handle vergleichbar ist. Die Kommunikation mittels DDE setzt jedoch voraus, daß die Zielanwendung aktiv ist.

Jede weitere Kommunikation erfolgt mit Hilfe dieses Kanals. Nach dem Öffnen eines Kanals kann die Kommunikation zwischen den Anwendungen mit den Befehlen DDExecute durchgeführt werden.

Befehle zur Steuerung von Anwendungen mit DDE von VFP.

Die nachfolgenden Befehle werden zur Kommunikation mit einem DDE-Server eingesetzt. Visual FoxPro enthält noch zusätzliche Befehle um eine VFP Anwendung als DDE Server zu implementieren. Diese Befehle sind in der Auflistung jedoch nicht enthalten.

  • DDESetOption( cOption, Wert

Zweck:                  Setzen der DDE Optionen
Parameter:             String, Option die gesetzt werden soll
Optionen:              Safety, TimeOut
Rückgabe:            Logisch oder Wert der Option

 

  • DDEInitiate( cAnwendung)

Zweck:                  Erstellen eines Kanals zu der Zielanwendung
Parameter:             String, Name der Anwendung, die mit DDE gesteuert werden soll
Rückgabe:            Numerisch, die Kanalnummer zu der Zielanwendung

 

  • DDEExecute ( nKanalnr, cBefehl)

Zweck:                  Ausführen eines Befehl der Zielanwendung.
Parameter:             Numerisch, Verbindungsnummer (Kanalnummer)
                             String , Befehl der von der Zielanwendung ausgeführt werden soll
Rückgabe:            Logical, Gibt an ob der Befehl erfolgreich war

  • DDETerminate( nKanalNr)

Zweck:                  Beenden einer Verbindung
Parameter:             Numersich, Nummer der Verbindung die zu schließen ist
Rückgabe:            Logisch, gibt an, ob die Verbindung getrennt wurde

  • DDERequest( nKanalnr, cTopic)

Zweck:                  Abrufen von Daten aus der Zielanwendung
Parameter:             Numerisch, Verbindungsnummer
                             String, Topic dessen Inhalt abzurufen ist
Rückgabe:            String, Enthält die Daten

·         DDELastError()

Zweck:                  Feststellen des letzten DDE-Fehlers
Rückgabe:            Numerisch, Fehlernummer der bei der letzten DDE-Aktion aufgetreten ist.

Die programmatische Verwendung von DDE

Die Steuerung einer Anwendung mit Hilfe von DDE kann in drei Schritte eingeteilt werden. Zuerst sind die DDE- Optionen zu setzen und zu prüfen, ob die zu steuernde Anwendung bereits aktiv ist. Ist dies nicht der Fall, so muß die Anwendung gestartet werden. Nun kann über ddeInitiate( ) eine Verbindung von VFP zu der Anwendung aufgebaut werden.

Nach dem Ausführen der Bearbeitungsschritte mit ddeExecute( ) ist am Ende die Verbindung mit ddeTerminate() zu trennen.

Der folgende Programmcode zeigt die Prüfung, ob eine Anwendung - in diesem Fall Word - aktiv ist und startet Word falls dies nicht der Fall ist. Wichtig ist die Bezeichnung der Anwendung.

* Fehlermeldungen abschalten
=ddeSetOption( "Safety", .f.)
 
* Prüfen ob WinWord aktiv ist
* lhWord enthält das Verbindungshandle bei erfolgreicher Initialisierung
lhWord= ddeInitiate( "Winword", "System")
if lhWord < 0
   * Winword nicht aktiv und nun als Hintergrundanwendung starten
   run /n7 D:\Programme\Winword\winword
   * Verbindungsaufbau nochmal versuchen
   lhWord= ddeInitiate( "Winword", "System")
   if lhWord < 0
      return
   endif
endif

Der folgende Code zeigt die Erstellung eines Dokuments auf Basis der Vorlage Rechnung.dot. In dieser Vorlage sind die Textmarken Adresse_An, Adresse_Anschrift und Adresse_Ort definiert. Diese dienen zum direkten Setzen des Cursors und dem Einfügen von Daten an diesen Stellen im Rechnungsdokument. Welche Funktionen wir mit DDE benutzen können, ist in der WordBasic Hilfe nachzulesen.

Alle Befehle der Zielanwendung sind mit den Zeichen ‘[ einzuleiten und mit den Zeichen ]’ abzuschließen. Die Argumente eines Befehls sind mit den Anführungszeichen “ “ zu begrenzen. Argumente die in VFP in Variablen oder Tabellenfelder gespeichert sind, müssen mit dem Zeichen & gekennzeichnet werden.

* Neues Dokument auf Basis der Rechnungsvorlage erstellen
if ddeExecute( lhWord, '[DateiNeu "Rechnung"]')
   ? ddeExecute( lhWord, '[BearbeitenGeheZu "Adresse_an"]')
   ? ddeExecute( lhWord, '[Einfügen "Network Consulting GmbH"]')
 
   ? ddeExecute( lhWord, '[BearbeitenGeheZu "Adresse_Anschrift"]')
   ? ddeExecute( lhWord, '[Einfügen "Boschstraße 8"]')
 
   * Und nun den Inhalt einer Variable übergeben
   lcOrt= "64347 Griesheim"
   ? ddeExecute( lhWord, '[BearbeitenGeheZu "Adresse_Ort"]')
   ? ddeExecute( lhWord, '[Einfügen "&lcOrt"]')
 
   * ... weitere Befehle ...
 
   * die Datei Speichern, der Dateiname steht in der Variable lcRngDoc
   ? ddeExecute( lhWord, '[DateiSpeichernUnter "&lcRngDoc"]')
 
   * Die Rechnung drucken
   * optional können weitere Argumente übergeben werden (Kopien etc.)
   ? ddeExecute( lhWord, '[DateiDrucken]')
 
   * Das aktive Dokument (Rechnung) schließen
   * Das Argument 2 unterbindet in diesem Fall den Speicherndialog
   ? ddeExecute( lhWord, '[DateiSchließen 2]')
endif
* Verbindung schließen
? ddeTerminate( lhWord)

Grundlagen zu OLE 2.0

OLE 2.0 ist eine objektbasierte Technik zur Kommunikation zwischen Anwendungen. Visual FoxPro ist in der Lage als OLE Server und Client zu agieren.

Notwendig für die Anwendung der OLE Automation mit VFP ist allerdings eine ausreichende Hardwareumgebung. Die Mindestausstattung eines PCs sollte 24 MB Hauptspeicher oder mehr sein, wobei nicht VFP die Hauptursache ist (ca. 8 MB), sondern Anwendungen wie Excel und Winword benötigen den Hauptteil des Speichers.

Der Einsatz von OLE setzt auch eine korrekte Installation der Anwendungen voraus, die mit OLE gesteuert werden sollen. Bei der Installation werden die notwendigen Einträge in die Registrierdatenbank von Windows eingetragen und stehen so den Client Anwendungen zur OLE Kommunikation zur Verfügung. Diese Eintragungen sind für das Funktionieren der OLE Kommunikation unverzichtbar - im Gegensatz zu DDE.

Das Objektmodell

OLE 2.0 basiert auf Objekthierarchien, die von den Server- Anwendungen zur Verfügung gestellt werden. Leider steht MS Word 95 nicht als Objektmodell zur Verfügung, sondern bietet uns nur den Zugriff auf WordBasic. Echte OLE 2.0 Anwendungen bieten die Möglichkeit auf  alle (öffentlichen) Eigenschaften und Methoden der Objekte in der Objekthierarchie zuzugreifen.

Jede OLE 2.x Anwendung besitzt normalerweise ein Applikationsobjekt, das mehrere Objekte enthalten kann. Diese Hierarchie ist häufig als Collection von Objekten implementiert - dies entspricht einem Array von Objekten. Nachfolgend ist ein Auszug aus der Hilfe zu Visual Basic for Applications (VBA) für Excel dargestellt, der die Objekthierarchie von Excel zeigt.

Abbildung 1: Objektmodell Excel

Die Objekte WorkBook, Worksheet, Chart etc. sind als Collection implementiert. Der Zugriff auf einzelne Objekte einer Collection kann wahlweise über den Index, z. B. WorkBooks( 1), oder den Namen, z. B. Workbooks( “Name“), erfolgen. Ein Element einer Collection entspricht konkret einem Objekt vom Typ der Collection.

Welche Objekte, Methoden und Eigenschaften eine Anwendung beinhaltet, kann in der VBA Hilfe zu der entsprechenden Anwendung nachgelesen werden.

OLE Sessions

Die programmatische Verwendung von OLE (OLE Session) ist von der interaktiven Benutzung der entsprechenden Anwendung zu unterscheiden. OLE Sessions können vollkommen im Hintergrund ablaufen ohne daß der Benutzer die Anwendung wahrnimmt. Interessant ist auch, daß Word 95 nur eine OLE Session zuläßt, Die Office 97 Anwendungen jedoch mehrere unabhängige OLE Sessions ermöglichen. Dies bedeutet in der Praxis, daß in VFP mehrere unabhängige Excel Anwendungsobjekte instanziert werden können. Jedes dieser Objekte kann unterschiedliche Dokumente bearbeiten.

VFP und OLE Objekte

Die Verwendung von OLE in Visual FoxPro ist im Grunde sehr einfach. Zuerst setzen wir die Sprache mit der Funktion SYS( 3005, 1033) auf Englisch. Anschließend wird das gewünschte Objekt mit CREATEOBJECT( „Objektbezeichnung“) instanziert - dies ist sehr häufig das Application Objekt. Oftmals ist mit Hilfe des Application Objekts die grundlegende Arbeitsumgebung einzustellen. Die Dokumente einer Anwendung sind normalerweise als Collection verfügbar und das Erstellen von neue Dokumenten erfolgt über die ADD Methode der Collection. Hier nun ein Beispiel für die Ansteuerung von Word 97 aus Visual FoxPro.

* Sprache einstellen
=sys( 3005, 1033)
 
* Anwendungsobjekt erstellen
oWord= createobject( „Word.Application“)
 
* Prüfen ob erfolgreich ausgeführt
IF isnull( oWord)
   && nicht erfolgreich
endif
 
* Neues Dokument erstellen
* owDok enthält die Referenz auf das neue Dokument
owDok= oWord.Documents.add( <Vorlage>)

OLE und Word 95

Word 95 enthält leider kein echtes Objektmodell sonder besitzt nur die Word Basic Schnittstelle, d.h. die Funktionalität der OLE Schnittstelle ist durch WordBasic gegeben. Das Objekt zur Instanzierung ist WORD.BASIC. Sonstige Objekte stehen für die Instanzierung nicht zur Verfügung. Die Dokumente in Word können nicht als Objekte angesprochen werden, sondern sind mit Hilfe von WordBasic Befehlen zu bearbeiten. Die zur Verfügung stehenden Befehle sind in der Hilfe zu WordBasic beschrieben. Zu beachten ist dabei, daß für die Ansteuerung von Word mittels OLE nur Funktionen, jedoch keine Wordbasic Anweisungen möglich sind. Diese Anweisungen sind nur innerhalb von WordBasic Makros zulässig. Die Verwendung von Word 95 als OLE Server ist so implementiert, daß die Ausführung eines Befehls einem einzeiligen Makro in Word entspricht.

Positiv ist jedoch die Möglichkeit, Objektreferenzen auf die Dialoge von Word 95 innerhalb einer OLE-Session zu erstellen. So können die einzelnen Parameter eines Dialogs relativ einfach abgefragt werden.

Wichtig für das Arbeiten mit OLE und Word 95 ist die installierte Sprachversion. Im Gegensatz zu den vielen OLE 2.0 Anwendungen unterstützt Word nicht die Einstellung der OLE Sprache zur Laufzeit, sonder hängt einzig von der auf dem PC installierten Sprachversion ab.

Visual FoxPro und Word 95

Die Instanzierung eines OLE Objektes in Visual FoxPro erfolgt mit der Funktion CREATEOBJEKT( ). Diese Funktion liefert bei erfolgreicher Instanzierung eine Objektreferenz auf das entsprechende Objekt. Diese Objektreferenz ist nun für die weitere (programmatische) Bearbeitung zu verwenden.

Der Aufbau einer Word 95 OLE Session erfolgt über das Objekt WORD.BASIC. Der folgende Code zeigt die Instanzierung eines Word OLE Objekts.

Instanzierung des Word.Basic Objekts

* Instanzierung einer Word Session
oWord= CreateObject( “Word.Basic“)
 
* Prüfen ob Instanzierung erfolgreich
if isnull( oWord)
   * Instanzierung fehlgeschlagen
   return
endif
 
* Ein neues Dokument auf Basis der Vorlage Rechnung erstellen
* Es wird keine Objektreferenz auf das Dokument erstellt !!!
oWord.DateiNeu( “Rechnung“)
 
* Ein bestehendes Dokument öffnen; hier das Dokument RNG0001.doc
oWord.DateiÖffnen( “Rng0001“)
 
* Und nun das aktive Dokument drucken
oWord.Drucken()
 
* Leider geht das Beenden von Word nicht wie vermutet
oWord.DateiBeenden() && geht leider nicht L
 
* Um Word zu beenden müssen wir Trick siebzehn benutzen
* WordBasic enthält die Funktion AnwSchließen( „Anwendung“), diese war
* allerdings wohl nicht hierfür gedacht.
oWord.AnwSchließen( “Microsoft Word“)
* und weg damit. Wichtig ist hierbei der Titel des Anwendungsfensters.

Im Vergleich zu DDE bietet OLE mit Word 95 nicht viel Neues. Der Unterschied besteht bisher lediglich in der (Zeit) Ersparnis bei der Tipparbeit und der einfacheren Verwendung von Variablen und Tabellenfeldern. Dies verdeutlicht der folgende Code.

* Neues Dokument auf Basis der Rechnungsvorlage erstellen
oWord.DateiNeu( “Rechnung“)
 
oWord.BearbeitenGeheZu( "Adresse_an")
oWord.Einfügen( "Network Consulting GmbH")
 
oWord.BearbeitenGeheZu( "Adresse_Anschrift")
oWord.Einfügen( "Boschstraße 8")
 
* Und nun den Inhalt einer Variable übergeben
lcOrt= "64347 Griesheim"
oWord.BearbeitenGeheZu "Adresse_Ort")
oWord.Einfügen( lcOrt)
 
* ... weitere Befehle ...
 
* die Datei Speichern, der Dateiname steht in der Variable lcRngDoc
oWord.DateiSpeichernUnter( lcRngDoc)
 
* Die Rechnung drucken
* optional können weitere Argumente übergeben werden (Kopien etc.)
oWord.DateiDrucken( )
 
* Das aktive Dokument (Rechnung) schließen
* Das Argument 2 unterbindet in diesem Fall den Dialog zum Speichern
oWord.DateiSchließen( 2)

Dialogparameter abfragen

Die Eigenschaften der diversen Dialoge konnten bisher nur umständlich abgefragt werden. Die OLE Implementation von Word bietet uns nun eine bessere Möglichkeit die aktuellen Parameter zu prüfen. Das Setzen der Parameter ist jedoch immer noch umständlich zu durchzuführen.

* Anzeigen der Dialogparameter Titel und Autor im Dialogfenster
* Datei->DateiInfo
owd= oWord.CurValues.DateiDateiInfo
? owd.Titel
? owd.Autor
 
* Das Setzen der Parameter ist nach wie vor über die entsprechende
* WordBasic Funktion durchzuführen.
OWord.DateiDateiInfo( , “OLE mit Winword und Excel“)
* Thema setzen, generell gilt: die Reihenfolge der Parameter stimmt
* nicht immer mit der Hilfe überein. Nicht anzugebende Parameter müssen
* ohne Wert durch Komma getrennt angegeben werden.

Beispielformular für Dokumenteigenschaften

Ein Beispiel für die Abfrage von Dokumenteigenschaften ist in dem VFP Formular WordInfo.scx enthalten.

Diese Formular instanziert in der INIT-Methode das WordBasic Objekt und weist die Dialogeinstellungen der Formulareigenschaft oWordDlg zu. Die Textfelder des Formulars stellen diese Eigenschaften dar. Das Destroy-Event enthält den Code zur Freigabe der Dialog- und Objektreferenz.

Automation mit Office 97

Die Anwendungen von Office 97 basieren alle auf einem Objektmodell. Die verfügbaren Objekte einer Anwendung können wir der VBA entnehmen - teilweise ist auch eine graphische Abbildung verfügbar. Der Zugriff auf die einzelnen Objekttypen ist normalerweise über eine Collection gelöst - das Hinzufügen und Entfernen von Objekten eines Typs erfolgt häufig über die Collection. Objekte selbst enthalten oftmals weitere Collections.

Finden von Informationen

In der VBA Hilfe sind oftmals Konstanten aufgeführt, deren Wert uns nicht bekannt ist. Abhilfe bietet der VBA Editor: innerhalb des VBA - Editors einer Anwendung finden den Objektkatalog. Mit diesem können wir den Wert von definierten Konstanten herausfinden.

Die wichtigsten Objekte

Das Application Objekt

Das Application Objekt ist das oberste Objekt in der Objekthierarchie einer Anwendung. Dieses Objekt enthält einige sehr nützliche Eigenschaften wie zum Beispiel das aktive Element wie Dokument, Absatz, Zelle etc..und sogar den aktuell eingestellten Drucker (ActivePrinter). Eine interessante Methode in Excel ist Application.Evaluate( ). Diese Methode wertet wie die EVALUATE( ) - Funktion in VFP einen übergeben Ausdruck aus.

Bei der Instanzierung eines OLE- Servers ist das Anwendungsfenster am Bildschirm zuerst nicht sichtbar. Möchten wir dem Anwender das Anwendungsfenster präsentieren so ist die Eigenschaft Visible des Applicationobjects auf TRUE zu setzen.  Die Größe des Anwendungsfenster kann mit den Eigenschaften Top, Left, Height, und Width eingestellt werden

oApplication.Visible= .t.  && oApplication ist eine Referenz auf das Applicationsobject
oApplication.Left= 400  && Linker Rand des Fenster auf Pixel 400
oApplication.Width= 400 && Breite des Fenster 400 Pixel

Collections

Objekte eines Typs sind in Excel meistens als Collection implementiert. Ein Beispiel hierfür sind die einzelnen Tabellenblätter in einer Arbeitsmappe. Der Zugriff auf ein Objekt in einer Collection kann über den Index oder den Namen des Objekts erfolgen. Im anschließenden Beispiel ist der Zugriff auf eine Tabelle (Sheet bzw. WorkSheet) dargestellt.

oExcel.WorkBooks( 1 ).WorkSheets( 1 ).Methode/Eigenschaft
oExcel.WorkBooks( 1 ).WorkSheets(  “Tabelle1“ ).Methode/Eigenschaft

Jedes Objekt besitzt entsprechende Eigenschaften und Methoden. Die wichtigsten Methoden sind Collection.Add( ), Objekt.Open( ), Objekt.Save( ) und Objekt.Close( ). Die ADD Methode liefert eine Referenz auf ein neues Objekt, das in der aktuellen Collection erstellt wird. Mit der CLOSE Methode können wir ein Objekt schließen.

Mit der Eigenschaft Objekt.Application erhalten wir auf jeder Ebene der Objekthierarchie eine Referenz auf das Applicationobjekt und können so dessen Eigenschaften und Methoden verwenden.

Speziell für den Einsatz von Collections steht in Visual FoxPro nun ein neues Programmkonstrukt zur Verfügung: FOR EACH Variable IN Collection. Dies ermöglicht uns die sequentielle Bearbeitung von Objekten in einer Collection.

Die zu verwendete OLE Sprache in VFP einstellen

Im Gegensatz zu Word 95 kann die OLE Ansteuerung nun in Englisch erfolgen - unabhängig der installierten Sprachversion. Das Einstellen der Sprache ist mit dem Befehl SYS( 3005, 1033) durchzuführen.

* Deutsche Spracheinstellung
Sys( 3005, 1031)
 
* Englische Sprache einstellen
sys( 3005, 1033)
 
* OLE Spracheinstellung abfragen
? sys( 3004)

OLE und Winword 97

Word 97 enthält nun ein echtes Objektmodell. Als Alternative steht auch die Word Basic Schnittstelle zur Verfügung und kann für die Umsetzung von älteren Anwendungen verwendet werden. Beim Einsatz von VFP mit Build kleiner 412 muß teilweise WordBasic verwendet werden, da einige Probleme beim Aufruf von Word Methoden zu erwarten sind.

Das Objektmodell besteht aus Objekte wie Application, Document, Paragraph (Absatz) bis zu den einzelnen Zeichen eines Dokuments. Die zur Verfügung stehenden Objekte und Funktionen sind in der VBA Hilfe zu Word beschrieben.

Visual FoxPro und Word 97

Der Aufbau einer Word 97 OLE Session kann über die Objekte Application, Document, Basic, Picture etc. erfolgen. Innerhalb eines Dokuments sind verschiedene Objekte verfügbar: Absätze, Tabellen, Grafiken, Wörter und Zeichen und können mit Angaben zur Formatierung - mit Hilfe des Font Objekts - versehen werden.

Ein Objekt innerhalb einer Collection ist über den Index (Zahl) oder den Namen des Objekts anzusprechen. Das folgende Beispiel zeigt die Verwendung des zweiten Absatzes eines Dokuments: oPar= owDok.Paragraphs(2).

Eine Besonderheit ist das Range Objekt. Dieses Objekt wird verwendet, um Operationen wie kopieren, formatieren etc. durchzuführen.

Benennung der aufgeführten Variablen

Der folgende Code zeigt die Erstellung eines Word Dokuments zur Ausgabe von Daten mit VFP.

Arbeiten mit Word 97

* Instanzierung einer Word Session
oWord= CreateObject( “Word.Application“)
 
* Prüfen ob Instanzierung erfolgreich
if isnull(oWord)
   * Instanzierung fehlgeschlagen
   return
endif
 
* Ein bestehendes Dokument öffnen; hier das Dokument RNG0001.doc
owDok= oWord.Documents.open( “Rng97.doc“)
 
* Ein neues Dokument auf Basis der Vorlage Rechnung erstellen
owDok= oWord.Documents.Add( “Rng97.dot“)
 
* Ein neues Dokument mit der Standardvorlage erstellen
owDok= oWord.Documents.Add()
 
* Format und Seitenränder des Dokuments setzen
with owDok.PageSetup
   .Papersize=    7  && A4
   .Orientation= 0  && Portrait
 
   * Die Seitenränder sind in Punkten anzugeben
   .LeftMargin=   oWord.CentimetersToPoints( 2.5)
   .RightMargin=  oWord.CentimetersToPoints( 2)
   .TopMargin=    oWord.CentimetersToPoints( 2.5)
   .BottomMargin= oWord.CentimetersToPoints( 2)
endwith
 
* Cursor an den Anfang des Dokuments setzen
oRange= owDok.Paragraphs(1).Range
 
* Eine Tabelle mit 3 Spalten und 5 Zeilen hinzufügen
oTable= owDok.Tables.add( oRange, 5, 3)
 
* Die Spaltenbreiten festlegen
oTable.Columns(1).Width= oWord.CentimeterToPoints( 8)
oTable.Columns(2).Width= oWord.CentimeterToPoints( 2)
oTable.Columns(3).Width= oWord.CentimeterToPoints( 6)
 
* Zeilenhöhe der Tabelle einstellen
lnHeight= oWord.CentimeterToPoints( 1)
for each oRow in oTable.Rows
   oRow.Height= lnHeight
   oRow.HeightRule= 2 && exact
endfor
 
* und nun die Tabelle füllen, kann natürlich auch mit Daten einer DBF sein
oTable.Cell( 1, 1).Range.Text= “Network Consulting GmbH“
oTable.Cell( 2, 1).Range.Text = “Herrn Riethmüller“
oTable.Cell( 3, 1).Range.Text = “Boschstraße 8“
oTable.Cell( 5, 1).Range.Text = “64347 Griesheim“
 
* Und nun das Dokument drucken
owDok.PrintOut()  && alternativ PrintPreview()
 
* Dokument speichern
owDok.SaveAs( “Rng97001“)
 
* Word beenden
oWord.Quit()   && Parameter 0= ohne Speichern beenden

Beispiel für Dokumenteigenschaften und Felder

In Word 97 können den Dokumenten zu den vorhandenen Eigenschaften auch benutzerdefinierte Eigenschaften erstellt werden. Dies ist zum Beispiel für Serienbriefe oder ähnliches sinnvoll.

* Dokumenteigenschaften hinzufügen
owDok.CustomDocumentProperties.Add( "AdrName", .f., 4, "Riethmüller")
owDok.CustomDocumentProperties.Add( "AdrVName", .f., 4, "Rolf")
 
* Einen Absatz hinzufügen
owDok.Paragraphs.add()
oRange= owDok.Paragraphs(1).Range
 
* Ein Feld in das Dokument einfügen
* Field.Type: DokumentProperties = 85
owDok.Fields.add( oRange, 85, "AdrName")
 
* Felder im Dokument aktualisieren
owDok.Fields.Update

Automation mit Excel

In Excel ist ein vollständiges Objektmodell zur Steuerung mit OLE enthalten. Dieses Objektmodell ist in Abbildung 1 dargestellt. Die einzelnen Komponenten wie Arbeitsmappen (Workbooks) und Tabellenblätter (Worksheets) von Excel finden wir auch als Objekte im Objektmodell wieder. Zum Teil können diese Objekte direkt instanziert werden. Die in Excel enthaltenen Tabellenfunktionen für die Summenbildung und stat. Auswertungen stehen ebenfalls zur Verfügung.

Die wichtigsten Objekte bei der Steuerung von Excel mit OLE sind das Application Objekt, das WorkBook Objekt, das WorkSheet Objekt und das Range Objekt. In der Windows Registrierdatenbank sind die direkt instanzierbaren Objekte eingetragen.

Eine Beschreibung der Objekte, Methoden, Eigenschaften und Funktionen ist in der VBA_XLS.HLP zu finden. In dieser Hilfe sind die Bezeichnungen der Objekte, Eigenschaften und Methoden in Englisch und der Hilfetext in Deutsch dargestellt. Bei der Verwendung der englischen Definitionen können wir in der Datei VBAListe.xls die Namen der englischen Tabellenfunktionen nachschlagen.

Steuerung von Excel mit VFP

Die Vorgehensweise für die Ansteuerung von Excel aus VFP ist im Prinzip wie bei der Ansteuerung von Word. Die folgenden Beispiele verdeutlichen die einfache Benutzung von OLE  2.0 zur Steuerung  von Excel.

Die Methoden zum Öffnen und Hinzufügen von Excel-Dokumenten liefern bei erfolgreichem Aufruf eine Referenz auf das neue Objekt zurück. Diese Referenz ermöglicht uns nun den direkten Zugriff auf ein solches Objekt. Die

Beschreibung der verwendeten Variablen

Arbeiten mit Excel

Die in der Registrierdatenbank eingetragenen Excel - Objekte können direkt instanziert werden. Möchten wir Excel nur als Funktionsbibliothek oder  Taschenrechner einsetzen, reicht die Instanzierung des Sheet - Objekts aus, da dieses auch eine Referenz auf das Applicationobject enthält und so indirekt die Evaluate( ) - Methode verwendbar ist.

* nur das Applikationsobjekt instanzieren
* Es sind nun keine Arbeitsmappen oder Tabellen geöffnet
oxApp= CreateObject( “Excel.Application“)
 
* Name der Anwendung ausgeben
? oxApp.Name   && Alternativ ist auch oxApp.Caption möglich
 
* Alternativ gleich ein Tabellenblatt instanzieren
oxSheet= CreateObject( “Excel.Sheet“)
 
* Anwendungsfenster von Excel anzeigen
oxApp.Visible= .t.
 
* Anwendungsfenster von Excel verbergen
oxApp.Visible= .f.
 
* falls wir direkt ein Sheet instanziert haben
oxSheet.Application.Visible= .t. && Anwendungsfenster anzeigen
 
* oder zuerst die Referenz in ox speichern und anschließend Visible setzen
oxApp= oxSheet.Application
oxApp.Visible= .t.
 
* Und nun die Evaluate Funktion anwenden
? oxApp.Evaluate( “sum( 1, 2, 3, 4, 5, 6)“)  && Ergebnis sollte 21 sein
 
* Und Excel wieder schließen
oxApp.quit()

Arbeitsmappen erstellen, öffnen, speichern und schließen

* Eine neue Arbeitsmappe mit einer Tabelle erstellen
oxApp.SheetsInNewWorkBook= 1  && Eigenschaft des Applicationobjects
oxBook= oxApp.Workbooks.add()
 
* Eine Arbeitsmappe öffnen, Referenz in oxBook speichern
oxBook= oxApp.Workbooks.Open( “D_OLEXLS“)
 
* ohne zu speichern das aktuelle Dokument schließen
oxBook.close( 2)  && Der Parameter 2 unterbindet den Dialog Speichern
 
* Name der Arbeitsmappe ausgeben
* Der Index eines neuen Objekts innerhalb der Collection ist 1
? oxBook.Name
? oxApp.Workbooks(1).Name

Mit Tabellen und Zellen arbeiten

* Eine Tabelle hinzufügen und die Referenz in oxSheet speichern
oxSheet= oxBook.Sheets.add()

 
* Name der Tabelle ausgeben
? oxSheet.Name
? oxBook.Sheets( 1).Name   && neue Objekte erhalten den Index 1
 

* Und nun die Zellen bearbeiten
oxSheet.Range( “A1“).Value= 10
oxSheet.Range( “B1“).Value= 11
 

? oxSheet.Range( “A1“).Value
? oxSheet.Range( “B1“).Value
 

* und nun eine Formel in A3 eingeben
* Vorsicht: englische Tabellenfunktionen benutzen
*           Argumenttrennung mit Komma!!
oxSheet.Range( “C1“).Formula= “=sum( A1, B1)“
 

* Mal schaun was nun drinsteht
? oxSheet.Range( “C1“).Value
 

* und nun einen Zellbereich mit einer Formel füllen
* Effekt ist die automatische Anpassung der Formel wie beim interaktiven
* Arbeiten mit Excel
oxSheet.Range( “A2:C2“).Formula= “=$A1*A1“
? oxSheet.Range( “A2“).Value
? oxSheet.Range( “B2“).Value
? oxSheet.Range( “C2“).Value
 

* Eine Referenz auf einen Zellbereich erstellen, hier die Zelle B2
oxCells= oxSheet.Range( “B2“) && Referenz auf die Zelle B2
? oxCells.Value               && Wert der Zelle B2 ausgeben

Die hier vorgestellten Beispiele sind nur ein kleiner Auszug der Möglichkeiten die uns mit OLE zur Verfügung stehen. So können wir den Zellbereichen Namen zuweisen und diese Namen in Tabellenfunktionen wie z. B. SUM( ), AVG( ), MEDIAN( ) etc. verwenden. Jedes Bereichsobjekt besitzt die Eigenschaften Borders und Style, die eine Referenz auf ein Objekt darstellen. Mit Hilfe dieser Referenzen können wir die Zellen formatieren.

Übergabe von Datensätze an Excel

Das Applikationsobjekt von Visual FoxPro 5.0 ( _VFP) enthält eine Methode zur Übergabe von Datensätzen in das Windows Clipboard: _VFP.DataToClip.

Das folgende Beispiel erstellt zuerst eine Liste der zehn umsatzstärksten Kunden. Anschließend werden diese zehn Datensätze in die Zwischenablage kopiert und in Excel eingefügt. Die verwendeten Tabellen sind die mitgelieferten Beispiele von Visual FoxPro.

Zu beachten sind die Parameter bei DataToClip: Alias, Datensätze, Trennzeichen

SELECT TOP 10 Customer.company, sum( Orders.order_amt) as Gesamt;
   FROM  testdata!customer LEFT OUTER JOIN testdata!orders ;
   ON  Customer.cust_id = Orders.cust_id;
   GROUP BY Customer.cust_id;
   ORDER BY 2 DESC ;
   INTO CURSOR _cTopTen
 
* und nun die 10 Datensätze in das Clipboard kopieren
_vfp.DataToClip( “_cTopTen“, _tally, 3)   && die 3 für Tab-Trennung
 
* Datensätze in Excel einfügen
oxApp.ActiveSheet.Range( “A2“).Select     && Zelle A2 auswählen
oxApp.ActiveSheet.Paste()                 && und die Datensätze einfügen
 
&& oxCells erhält die Referenz auf den eingefügten Bereich
oxCells= oxApp.Selection
 
* und nun noch ein Autoformat
oxCells.Autoformat(11)  && immer zwei Reihen farblich anders
 
* Die aktuelle Arbeitsmappe speichern
ox.ActiveWorkBook.saveAs( “D_OLEXLS“)
 
* Die Summe über die Umsätze der Top 10
* Die erste Zeile enthält die Spaltenköpfe (Feldnamen)
? oxApp.Application.Evaluate( "sum( B2:B11)")
 
* Excel Beenden
oxApp.Quit

Ein Taschenrechner in VFP

Mit den vorgestellten Beispielen können wir nun einen kleinen Taschenrechner bauen. Dazu erstellen wir ein neues VFP - Formular und fügen diesem die Eigenschaft oExcel zu. Diese Eigenschaft erhält im Init des Formulars die Referenz auf das Excel - Objekt. Sollte wieder erwarten etwas schiefgehen - das Objekt kann nicht instanziert werden - muß die Init- Methode den Wert FALSE zurückliefern. Außerdem fügen wir noch die Eigenschaften cFormel und cErgebnis hinzu.

Auf das Formular plazieren wir nun eine Editbox und ein Textfeld sowie einen Button zum Beenden. Im Click Event des Buttons schreiben wir ein THISFORM.Release um das Formular zu schließen. Im QueryUnload Event des Formulars fügen wir die Zeile This.oExcel.Quit ein um Excel zu beenden.

Die Controlsource der Editbox setzen wir auf  thisform.cFormel, die ControlSource der Textbox ist thisform.cErgebnis. Das Valid Event der Editbox erhält die Zeilen.

thisform.cErgebnis= thisform.oExcel.Evaluate( thisform.cFormel)
thisform.Refresh( )

Prinzipiell ist unser Taschenrechner nun fertig. Dieser Taschenrechner ist als D_OLEXLS.scx auf den Beispieldisketten enthalten.

Tips & Tricks

1. Abfragen ob die Anwendung aktiv ist

Mit Hilfe der vorgestellten DDE Technik kann abgefragt werden, ob eine Anwendung schon aktiv ist.

2. Prüfen welche Version installiert ist

Über die Registry können wir herausfinden, welche Version einer Anwendung installiert ist. Im Normalfall ist die Anwendungsversion an der Nummer hinter den registrierten Objekten erkennbar - z. B. Word.Application.8. In den Solutions Beispielen von VFP ist eine entsprechende Abfrage enthalten.

Außerdem kann über die Registry herausgefunden werden, wo die Serveranwendung installiert ist.

3. Einstellen der Sprache

Mit der Funktion SYS( 3005, Sprache) kann die Ansteuerung von OLE-Objekten in Englisch eingestellt werden.

4. Benutzen von WordBasic

Bei Verwendung von VFP 5.0 Build < 412 gibt es Problemen bei der Ansteuerung von Word 97. So ist z. B. die Funktion SaveAs() nicht einsetzbar. Durch die Verwendung des WordBasic Objekts kann dies aber umgangen werden: oWordApp.WordBasic( “FileSaveAs[ Dokument]“)

5. Arbeiten mit Collections

Eine Collections in der Anwendung kann mit Hilfe einer FOR ... EACH Schleife bearbeitet werden:

FOR EACH loDok in oWord.Documents()
   loDok.Save()
ENDFOR
 
* Alternativ kann das Property Count ausgewertet werden
lnCount= oWord.Documents.Count
for lni= 1 to lnCount
   oWord.Documents.save()
endfor

6. VFP 5.0a Build 412

Den Konferenzunterlage ist die Version VFP 5.0a Build 412 beigelegt, mit der die unter Punkt 4 genannten Probleme beseitugt sind.

7. Debugging mit VFP

Beim Testen von Anwendungen mit OLE Automation sollte der Debugger im VFP Frame gestartet werden. Sonst ist ein Absturz von VFP möglich.

Zusammenfassung

Der Einsatz von OLE bietet uns eine Fülle von Möglichkeiten, unsere Anwendungen ohne großen Aufwand mit neuen Funktionen zu versehen. So können wir zum Beispiel mit Hilfe der OLE- Technik Anwendungen für das Dokumentenmanagement in VFP realisieren.

An den Beispielen können wir sehen, wie einfach der Umgang mit OLE sein kann. Endlich kann auch in Word 97 mit Objekten gearbeitet werden - notwendig für internationale Anwendungen ist die sprachunabhängige Implementierung der Schnittstelle von Word.

Weitere OLE Anwendungen sehen sie von Norbert Abb und Ted Roche. Diese Konferenz zeigt in anderen Vorträgen auch die Verwendung von Visual FoxPro als OLE Server. Dieses Feature ermöglicht uns die Bereitstellung von Funktionalitäten die in unseren Anwendungen implementiert sind.