Die Entwicklung von leistungsfähigen Star-Office-6-Makros droht an Suns unzureichender Programm- Dokumentation zu scheitern. Unsere Tipps für VBA- und andere an Objekten orientierten Basic-Aktivisten erleichtern den Ein- und Umstieg.
Wer als VBA-Entwickler beispielsweise Makros für Microsoft Word entwickelt, sieht sich mit einem geschlossenen Objektmodell konfrontiert. Es besteht aus zahlreichen Objekten, die jeweils ein bestimmtes Element der Anwendung repräsentieren. So gibt es das »Selection«-Objekt, das die aktuelle Textmarkierung darstellt, oder das »Documents«-Objekt, eine Auflistung aller geöffneten Dokumente. Diese Objekte lassen sich direkt aus dem Quelltext heraus ansprechen, im unmittelbaren Zugriff auf ihre Eigenschaften und Methoden.
In Star Office 6 gibt es keine geschlossene Objektwelt (mehr). An deren Stelle ist das Star-Office-API getreten, eine an Komponenten reiche und in Modulen geordnete Bibliothek, die dem Entwickler keine Objekte, sondern Services anbietet (Abbildungen 1 und 2). Jeder dieser Dienste stellt ein Interface (eine Schnittstelle) sowie Properties (Eigenschaften) zur Verfügung, über die man jeweils auf ein bestimmtes Programmfeature zugreifen kann. Der wesentliche Unterschied zu Objekten ist, dass ein Service nicht direkt abrufbar ist. Stattdessen muss der Programmierer ein Objekt anlegen und diesem dann einen Verweis auf den gewünschten Service zuweisen.
Das im folgenden Tipp beschriebene Verfahren dürfte vom Grundsatz her auch VBA-Entwicklern bekannt sein, die schon mal ein ActiveX-Control oder eine andere COM-Komponente in ihre Makros eingebunden haben.

Abbildung 1: Das Star-Office-API bietet seine Funktionen in Form von Services an, auf die man über selbst erstellte Objektvariablen zugreift. (Quelle: Sun Microsystems)

Abbildung 2: Die zahlreichen Services des Star-Office-API sind in Modulen untergebracht, deren Namen man für den Aufruf eines Service kennen muss. (Quelle: Sun Microsystems)
Tipp 1: Dienste einbinden I
Zum Einbinden eines Services ist immer eine Objektvariable erforderlich, die wie folgt zu deklarieren ist:
Dim objIrgendEinService As Object
Das weitere Vorgehen unterscheidet sich je nachdem, ob ein kontextabhängiger oder -unabhängiger Service vorliegt. Zum Einrichten eines Verweises auf einen unabhängigen Service dient die Funktion »createUnoService«, der der Name des gewünschten Dienstes übergeben wird. Der setzt sich aus drei Bestandteilen zusammen: dem stets gleichen Pfad »com.sun.star«, dem Namen des API-Moduls, das den Service bereitstellt (Tabelle 1), sowie dem Namen des Services selbst.
Das Modul »drawing« etwa enthält einen Service namens »ColorTable«, der den Zugang zur Star-Office-eigenen Farbpalette freimacht. Der vollständige Service-Name lautet »com.sun.star.drawing.ColorTable«. Die folgende Zeile richtet einen Verweis auf den Service ein und speichert ihn in der zuvor deklarierten Objektvariablen »objColorTable«:
objColorTable = createUnoService
("com.sun.star.drawing.ColorTable")
Tipp 2: Dienste einbinden II
Kontextabhängige Services stehen nur in Verbindung mit Dokumenten zur Verfügung, genauer: Sie werden von diesen bereitgestellt. Um etwa den »Text«-Service zu nutzen, der Zugriff auf die Inhalte eines Star-Writer-Dokuments erlaubt, ist zunächst ein Verweis auf das Dokument nötig. Den erhält man über das Öffnen eines vorhandenen (siehe Tipp 3) oder das Anlegen eines neuen Dokuments (Tipp 4). Am einfachsten ist es, einen Verweis auf das aktuelle Star-Office-Dokument zu bekommen. Dazu genügt in Star Basic die Zuweisung des Schlüsselworts »ThisComponent« an eine zuvor deklarierte Objektvariable:
objDokument = ThisComponent
Die Objektvariable »objDokument« liefert den kontextabhängigen Service »Text«, der nur noch einer weiteren (natürlich ebenfalls zuvor angemeldeten) Objektvariablen zugewiesen sein will:
objText = objDokument.Text
Tipp 3: Ein vorhandenes Dokument öffnen
Der kontextunabhängige Service »Desktop« liefert dem Entwickler die Funktionen des (virtuellen) Star-Office-Desktops. Unter anderem verfügt er über die Methode »loadComponentFromURL«, die ein vorhandenes Star-Office-Dokument öffnet. Die Methode benötigt einen Verweis (siehe Tipp 2) auf den Service, der wie folgt beschaffbar ist:
Dim objDesktop As Object
objDesktop = createUnoService
("com.sun.star.frame.Desktop")
Beim Aufruf ist der Methode die URL (siehe Tabelle 2) der zu öffnenden Datei – zum Beispiel »file:///home/ralf/Artikel.sxw« – zu übergeben. Weitere Argumente sind der Text »_blank«, eine Null sowie ein leeres Variant-Array. Im Erfolgsfall liefert die Methode einen Verweis auf das geöffnete Dokument zurück, der in einer Objektvariablen zu speichern ist:
Dim objDokument As Object objDokument = objDesktop .loadComponentFromURL( "file:///home/ralf/Test.sxw", "_blank", 0, vntNoArgs())
Tipp 4: Ein neues Dokument anlegen
Die »loadComponentFromURL«-Methode des »Desktop«-Service ermöglicht nicht nur das Öffnen eines vorhandenen (siehe Tipp 3), sondern auch das Anlegen eines neuen Dokuments (siehe Abbildung 3). Dazu ist ihr eine besondere URL zu übergeben, die mit »private:factory/« beginnt und mit einem der folgenden Bezeichner für die Art des anzulegenden Dokuments endet:
- »swriter«: Textdokument
- »scalc«: Tabellendokument
- »draw«: Zeichnung
Die folgende Befehlszeile ermöglicht demnach das Anlegen eines neuen Star-Writer-Dokuments:
objTextDokument = objDesktop .loadComponentFromURL( "private:factory/swriter", "_blank", 0, vntNoArgs())
Über die entsprechende Objektvariable »objTextDokument« ist anschließend der Zugriff auf das neu angelegte Dokument möglich.

