Lade...
 

OLE-Automation

OLE-Automation mit ClassiX®

ClassiX® bietet die Möglichkeit, über OLE-Automation externe Anwendungen zu steuern und zu programmieren. Im Folgenden werden speziell die Office Produkte von Microsoft betrachtet. Wer schon einmal Visual Basic programmiert hat, wird auch keine Schwierigkeiten haben, dies in InstantView® zu tun. Wichtigstes Hilfsmittel ist der von den Microsoft Anwendungen angebotene Objektkatalog. Ihn erreicht man innerhalb der Anwendung nach drücken von Alt+F11 unter ‚Ansicht’ > ‚Objektkatalog’. Er listet in dem linken Fenster alle Klassen und Enumerationen der gewählten Anwendung. Wenn man eine anklickt, zeigt er im rechten Fenster die enthaltenen Methoden, Attribute und Events sowie unten eine kurze Syntaxerläuterung mit Beschreibung. Per Kontextmenu erreicht man auch die ausführliche Hilfe.

Eine fremde Anwendung programmieren

Die Herangehensweise zur Programmierung einer fremden Anwendung beinhaltet als erstes das Verstehen dieser Anwendung. Dies geht am besten, in dem man versucht, das Objektmodell der Anwendung zu verstehen. Hierbei hilft der Objektkatalog oder Literatur, wie z.B. 1. sowie das Internet, siehe 2. Informationen zur VB Programmierung von Office 2000 findet man unter 3.

objcat.gif
Abb. 1 Der Objektkatalog von Microsoft Word im VB(A)-Editor

Um mit der Programmierung zu beginnen, muss man den Namen einer Ausgangsklasse in Erfahrung bringen. Alle Office Anwendungen bieten die Klasse ‚Application’ an, welche zur Programmierung der Anwendung selbst dient. Dazu gibt es dann noch Klassen für die entsprechenden Dokumente, z.B. Word.Document oder Excel.Sheet. Alle diese Klassenname kann man auch in der Windows Registry unter dem Schlüssel ‚HKEY_CLASSES_ROOT’ nachgucken, hier sind alle im System registrierten Anwendungen und Dateitypen aufgelistet. Alle direkt zugänglichen Klassen von Word findet man z.B. unter Word.*, wobei der Stern für den Klassennamen steht. Um z. B. ein Word-Dokument zu programmieren, steht die Klasse Word.Document zur Verfügung. Wenn hinter dem Klassennamen noch eine Zahl steht, dann bezeichnet diese die Version, wobei der Eintrag ohne Zahl immer für die aktuellste Version steht.

COM-Objekte in ClassiX®

Mit diesen Informationen kann nun mit der Programmierung begonnen werden. Da alle COM-Objekte in ClassiX® vom Typ CX_COM_OBJECT sind, wird zuerst ein neues Objekt vom Typ CX_COM_OBJECT erstellt. Dieses bietet die Methode CreateFromProgID an, welche die Verbindung mit der Anwendung herstellt. Als Parameter bekommt die Methode den Namen der gewünschten Klasse übergeben.

Beispiel:

    Var(doc)
    CreateTransObject(CX_COM_OBJECT) -> doc 

    "Word.Document" doc Call(CreateFromProgID)

Der entsprechende Code in VB:

    Dim doc As Word.Document
    Set doc = CreateObject("Word.Document")

Nun repräsentiert das Objekt doc die Klasse Word.Document. Alle Datenfelder und Methoden dieser Klasse können nun benutzt werden. Um eine Methode zu verwenden werden die Parameter auf den Stack gelegt und dann mit Call() die entsprechende Methode aufgerufen:

Beispiel:

    "C:\Beispiel.doc" doc Call(Compare)

Der entsprechende Code in VB:

    doc.Compare("C:\Beispiel.doc")

Die Werte der Datenfelder werden auf ähnliche Art und Weise gesetzt und ausgelesen. Jeder Datenfeldname wird auf zwei Methoden umgesetzt, einmal mit ‚Put’ und einmal mit ‚Get’ vor dem Datenfeldname. Dieses kann man nun wie jede andere Methode aufrufen:

Beispiel:

    "geheim" doc Call(PutPassword)

    doc Call(GetPassword)

Der entsprechende Code in VB:

    doc.Password = "geheim"
    doc.Password

Hier wird das Datenfeld ‚Password’ erst mal mit ‚PutPassword’ gesetzt und gleich darauf wieder mit ‚GetPassword’ ausgelesen. Auf dem Stack befindet sich jetzt der String „geheim“.

Collections und Objekte

Wenn eine Methode oder ein Datenfeld ein Objekt zurückliefert, dann ist dieses immer vom Typ CX_COM_OBJECT, repräsentiert aber das entsprechende VB Objekt und kann genauso wie jedes normale ClassiX® Objekt verwendet werden.
Falls eine Collection zurückgeliefert wird, dann kann diese auch wie eine Collection unter ClassiX® verwendet werden. Die ‚Iterate’ Anweisung stellt hier das Äquivalent zur ‚For Each ... Next’-Schleife in VB dar.

Beispiel:

    Var(Foo)
    1 100 doc Call(Range) Call(Rows)
    Iterate
    {
    Call(GetAlignment) -> Foo

    }

Entsprechend in VB:

    Dim Foo As Byte
    For Each thisRow In doc.Range(1,100).Rows
    Foo = ThisRow.Alignment
    Next

Diese Anweisungen sind auf jedem Fall einer normalen Schleife mit manuellem Hochzählen eines Index vorzuziehen, da sie kleiner und wesentlich besser zu lesen sind.

Events

