Aktuelle Schlagworte wie „3-tier“, „COM“, OLE-Server“ lassen einige Fo’ler (zum Teil nach den ersten Versuchen) einen großen Bogen machen, zumindest für ihre praktische Entwicklungsarbeit. Aber es lohnt sich, die anfänglichen Klippen eines solchen Programms ohne User-Interface zu überwinden. Diese Session richtet sich an Entwickler, die in die Arbeit von VFP als COM-Server eingeführt werden wollen, und das ganze praktisch bei sich zum Laufen kriegen wollen. Sie richtet sich nicht an ausgefoxte VFP-Profis, die noch das letzte aus ihrem fertigen COM-Server heraus-tunen wollen... Sie sollten jedoch Grundbegriffe der Objektorientierten Programmierung (den Umgang mit Klassen und Objekten) etwas kennen.
Wenn Sie ihre Anwendung als herkömmliche Desktop Anwendung konzipieren, liegt alle Logik, mit der Sie auf Daten zugreifen im gleichen Programm wie auch die Oberfläche, bei der Sie sich Mühe geben dem Anwender eine angenehme Benutzerschnittstelle zu liefern. Dies ist die herkömmliche Client/Server-Strategie. Sie besteht also aus zwei Ebenen: Server auf der einen Seite (Daten) und Client auf der anderen (Logik und Benutzeroberfläche)
Ihr Nachteil besteht einfach darin, dass die einzige Möglichkeit, um die von Ihnen programmierte Logik zur Be- und Verarbeitung bzw. Abfrage der Daten eben über genau diese ebenfalls von Ihnen hergestellte Benutzeroberfläche läuft. Sie können zwar über ODBC auch von einer anderen Anwendung aus auf die Daten zugreifen, nicht jedoch unter Verwendung Ihrer Geschäftslogik, denn die ist eins mit ihrer Oberfläche.
Die Technik, von der wir in dieser Session sprechen wollen, trennt nun die Benutzeroberfläche Ihres Programmes (des „Client“, nach Client/Server-Gesichtspunkt gesehen) völlig ab. Was bleibt übrig? Lediglich alles, worin die eigentliche Geschäftslogik besteht. Andersherum gesprochen: Die Benutzeroberfläche wird getrennt von der Geschäftslogik. Das bedeutet:
„COM“ / „Common Object Model“: Das Programm kann nun “Common”, d.h. allgemein zur Verfügung gestellt werden. Andere Programme mit beliebiger Benutzeroberfläche greifen auf Ihr Programm mit Ihrer Geschäftslogik zu.
„3-tier“ / 3 Ebenen: Es ist zu den 2 Ebenen des Client/Server-Prinzips noch eine dritte hinzugekommen: (1) Daten (Server), (2) Programm mit Geschäftslogik (Client), (3) Benutzeroberfläche (Frontend). Dabei müsste die Benutzeroberfläche dann gar nicht mehr mit VFP programmiert sein, sondern mit einer beliebigen Sprache, z.B. Visual Basic etc. Sie könnte sogar in einer Internet-Anwendung direkt vom Browser aus angesprochen werden.
Sie mögen vielleicht sagen: „Aber für meine Anwendung mache ich die Oberfläche selbst und ich mache sie in VFP“? Trotzdem! Wenn Sie die Anwendung von vornherein nach dem 3-tier Modell strukturieren, haben Sie nach vorne hin größtmögliche Offenheit, insbesondere falls die Anwendung einmal in einen Internetserver integriert werden soll.
Um es anderen Anwendungen als VFP möglich zu machen, auf Ihre VFP-Anwendung und deren Methoden zuzugreifen, eventuell sogar aus Ihrer Anwendung Werte zurückgeliefert zu bekommen und diese weiterzuverarbeiten, machen wir uns das COM-Modell zunutze, das Windows uns liefert.
COM steht für „Common Object Model“ oder auch “Component Object Model”.
Common = gemeinsam, d.h. gemeinsam von allen OLE-fähigen Anwendungen zu verwenden
Object = die gemeinsame Nutzbarkeit bezieht sich auf die Instanziierung der Anwendung als Objekt in einer anderen Anwendung
Das bedeutet: wenn eine Klasse als OLE-Public registriert worden ist (wie das von uns gemacht wird sehen wir unten) kann in einer anderen Anwendung eine Objekt aus Ihrer VFP-Klasse erzeugt werden und von dort aus auf die Methoden und Eigenschaften dieser Klasse zugegriffen werden. Die meisten Entwickler haben ja schon mal Word aus VFP aus angesprochen:
Da die eigenen Microsoft-Anwendungen immer als OLE-Server konzipiert sind (sie können also anderen Anwendungen "dienen"), können wir sie gut als Beispiel heranziehen. So wie wir im folgenden Beispiel Word als COM-Server von VFP aus ansprechen, werden wir später unsere eigene VFP-Anwendung von Word oder einem anderen Client aus ansprechen, sie wird damit selbst zum COM-Server.
Zusammenfassend: COM ist also eine allgemein in Windows zur Verfügung stehende Technik, mit der wir unsere Anwendung Windows-öffentlich (also für andere Anwendungen) zur Verfügung stellen können. Dabei kann der Client, mit der wir diese Klasse ansprechen natürlich auch wiederum ein VFP-Client sein.
COM arbeitet mit der OLE-Technik zur Verknüpfung von Programmen. Wir können also statt COM-Server auch von einem OLE-Server sprechen (gleichbedeutend).
Unser OLE-Server soll folgende Aufgabe erfüllen: Wenn er von irgendeinem Programm, z.B. von Word aus, aufgerufen wird, soll er die Möglichkeit geben, einer bestimmten Methode einen Parameter zu übergeben mit einer Adress-Nummer. Wird diese Adresse in der Adresstabelle gefunden, wird die Adresse als String von der Methode zurückgegeben und kann so z.B. in ein Word-Dokument eingefügt werden. Der Anwender würde also in diesem Falle nichts davon merken, dass hier ein FoxPro-OLE-Server gestartet wird, sondern würde lediglich feststellen, dass die von ihm angeforderte Adresse eingefügt wurde.
Um dieses Beispiel selbst nachzuvollziehen, legen sie sich einen neuen Ordner an, darin ein neues leeres Projekt. Legen Sie darin eine einfache Adress-Tabelle (freie Tabelle genügt für das Beispiel) mit typischen Feldern an: "Vorname", "Name", "Strasse", "Plz", "Ort" (alles als Zeichenfelder) und zusätzlich ein ID-Feld "ID" (Integer)
Bei objektorientiert konzipierten Anwendung haben wir bereits kaum noch etwas mit PRGs zu tun, das meiste liegt in Objekten. Trotzdem haben wir aber immer noch zumindest ein prozedurales Main-Programm verwendet, um das Anwendungsobjekt zu instanziieren und nach Beenden des Programmes letzte Aufräumungsarbeiten durchzuführen.
Dies ist hier nicht mehr der Fall.
Wir verwenden eine Anwendungsklasse, die von außen (ohne Verwendung eines Hauptprogrammes) instanziiert wird.
Darin besteht also das Starten des Ole-Servers: nicht im Starten einer EXE, die als erstes ihr Hauptprogramm ausführt, sondern im unmittelbaren instanziieren der Anwendungsklasse, die wir nun programmieren (aus diesem Grund muss seit VFP6 ein Projekt keine Hauptdatei mehr haben, wenn es als OLE-Server kompiliert wird). Zuerst werden wir nun diese Klasse entwerfen, als eine übliche VFP-Klasse, dann werden wir sehen, wie wir diese Klasse der Windows-„Öffentlichkeit“ zur Verfügung stellen.
Wir legen eine neue Klasse an aus der Basisklasse „Custom“. Wir können ihr schlicht den Namen „App“ (bitte nicht „application“ – dies ist ein geschützter Name) geben. Bei „Speichern in“ geben wir als Klassenbibliotheksnamen den einer neuen Klassenbibliothek wie MyOleServer an.
Diese neue „App“-Klasse muss weder im Init- noch im Destroy-Event spezielle Operationen ausführen. Unser ganzes Interesse gilt der Methode, die eine Adressnummer in Empfang nimmt und eine Adresse als Zeichenkette zurückgibt:
Legen wir also eine
neue Methode an, z.B. mit dem Namen „AdrGet“. Der Code könnte etwa lauten:
1 Ein sehr wichtiges Stück Code, das Sie bei allen OLE-Servern benötigen werden! Sobald Sie eine Anwendung von außen als OLE-Server starten, ist das Default-Verzeichnis immer das der VFP-Runtime, also meist das Windows\System32-Verzeichnis. Zu Anfang müssten sie also wechseln in das Verzeichnis des Programmes das aktuell läuft. Wir ermitteln es mit SYS(16) und schneiden den Namen der VCX (hinten) mit JUSTPATH() ab und den Namen der aktuell laufenden Methode vorne mit SUBSTR(.... AT(":",...)-1).
Ansonsten bedarf der Code vermutlich keiner weiteren Erklärung. Der Rückgabewert lcReturn wäre nun der Wert der nicht nur in die aufrufenden VFP-Methode zurückgegeben wird, sondern heraus aus VFP über OLE an das aufrufende Programm.
Damit unsere App-Klasse später von Windows-Anwendungen angesprochen werden kann, ist hier der erste Schritt, dass wir die spezifische Klasse als „OLE Public“ definieren. Rufen Sie dazu im Menü Klassen die Klasseninfo auf und klicken dort die Checkbox „OLE Public“ an.
![]() |
Sie sollten sich vor dem Erproben Ihrer Klasse in der „Windows-Öffentlichkeit“ erst davon überzeugen, dass diese "lokal" einwandfrei funktioniert, da die außerhalb von FoxPro zurückgegebenen Fehlermeldungen meist so kryptisch sind, dass man damit bei der Fehlersuche nicht viel anfangen kann.
Dazu legen wir ein Objekt aus unserer Klasse an und testen
die Methode AdrGet:
Es müsste eine Zeichenkette mit der Adresse für ID=1 ausgegeben werden. Wenn die Klasse hier einwandfrei funktioniert, können wir fortfahren:
Sie können einen OleServer sowohl als DLL als auch als EXE kompilieren. Der grundsätzliche Unterschied liegt darin, dass eine DLL als "in-process"-Server arbeitet, d.h. im gleichen Process läuft, wie das Programm, das sie aufrief. Ein in-process Server kann nicht über eine Benutzeroberfläche verfügen. Kompilieren Sie ihren Server hingegen als EXE, so ist dies ein out-of-process Server. Bei jeder Instanz des Servers öffnet sich also ein eigener, unabhängiger Task. Out-of-process Servers können über eine Benutzeroberfläche verfügen, z.B. Forms anzeigen.
Der Dialog zum Kompilieren unterscheidet sich von VFP6 zu VFP6SP3 (Service Pack 3):
![]() |
Erstellungs-Dialog unter VFP 6 bis SP2: Sie können neben der APP auswählen zwischen EXE und COM-DLL | |
![]() |
|
Die im Service-Pack
3 eingeführte zusätzliche Möglichkeit eines „Multi-Thread-COM-Servers“
läßt eine Problematik des früheren COM-Modells bei VFP erkennen.
Dort konnte eine gestartete DLL im Speicher nur einen Thread (also ein daraus
erzeugtes COM-Objekt) verwalten. Der Multi-Thread-COM-Server erlaubt einer DLL
im Speicher, mehrere COM-Objekte zu verwalten. Dies ist natürlich generell
von Vorteil. Für Absturz-gefährdete COM-Server macht jedoch nach wie
vor die Verwendung von Single-Thread-COM-Servern Sinn. In diesem Zusammenhang
beinhaltet das Service-Pack 3 auch eine neue Laufzeitbibliothek (VFP6T.DLL). Beachten
Sie auch hierzu die Hinweise der Hilfedatei VFPSP3.CHM.
Beim Kompilieren wurde
eine Datei mit der Endung .VBR erzeugt. Sie enthält die Schlüssel,
die VFP in die Registry einträgt, wenn es unsere Anwendung dort registriert.
Wollen sie Schlüssel verändern oder hinzufügen, können Sie
dies in der VBR-Datei tun vor einem erneuten Registrieren.
Alle OLE-Anwendungen greifen immer auf die Registrierungsdatenbank von Windows zu. Was dort nicht eingetragen ist, ist gewöhnlich auch per OLE nicht von anderen Anwendungen ansprechbar. Zwar wird ab Service Pack 3 von Visual Studio die Registrierung automatisch beim Kompilieren einer COM-DLL/EXE durchgeführt. Trotzdem will ich hier den einfachen Vorgang der manuellen Registrierung kurz zeigen: Verkleinern Sie VFP und alle anderen Anwendungen zum Symbol, so dass Sie den Desktop sehen (Tip: Windows95-Taste + M). Erstellen Sie auf dem Desktop eine Verknüpfung mit der REGSVR32.DLL aus dem SYSTEM32-Pfad Ihres Windows/WinNt-Ordners (Wechseln in diesen Ordner, Suchen der entsprechenden Datei, rechts klicken, auf den Desktop ziehen, Verknpüfung hier erstellen? anklicken).
Öffnen Sie ein
Fenster Ihres Anwendungs-Ordners und ziehen Sie die von Ihnen erstellte AdressInfo.Dll
bzw. ADRESSINFO.EXE auf das Symbol der REGSVR32.EXE.
Sie müssten als
Ergebnis eine Meldung bekommen wie diese:
Nun ist Ihre DLL registriert
und kann von anderen OLE-fähigen Windows-Programmen verwendet werden.
Verwenden der DLL von außen
(Test)
Zum ersten Test wollen
wir die DLL innerhalb von VFP, aber „von außen“ als DLL ansprechen. Dies
funktioniert genau so wie wir es schon beim Word-Objekt gesehen haben:
Eine Klassenbibliothek
muss (und kann) hier nicht angegeben werden: Die „Klassenbibliothek“ ist gewissermaßen
die Registry, in der sämtliche vorhandene Klassen registriert sind. Stößt
also VFP bei der Klassendefinition auf einen Punkt, wird die Klasse nicht mehr
im aktuellen VFP sondern in der Registry gesucht. Nun kann das neu erzeugte
COM-Objekt verwendet werden:
Es müsste eine
Adresse auf dem Bildschirm ausgegeben werden, wie zuvor im FoxPro-internen Test.
Wir wollen in einem
Beispiel testen, wie wir nun unsere VFP-DLL außerhalb verwenden können.
Im Beispiel soll der Anwender mit Word arbeiten und wenn er einen bestimmten
Kunden einfügen will auf F3 drücken. Die Adresse wird eingefügt.
Legen Sie dazu in Word
ein neues Makro an (Extras | Makros) mit der
Tastatur-Zuordnung F3. Das Makro könnte so lauten (Achtung: kein VFP sondern
VBA-Code!)[1]
In diesem Beispiel müsste
der Anwender zuerst einen Namen schreiben und markieren. Diese Markierung wird
dann als Name verstanden und in unserem VFP-Server gesucht. Wird er gefunden,
so wird die Markierung ersetzt durch die komplette Adresse.
1
In VBA (Visual Basic for Applications) werden
Variablen so angelegt. Apostroph oben
zeigt einen folgenden Kommentar an (entspricht in VFP entweder *
oder in der gleichen Zeile && ).
2
Objektvariablen werden mit SET
zugewiesen.
3
OLE-Klassename.
4
In Selection.Text befindet sich die
aktuelle Markierung als String. Diese wird übergeben an unseren COM-Server.
Der entscheidende Unterschied
eines middle-tier OLE-Servers zu einem herkömmlichen Programm ist, dass
der COM-Server ohne User-Interface arbeitet. Stößt ein OLE-Server
auf einen Befehl, der eine Benutzer-Interaktion anfragt, läuft er auf einen
Fehler, wie:
Sie müssen also
dafür sorgen, dass jegliche Meldungen, Messageboxen, WAIT WINDOWs etc.
ausbleiben! Da Sie aber zum Testen Ihrer Anwendung, sie durchaus zuerst unter
VFP starten und dort ggf. Meldungen wünschen, empfehle ich folgende Arbeitsweise.
1.
Stellen Sie mit Hilfe der application.startmode-Eigenschaft fest, ob
die Anwendung gerade als Server gestartet wurde.
2.
Setzen Sie eine Eigenschaft (z.B. lServer) Ihrer Anwendungsklasse entsprechend.
3.
Setzen Sie alle Vorgänge, die eine User Interaktion benötigen
in eigene Methoden und fragen da jeweils ab, ob lServer auf .T. steht. Ist dies
der Fall, lassen Sie die Meldung weg bzw. setzen einen Standard-Wert.
Um festzustellen, wie
die Anwendung gestartet wurde, stellt uns VFP seit SP3 die application.startmode
Eigenschaft. Sie kann folgende Werte haben.
Value |
Description
|
0 |
Interaktiver Modus
(gestartet in VFP / bei der Entwicklung) |
1 |
Visual FoxPro wurde gestartet als Application-Objekt mit: oMyObject
= CREATEOBJECT('VisualFoxPro.Application') |
2 |
Anwendung gestartet als out-of-process
.exe automation server. |
3 |
Anwendung gestartet
als in-process .dll automation server. |
4 |
Anwendung gestaret
als unabhängige oder .app or .exe file. |
5 |
Anwendung gestartet
als multithreaded in-process .dll automation server. |
Demnach könnte
die Abfrage lauten:
Sie sollten unbedingt
darauf achten, dass jeder OLE-Server zuerst reiflich IN VFP getestet wird, also
noch nicht als Server. Nur da können Sie den Code durch-tracen um gezielt
Fehler zu suchen. (Ich spreche hier nicht von Neuerungen, die es in VFP7 geben
wird, die werden uns andere Sessions vorgestellt, sondern gehe auf die praktische
Anwendung ein – und die muß noch über einige Zeit über VFP7
verzichten).
Erst wenn dies gründlich
erfolgreich war, sollten Sie sich daran machen, Ihren OLE-Server als Server
anzusprechen von außen (selbst wenn dieses "außen" wiederum
VFP ist).
Nun entsteht das Problem,
wenn jetzt Fehler auftauchen, dass diese nur extrem schwierig zu finden sind,
da die Fehlermeldungen extrem kryptisch sind, und der Code nicht im Step-Modus
durchlaufen werden kann.
Um diesem Problem ein
wenig zu Leibe zu rücken, stellt uns SP3 von VFP6 eine wichtige neue Funktion
zur Verfügung: COMRETURNERROR. Sie bewirkt, dass eine Fehlermeldung bis
an den OLE-Client weitergegeben wird. Wenn Sie zuvor feststellen, ob sich die
Anwendung gerade im Servermodus befindet (s.o.), könnte der code folgendermaßen
aussehen:
![]() |
Um dem COM-Server Befehle in Auftrag zu geben, wird auf
jeden Fall eine Anwendung nötig sein, die diese Befehle ausführt.
Die anderer Nutzen des nicht mehr verwendeten User-Interfaces ist die Ausgabe
von Meldungen. Dies kann ersetzt werden durch eine Log-Datei. Es empfiehlt sich,
eine eigenes LOG-Objekt anzulegen, das dies verwaltet.
[1]
Vorhanden im Beispielcode der DevCon-CD: "Makro.txt"
[2] Beachten Sie, daß In-process Server (DLL's) immer das User-Interface abschalten (und bei Befehlen, die eine User-Interaktion erfordern einen Fehler generieren. Bei Out-of-Process Servern (EXE's) dagegen muß explizit die Benutzeroberfläche abgeschaltet werden (SYS(2335,0)=unattended Server Mode), wenn keine Benutzeroberfläche gewünscht ist, wie z.B. bei einem Internet-Server.
dFPUG c/o ISYS GmbH Frankfurter Str. 21 b
D-61476 Kronberg |
per Fax an: +49-6173-950903 oder per e-Mail an: |
© Texte, Grafiken und Inhalt: ISYS GmbH |