Abbildung 3: Die »loadComponentFromURL«-Methode des »Desktop«-Service erlaubt das Öffnen eines vorhandenen und das Anlegen eines neuen Dokuments.
Tipp 5: Den Wert einer Objektvariablen prüfen
Einer der häufigsten Fehler in Star-Office-Makros ist der, dass die Zuweisung eines Service oder Verweises an eine Objektvariable scheitert. Wenn die »loadComponentFromURL«-Methode etwa das in der URL angegebene Dokument nicht finden kann, weil es beispielsweise nicht (mehr) existiert, kann sie auch keinen gültigen Verweis darauf zurückliefern.
Zwangsläufig bekommt das Makro dann auch Probleme, wenn es über die Objektvariable auf das vermeintlich vorhandene Dokument zugreifen will. Damit keine Fehlermeldung die Ausführung des Makros unterbricht, sollte man noch die Gültigkeit der Objektvariablen mit Hilfe der Basic-Funktion »IsNull« überprüfen. Sie liefert den logischen Wert »True« zurück, wenn die Objektvariable keinen gültigen Wert besitzt. Das Beispiel
Dim objDokument As Object objDokument = ThisComponent If Not IsNull(objDokument) Then MsgBox objDokument.URL End If
prüft, ob die Objektvariable »objDokument«, die auf das aktuelle Dokument (hier »ThisComponent«) verweist, einen gültigen Wert besitzt. Nur wenn das der Fall ist, zeigt die darauf folgende »MsgBox«-Anweisung die URL der betreffenden Datei an. Sollte aktuell kein Dokument geöffnet sein, wird das Makro ohne Fehlermeldung beendet.
Tipp 6: Eigenschaften von Services festlegen
Eigenschaften (Properties) sind Werte, die Charakteristika von Services festlegen. Einige Services besitzen eine feste Anzahl von Eigenschaften, auf die man direkt über die zugewiesene Objektvariable zugreifen darf. Ein Beispiel ist die »FillColor«-Eigenschaft, die Füllfarben von Zeichnungsobjekten (»Shapes«) bestimmt. Das Shape-Objekt »objRechteck« beispielsweise wird über
objRechteck.FillColor = RGB(0, 0, 255)
mit rein blauer Füllung versehen. Anders sieht es aus, wenn ein Service optionale Eigenschaften besitzt, die mal angegeben werden und mal nicht. Dann müssen diese in einem Array vom Datentyp »PropertyValue« übergeben werden. Das ist etwa beim »Desktop«-Service so, dem man über optionale Eigenschaften mitteilen kann, welche Datei- Art er mit seiner »loadComponentFromURL«-Methode öffnen soll. Das beginnt mit der Dimensionierung des »PropertyValue«-Arrays, das so viele Elemente haben muss, wie Eigenschaften festzulegen sind. Bei zwei Eigenschaften ist das Array also auf »1« zu dimensionieren, so dass Star Basic zwei Elemente mit den Indexzahlen »0« und »1« reserviert:
Dim prvFileProperties(1) As New com.sun.star.beans.PropertyValue
Anschließend weist man jedem Element über »Name« und »Value« den Namen sowie den zugehörigen Wert der festzulegenden Eigenschaft zu. Das folgende Beispiel legt die »FilterName«-Eigenschaft auf »MS Word 97« und die »AsTemplate«-Eigenschaft auf »False« fest:
prvFileProperties(0).Name= "FilterName" prvFileProperties(0).Value= "MS Word 97" prvFileProperties(1).Name= "AsTemplate" prvFileProperties(1).Value=False
Zur Übermittlung an den »Desktop«-Service folgt das gefüllte Array der »loadComponentFromURL«-Methode als Parameter:
objDokument = objDesktop .loadComponentFromURL( "file:///home/ralf/Finanz.doc", "_blank", 0, prvFileProperties())
Im Klartext veranlasst diese Anweisung den »Desktop«-Service dazu, die Datei »Finanz.doc« als Microsoft-Word-Dokument zu öffnen.
Tipp 7: Word-Dokumente bequem öffnen
Die benutzerdefinierte Funktion »WordDokOeffnen« in Listing 1 vereinfacht das Öffnen von Microsoft-Word-Dokumenten erheblich. Zum Aufruf ist der Funktion nur die URL des zu öffnenden Word-Dokuments zu übergeben sowie eine Objektvariable zur Aufnahme des Rückgabewerts zuzuweisen:
Dim objDokument As Object
objDokument = WordDokOeffnen
("file:///home/ralf/Muster.doc")
Die Funktion definiert ein »PropertyValue«-Array (siehe Tipp 6) zum Festlegen der Dateifilter-Eigenschaften und übergibt es der »loadComponentFromURL«-Methode des »Desktop«-Service, der das Dokument zu öffnen versucht. Wenn das gelingt, liefert die Funktion einen Verweis auf das geöffnete Word-Dokument zurück, der in der Objektvariablen gespeichert wird. Das aufrufende Makro sollte den Variablenwert prüfen, um seinerseits zu erfahren, dass die Arbeit der Funktion erfolgreich war:
If Not IsNull(objDokument) Then 'Beliebige Anweisungen '... End If