Events, welche von der externen Anwendung angeboten werden, können bisher nur in ClassiX® ActiveX-Controls verwendet werden, in normaler OLE-Automation noch nicht.

Arrays

Arrays werden von der ClassiX® COM-Schnittstelle noch nicht unterstüzt. Das bedeutet, dass sowohl aus ClassiX® heraus keine Arrays an Methoden der COM-Objekte übergeben werden können also auch keine Methoden der COM-Objekte aufgerufen werden können, wenn diese Arrays zurückgeben.

Konstanten

Wenn ein Attribut oder eine Methode laut Dokumentation oder Objekt-Explorer eine Konstante zurückliefert, dann kann diese nicht in der Form übernommen werden, da es in InstantView® keine Konstanten gibt. Stattdessen muss der Integer-Wert der Konstanten in InstantView® verwendet werden. Der Wert wird z.B. im Objekt-Explorer angezeigt. Der Lesbarkeit halber kann man den Wert einer Variable zuweisen, die den Namen der Konstanten bekommt, jedoch muss man dann aufpassen, dass diese Variable natürlich veränderbar ist.

Beispiel:

    doc Call(GetType)

Liefert den Typ des Dokuments (Dokument, Vorlage, ...) als Enum WdDocumentType. In VB ist dies eine Konstante, in InstantView® liegt jetzt ein Integer Wert auf dem Stack den man einer Variable zuweisen kann.
Zum Setzten eines Attributs wird genauso vorgegangen, im Objektkatalog lässt sich der Wert der gewünschten Konstante in Erfahrung bringen und dieser wird dann einfach wie jedes andere Attribut auch, gesetzt.

Beispiel:

    1 1 100 doc Call(Range) Call(PutCase)

und in VB:

    doc.Range(1, 100).Case = wdUpperCase

Hier werden im gewählten Bereich (die ersten 100 Zeichen) die Buchstaben auf Großbuchstaben umgesetzt.

Optionale Parameter

Ein weiterer Unterschied zwischen VB und InstantView® besteht in der Handhabung von Funktions-Parametern. Während VB optionale Parameter unterstützt, welche man nach Belieben weglassen kann, können in InstantView® nur die letzten optionalen Parameter weggelassen werden. Dabei muss darauf geachtet werden, dass nicht aus Versehen auf dem Stack alte Werte liegen, die als Parameter interpretiert werden könnten.

    "C:\Beispiel.doc" doc Call(SaveAs)

Obwohl die Methode SaveAs diverse Parameter versteht, funktioniert diese InstantView® Anweisung, da der Dateiname der erste erwartete Parameter ist. Hier sollte man jetzt aber darauf achten, dass der Stack leer ist, weil eventuell vorhandene Elemente auf dem Stack als die weiteren Parameter interpretiert werden könnten und man entweder unerwartete Ergebnisse oder eine Fehlermeldung aufgrund eines falschen Typ erhält. Folgende VB Anweisung ist in InstantView® nicht möglich:

    doc.SaveAs "C:\Beispiel.doc" ,,,"geheim"

Hier bekommt SaveAs neben dem Dateinamen noch ein Passwort, welches zum öffnen des Dokuments benötigt wird. Um diese Anweisung in InstantView® zu realisieren müsste man für alle weggelassenen Parameter die Default-Werte mit übergeben:

    "C:\Beispiel.doc" 0 FALSE "geheim" doc Call(SaveAs)

Die 0 steht hier für das Speicher Format, welches standardmäßig das Microsoft Word Format ist. Der FALSE Parameter ist der Default-Wert für die Einstellung, ob das Dokument für Kommentare gesperrt sein soll.

Performance

Zum Schluss noch einige Hinweise zur Performance. Jeder Aufruf einer Methode oder setzen bzw. holen eines Attributs kostet Zeit. Dadurch kann längeres Navigieren von einem Objekt zum anderen ziemlich lange dauern. Wenn von dem Zielobjekt aus jetzt zwei Aufrufe gemacht werden sollen, dann ist es wesentlich effizienter, das Objekt einmal in einer Variable zwischenzuspeichern, als jedes Mal wieder von der Ausgangsklasse aus komplett hinzunavigieren.

    3 1 100 doc Call(Range) Call(Next) Call(Copy)

    3 1 100 doc Call(Range) Call(Next) Call(Select)

Ist nicht so effizient wie

    Var(next)
    3 1 100 doc Call(Range) Call(Next) -> next
    next Call(Copy)
    next Call(Select)

Dies gilt in VB genauso wie in InstantView®.
Des weiteren sind Variablenzugriffe immer schneller als ein Zugriffsausdruck auf ein Attribut oder eine Methode eines Objektes. Dies macht sich insbesondere in Schleifen bemerkbar, weshalb man hier auf Zugriffsausdrücke verzichten sollte und stattdessen lieber einmal vor der Schleife den Rückgabewert des Zugriffsausdruckes einer Variable zuweisen sollte.

Anhang

Abbildung von VB Typen auf ClassiX®:

Byte, Integer, Long: Integer
Single, Double: CX_NUMERIC
Currency:  CX_VALUE
String: String
Variant: Der entsprechende Fix-Typ
Boolean: CX_BOOLEAN
Date: CX_DATE/CX_TIME/CX_DATETIME
Object: CX_COM_OBJECT
Array: Wird von ClassiX® noch nicht unterstüzt

Literatur:

1
Microsoft Office 97 Visual Basic Programmer’s Guide, Microsoft Press, 1997

extlnk.gif2
http://www.microsoft.com/technet/treeview/default.asp?url=/TechNet/prodtechnol/office/proddocs/opg/appendixes/partapp.asp

extlnk.gif3
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odeopg/html/deovroffice2000visualbasicprogrammersguide.asp

InstantView®