Abbildung 4: Die Services des Star-Office-API erlauben auch eine automatisierte Übernahme von Microsoft-Office-Dokumenten.
Tipp 8: Mit Collections arbeiten I
Das Star-Office-API enthält viele Komponenten, die zu so genannten Kollektionen (Collections) zusammengefasst sind. So bilden etwa sämtliche Tabellen (Sheets) eines Tabellendokuments eine Kollektion, ebenso die Absätze eines Textdokuments. Je nach Typ der Kollektion gibt es mehrere Möglichkeiten, auf einzelne Elemente zuzugreifen. Bei benannten Kollektionen wie »Sheets« hat jedes Element einen individuellen Namen, über den es mit der »getByName«-Methode adressierbar ist.
Das folgende Beispiel richtet einen Verweis auf die Tabelle »Tabelle1« ein, der in der Objektvariablen »objTabelle« gespeichert wird:
Dim objSheets As Object
Dim objTabelle As Object
objSheets = ThisComponent.Sheets
objTabelle = objSheets
.getByName("Tabelle1")
Jede benannte Kollektion besitzt eine »getElementNames«-Methode, die die Namen aller Elemente als Array zurückliefert. Zur Aufnahme des Arrays ist eine Variant-Variable nötig. Das Beispiel liest die Namen aller Tabellen des aktuellen Tabellendokuments in die Variant-Variable »strNamen« ein und gibt deren Inhalt per »For-Next«-Schleife aus:
Dim strNamen As Variant Dim intI As Integer objSheets = ThisComponent.Sheets strNamen = objSheets.getElementNames For intI = LBound(strNamen) To UBound(strNamen) MsgBox strNamen(intI) Next
Um festzustellen, ob ein bestimmtes Element in einer benannten Kollektion enthalten ist, tritt die »hasByName«-Methode der Kollektion in Aktion. Das Beispiel prüft die Existenz der Tabelle »Tabelle1« und zeigt das Ergebnis (»True« beziehungsweise »False«) per »MsgBox«-Dialog an:
objSheets = ThisComponent.Sheets
MsgBox objSheets.hasByName
("Tabelle1")
Tipp 9: Mit Collections arbeiten II
Bei indizierten Kollektionen besitzt jedes Element eine Indexzahl, die seine Position innerhalb der Kollektion angibt. Die Zählung der Kollektionselemente beginnt stets bei null. Den Zugriff auf ein Element ermöglicht die »getByIndex«-Methode, die die Indexzahl des gewünschten Elements erwartet. Das folgende Beispiel
Dim objSheets As Object Dim objTabelle As Object objSheets = ThisComponent.Sheets objTabelle = objSheets.getByIndex(1)
erzeugt einen in »objTabelle« gespeicherten Verweis auf die zweite Tabelle des aktuellen Tabellendokuments. Alternativ erlaubt Star Basic einen verkürzten Zugriff, der ohne die »getByIndex«-Methode auskommt:
objTabelle = objSheets(1)
Wer jedoch eine indizierte Kollektion vollständig durchlaufen will, sollte dazu eine For-Next-Schleife verwenden. Über deren automatisch erhöhte Zählvariable ist der Zugriff auf jedes einzelne Element der Kollektion möglich. Den Zähler-Endwert liefert die »getCount«-Methode, die die Anzahl der Elemente benennt. Das Beispiel zeigt die Namen (»Name«-Eigenschaften) aller Tabellen des aktuellen Tabellendokuments an:
Dim objSheets As Object Dim intI As Integer objSheets = ThisComponent.Sheets For intI = 0 To objSheets .getCount() - 1 MsgBox objSheets(intI).Name Next
Tipp 10: Mit Collections arbeiten III
Es gibt Kollektionen, deren Elemente weder Namen noch Indizes besitzen. Das ist etwa bei den Absätzen eines Textdokuments der Fall. Bei solchen Kollektionen ist kein direkter Zugriff auf die einzelnen Elemente möglich. Stattdessen gilt es, mit der »createEnumeration«-Methode ein Aufzählungsobjekt zu erzeugen, auf dessen Elemente man sequenziell zugreifen kann.
Das Beispiel erzeugt das Aufzählungsobjekt »objAufzaehlung«, das alle Absätze des aktuellen Textdokuments enthält. Der Kopf der While-Wend-Schleife prüft bei jedem Durchlauf mit der »hasMoreElements«-Methode, ob die Aufzählung weitere Elemente enthält. Wenn das der Fall ist, speichert die Schleife den von »nextElement« gelieferten Verweis auf den nächsten Absatz in der Objektvariablen »objAbsatz« und zeigt dessen Inhalt per »MsgBox«-Meldung:
01 Dim objAufzaehlung As Object 02 Dim objAbsatz As Object 03 04 objAufzaehlung = ThisComponent 05 .Text.createEnumeration 06 07 While objAufzaehlung 08 .hasMoreElements 09 objAbsatz = objAufzaehlung 10 .nextElement 11 MsgBox objAbsatz.getString 12 Wend
Tipp 11: Verfügbare Services dokumentieren
Das zurzeit größte Problem bei der Entwicklung von Star-Office-Makros ist die unzureichende Dokumentation. Es gibt bislang nur ein Gesamtverzeichnis sämtlicher API-Bestandteile, das ausschließlich online einsehbar ist [3] und kaum Orientierung bietet.
Eine Besserung dieser Situation kann die nützliche Prozedur aus Listing 2 bringen, das online auf dem Linux-Magazin-Server zur Verfügung steht [4]. Sie trägt die Namen aller verfügbaren Services einer bestimmten API-Komponente zusammen und schreibt sie in ein neues Textdokument. Beim Aufruf ist der Prozedur ein Star-Basic-Bezeichner respektive eine Objektvariable zu übergeben, der/die auf die gewünschte Komponente verweist. Die Anweisungszeile:
Call ServicesDokumentieren (ThisComponent)
beispielsweise erstellt eine Referenz aller Services des aktuellen Dokuments. Als Lieferant der Service-Namen dient die Methode »getAvailableServiceNames« der jeweiligen API-Komponente. (jk)
|
Infos |
|
[1] Star Office: [www.sun.de/staroffice] [2] Newsgroup zu Star Basic: [news:staroffice.de.support.starbasic] [3] Verzeichnis der API-Teile: [http://api.openoffice.org/common/ref/com/sun/star/module-ix.html] [4] Listings zum Artikel: [ftp://ftp. linux-magazin.de/pub/listings/magazin/2002/05/StarBasic] |









