Session D-MIX

COM, DCOM, MTS -
 kleine Beispiele, große Wirkung

Peter Herzog
ProLib Software GmbH


Um es mir einfach zu machen… Es wird in diesem Dokument grundsätzlich um folgende Beispiele gehen:

Und weil es sich nicht verhindern läßt, hier

Die Basic´s

Als erstes müssen wir wissen, was ein COM-Object überhaupt ist.

Dazu mache ich es wie die Bibel und zeige ein paar Gleichnisse auf, und versuche so die gesamte Geschichte etwas leichter durchschaubar zu machen.

Es wird noch ein paar alte Hasen geben, die sich an die Zeit erinnern können, als man fremde Programmteile als Objectfile (*.OBJ) zum eigenen Programm hinzugelinkt hat.

Das Objectfile selbst konnte (wie ein Virus) selbst nicht funktionieren, da ihm der Körper fehlte.

Innerhalb des Objectfiles gab es eine kleine Liste, in der die einzelnen Funktionen aufgelistet waren. Sobald nun der Wirtskörper (das eigentliche Programm) das Objectfile hinzugelinkt bekam, wurde die Liste ausgelesen und die dabei verzeichneten Adressen der Funktionen in die interne Liste des Wirtes aufgenommen.

Na wunderbar. Auf einmal konnte man sich ein Datenbanksystem als Objectfile kaufen, hatte eine Liste mit Funktionen zur Verfügung die man nach Lust und Laune verwenden konnte.

Einzige Vorraussetzung war eine ordentliche Dokumentation. Na ja, das hat sich bis heute nicht geändert <g>

Als Windows gebaut wurde, kam man auf die Idee, daß gewisse Funktionen nicht nur von einem Programm sondern von mehreren verwendet werden mussten. Nichts einfacher als das... Die DLL (Dynamic Link Library) wurde erfunden.

Sie entspricht ungefähr einem Objectfile mit dem Unterschied, daß sie nicht statisch zum Programm gelinked werden musste, sondern als DLL-Datei auf der Platte liegen konnte und bei Bedarf von jedem Programm hinzugelinked wurde. Vorteil der gesamten Geschichte ist die Austauschbarkeit. Was sich nebenbei immer öfter als Problem herausgestellt hat. Wer von euch kann sich noch daran erinnern, daß gewisse Programme (zB. Visual Sourcesafe) plötzlich nicht mehr funktionierte, weil ein neues Word installiert wurde.

Genau. Bei der Installation von Word oder anderen Microsoftprodukten wird regelmäßig ein komplett neuer Satz an DLL´s mitgeliefert. Eigentlich sollten diese Rückwärtskompatibel zu alten DLL´s ein, aber unser Freund und Weltbeherrscher Microsoft kocht sein eigenes Süppchen... und ganz ehrlich, was geht einer Wordabteilung Visual FoxPro an ?? Oder sehe ich das komplett falsch ? <g>

Nun hat Microsoft eben dieses Problem auch erkannt (Oh Wunder) und hat sich abgeleitet von den Visual Basic-VBX´en zuerst die OCX´e erfunden, die aus marktstrategischen Überlegungen Active-X Komponenten genannt wurden.

Vom Gedanken her eine tolle Sache. Ähnlich wie bei einer DLL soll man grafische Elemente aus allen Sparten im eigenen Programm verwenden können.

Die Rechnung wurde jedoch ohne den Wirt gemacht. Da Visual Basic schon von jeher relativ mager an Controls augestattet war, wurde der Großteil der Active-X Komponenten für VB geschrieben.

Microsoft hat zwar einen Leitfaden herausgegeben, wie diese Active-X´e zu schreiben sind, jedoch haben sich die wenigsten daran gehalten und zB.: auf interne Routinen von Visual Basic zurückgegriffen, die bei Visual FoxPro natürlich nicht vorhanden sind und somit waren die Active-X´e nur für Visual Basic geeignet. (Hilfe. Gebt mir meine DLL´s zurück <g>)

Trotzdem finden sich immer wieder ein paar intelligente Firmen die neben Visual Basic und Access auch noch etwas weiter denken und OCX´e erzeugen, welche auch unter C++ und Visual FoxPro nutzbar sind.

Meistens sind deren Dokumentation zwar sehr Visual Basic lastig, jedoch mit etwas Gefühl kommt man schon dahinter, wie sie unter Visual FoxPro einzusetzen sind.

Ein gute Beispiel dafür sind die Internetcontrols von Mabry ( http://www.mabry.com )

Microsoft ist nun noch einen Schritt weiter gegangen und hat bemerkt, daß die Active-X Controls meistens etwas Grafisches an sich haben und hat sich einer Architektur erinnert, welche sich Remote Procedure Call nennt (RPC)

Die COM Schnittstelle

wurde entworfen. (Common Object Modell) Alles was sozusagen nicht grafisch ist, ist eben COM, das andere Active-X. Eine relativ „leichte“ Erklärung, aber es kommt ungefähr hin.

Die Wörter Remote Procedure Call weisen bereits darauf hin, daß es sich wieder um das alte Spiel handelt, daß man Funktionen anderer Programme verwenden kann. Ähnlich wie bei den DLL´s

Der Unterschied liegt bei uns eigentlich nur in der Verwendung anderer Kommandos.

Um ein COM-Control anzusprechen, muß man sich eine Verbindung schaffen. Dies erledigen bei uns zwei Kommandos.

Createobject()

und

CreateobjectEX()

 

Letzteres ist für DCOM zuständig. DCOM ist die erweiterte Art des COM und bedeutet „über Netzwerke hinweg“. Also identisch mit COM, nur das sich das anzusprechende Teil nicht auf unserem Rechner befinden muß, sondern auf einem fremden Rechner liegt.

Createobject() macht nichts anderes, als zuerst in der Registry nachzusehen, wie der Schlüssel zum angegebenen Namen lautet. Über diesen Schlüssel (CLSID) findet VFP nun die dazugehörigen Infos.

Das heißt es findet das Programm selbst und die sogenannte TypeLibrary. Das Programm wird in den Speicher geladen, wie eine DLL und in der TypeLibrary findet man das Inhaltsverzeichnis. Manchmal wird die TypeLibrary auch direkt in die EXE oder DLL aufgenommen.

Einmal EXE einmal DLL ein anderes mal OCX

Ein COM-Control kann sich in einem OCX verstecken, oder in einer DLL und sogar in einer EXE. Handelt es sich um ein OCX ist es eigentlich ein Active-X ohne grafische Elemente. Na ja, soll zwar nicht so sein, ist aber manchmal so. Soweit zur Normung.

Handelt es sich um eine EXE, dann wird dies als Out of Process bezeichnet.

Nehmen wir beispielhaft Visual FoxPro als Client her, welches sich Microsoft Word an die Stiefel heften möchte.

Der Befehl dazu lautet:

oword = createobject(“word.application“)

 

Wenn man den Taskmanager and Tageslicht kommen läßt (STRG+ALT+ENTF) dann wird man erkennen, daß nicht nur Visual FoxPro sondern auch Word im Speicher existiert.

Zwischen den beiden Programmen liegt nun eine Nabelschnur, die Referenz. Über diese Referenz werden Infos ausgetauscht. Man ließt oder schreibt ein Property und starten eine Methode usw.

Sobald man die Referenz löscht release oword, dann fällt das Object „Word“ aus dem Speicher wieder raus. (8 MB geladen und schon sind sie wieder weg )<g>

Wenn man ein COM Objekt in Form einer DLL per craeteobject lädt, dann passiert etwas ganz anderes. Der Client, in unserem Falle Visual FoxPro, reserviert bei sich selbst Speicher und lädt sich die DLL direkt unter seinen Allerwertesten.

Ich verwende diese Strassensprache, weil Sie sich dann nämlich wesentlich besser vorstellen können, was passiert, wenn in der DLL etwas schiefgeht und diese wie eine Bombe zerplatzt. <g>

Ist es eine EXE, dann.... ein Programm im Speicher weniger, aber mein VFP läuft ja weiter.

Im anderen Falle.... Bums und der GPF schlägt unerbittlich in meine Applikation ein, ohne das ich selbst etwas dafür kann.

Aufruf einer fremdem Applikation via COM

Im oberen Beispiel haben Sie bereits gesehen, wie man Word mittels COM startet.

oword = createobject(“word.application“)

 

Wir müssen nun wissen, daß wir eine Referenz auf dieses Objekt haben. (oword)

Über diese Referenz können wir das Objekt „Word“ direkt ansteuern. Natürlich können wir nur Sachen anstellen, die Word uns zur Verfügung stellt.

Hier einmal ein paar Beispiele:

oword.visible = .t.    

oword.documents.add()     

oword.typetext("Dies ist ein test")

oword.selection.typetext("Dies ist ein test")

oword.Selection.TypeParagraph()

oword.Selection.Font.Size = 16

oword.selection.typetext("Dies ist ein test")

oword.ActiveDocument.PrintPreview()

 

Kopieren Sie sich die einzelnen Zeilen einmal in ein Programm und lassen Sie sie laufen. Sie werden bemerken, daß zuerst zwei Zeilen in verschiedenartigen Schriftgrößen geschrieben werden und dann das ganze in der Seitenansicht gezeigt wird.

Wir haben in diesem Beispiel mehrere Methoden und eine Eigenschaft des Objektes oword angesprochen. (Anm: Es kann auch hugo heißen, lassen Sie sich wegen des Namens nicht irritieren.)

Es gibt in einem COM-Server also Methoden und Eigenschaften.

Die Eigenschaften können wir Auslesen oder Schreiben. Die Methoden können wir ausführen. Hinter bestimmten Eigenschaften können sich wiederum Objekte verstecken. Im obigen Beispiel ist es die Selektion.

Nun haben wir nur noch eine Hürde, bevor wir die Welt fernsteuern können. Woher weiß man, welche Eigenschaften und welche Methoden.

Im Falle von WinWord oder Excel ist das relativ einfach. Es gibt einerseits eine relativ gute Visual Basic Hilfedatei und andererseits bieten beide Produkte eine Macroaufzeichnung, bei der man rausfindet, was man wo und wie einsetzen muß.

Einzig und alleine die sogenannten Konstanten machen Probleme. Bevor Sie lange nach zB.: msoPropertyTypeNumbersuchen, unter ftp://ftp.prolib.de/public/WINWORD/winword8.h finden Sie die notwendigen #DECLARE Statements.

Das Beispiel

Als Beispiel habe ich mir etwas Besonderes ausgedacht.

Als erstes nehmen wir Word und erzeugen und ein Macro, welches auf ein Visual FoxPro Objekt zurückgreift um uns die Adresse zu holen.

Dieses wiederum bedient sich eines anderen Visual FoxPro Objekts, welches ich einfach mal im Internet auf unserem AFP-Server abgelegt habe. Dort läuft es in einer MTS-Umgebung.

Als erste einmal

Das MTS-Objekt

Um das ganze nachvollziehen zu können, benötigen Sie einen Server, auf dem der Microsoft Transaction Server installiert ist.

Auf diesem Server erzeugen Sie sich ein Projekt mit dem Namen inetdcom. Darin legen Sie ein Programm mit dem Namen inetdcom an.

Dort speichern Sie nachfolgenden Code

define class vfpserver as session olepublic

   lok = .f.         && war der Befehl OK

   nerror = 0        && letzte Fehlernummer

   cerror = ""       && letzte Fehlermeldung

   cerror1 = ""      && letzte Zusatzfehlermeldung

   dimension fieldname(1)  && beinhaltet nach dem select die Feldnamen

   fieldcount = 0    && beinhaltet nach dem Select die Feldanzahl

   fields = .null.   && darunter hängen dann die einzelnen Objekte

   datasession = 2   && Eine Private Session einrichten

  

   procedure init

      set excl off   && absolut wichtig nur shared zuzugreifen

      cd  \inetdcom  && Pfad setzen,

         *weil man sonst im system32 des Servers steht

   endproc

  

   procedure open

      lparameter tcdbf

      this.lok = .t.

      if file(tcdbf)    && Öffne eine Tabelle, wenn Sie vorhanden ist

         use (tcdbf) in 0 shared

      else

         this.lok = .f.

      endif

      return this.lok

   endproc

  

   procedure close

      this.lok = .t.

      close data all    && Schließe alle Dateien

      return this.lok

   endproc

  

   procedure error

      LPARAMETERS nError, cMethod, nLine

      dimension laa(1)

      this.lok = .f.

      aerror(laa)    && Fülle die Fehlervariablen

      this.nerror = laa(1)

      this.cerror = laa(2)

      this.cerror1 = laa(3)

   endproc

  

   procedure sqlcmd

      lparameter tcsql

      local lni

      this.lok = .t.

      * hier wird jedes Commando ausgeführt

      * ist jedoch ein select from Befehl darunter

      * wird ein Cursor mit dem Namen _xxx erzeugt

      if "select"$lower(tcsql) and "from"$lower(tcsql)

         tcsql = tcsql + " into cursor _xxx"

      endif

      &tcsql         && Commando ausführen

      * wenn ein Cursor mit dem Namen _xxx erzeugt wurde....

      if used("_xxx")

         this.fields = .null.       && Alle bisherigen Felder weg

         scatter name this.fields   && Die Felder neu erzeugen

         this.fieldcount = fcount() && Die Anzahl wegspeichern

         dimension this.fieldname(this.fieldcount) && Das Array erzeugen

         for lni = 1 to this.fieldcount

            this.fieldname(lni) = fields(lni)   && Feldnamenwegspeichern

         endfor

      endif

      return this.lok

   endproc

   procedure movenext

      this.lok = .t.

      * Hier wird auf den nächsten Datensatz gesprungen

      if used("_xxx")

         if not eof()

            skip

            if eof()

               go bott

            endif

         endif

         this.fields = .null.

         scatter name this.fields

      endif

      return this.lok

   endproc

   procedure moveprev

      this.lok = .t.

      * Den vorherigen datensatz

      if used("_xxx")

         if not bof()

            skip -1

         endif

         scatter name this.fields

      endif

      return this.lok

   endproc

enddefine

(Anm: Ändern Sie gegebenfalls die Zeile cd \inetdcom auf Ihre Bedürfnisse)

Nehmen wir uns das Programm einmal vor.

Das absolute Zauberwort finden Sie in der ersten Zeile. OLEPUBLIC

Dieses Wort zeigt Visual FoxPro, daß es sich nun um eine Klasse handelt, welche von außen angesprochen werden soll.

Der Rest ist ein Abfallprodukt aus meiner D-WEB Session. Es macht nicht besonders viel. Es ist schlicht und einfach ein kleiner Server in Visual FoxPro geschrieben.

Man kann ihm ein Statement übergeben und der Server führt dieses aus. Ist das Statement ein SELECT Statement, wird ein Cursor erzeugt und der Inhalt jeden Datensatzes kann man als Eigenschaft ansprechen.

Erzeugen Sie nun eine Multithreaded DLL daraus.

Nun wechseln Sie in dei Microsoftconsole zum Transaction Server.

Erzeugen Sie sich ein neues, leeres Package. Nennen Sie das Package „INETDCOM“. Wichtig ist vor allem, daß Sie ein „empty Package“ erzeugen. Sie werden dabei gefragt, ob der „Interactive User“ dafür zuständig ist oder ein anderer. Ich schlage Ihnen vor, den Administrator des Servers einzutragen, dadurch entstehen Ihnen keine Probleme wenn es um Zugriffsrechte Ihre VFP-Servers geht.

Das Package benötigt nun noch Components und Roles. Was so viel bedeutet wie, WAS soll ausgeführt werden, und WER darf es ausführen.

Zuerst zum WAS.

Mit einem rechten Mausklick auf „Components“ können Sie eine neue Komponente installieren. Sie werden aufgefordert eine Datei auszuwählen. Wählen Sie die inetdcom.dll, welche aus unserem Projekt entstanden ist. Die dazugehörige inetdcom.tlb wird automatisch mitgeladen.

Legen Sie nun eine neue „Role“ an und benennen Sie diese nach Ihren Vorstellungen. Addieren Sie in diese Role jeden User, der auf den VFP-Server zugreifen soll. Sie machen es sich am einfachsten, indem Sie eine spezielle Usergruppe auf dem Server anlegen und dann nur dieser Gruppe den Zugriff erlauben.

Unterhalb der neu angelegten Komponente, können Sie die „Role“ eintragen, die Sie erzeugt haben.

Gute Geister haben mir zugeflüstert, daß man den Transaktionserver neu starten sollte, da die Zugriffssteuerung ... na sagen wir einmal ... nicht auf Anhieb seine Arbeit aufnimmt.

Um auf einer anderen Maschine wie den Server selbst einen Zugriff zu erlangen, ist es am einfachsten wenn man sich ein Package exportiert.

Ein rechter Mausklick auf das Package und man kann „Export“ wählen. Bitte beachten Sie, daß dies unter der deutschen Version zu Fehlermeldungen führt und schlicht und einfach nicht ordentlich funktioniert.

In der englischen Version von NT und dem Option Pack ist dies kein Problem.

Sobald Sie das Packet exportiert haben, finden Sie dort auch ein Unterverzeichnis mit dem Namen Client. Dort wurde Ihnen nun eine EXE abgelegt, mit der Sie zu jeder anderen Maschine gehen können und Ihnen fast alle Einstellungen automatisiert vorgenommen werden.

Trotzdem sollten Sie nachträglich noch das Programm DCOMCNFG.EXE starten und den Eintrag „inetdcom.vfpserver“ bearbeiten. Unter Server finden Sie nämlich dort den Namen des Servers, der unter Umständen nicht über das Internet gefunden werden kann. Tragen Sie dort einfach die IP-Adresse des Servers ein.

Um dem Server auch noch Daten zum „servieren“ zu bieten, kopieren Sie einfach die Sampledaten aus Visual FoxPro in das Verzeichnis \inetdcom, bzw. dorthin, wo Sie den Server erzeugt haben.

Der Server steht uns also nun auf einer anderen Workstation „Remote“ zur Verfügung.

Versuchen Sie nun, den Server anzusprechen.

Verwenden Sie dazu entweder

X=createobject(„inetdcom.vfpserver“)

Oder wenn Sie den Server auf einer bestimmten IP-Adresse ansprechen woollen

X=createobjectex(„inetdcom.vfpserver“,“ip-adresse“)

Sie erhalten nun eine Referenz auf das am MTS installierten VFP-Server.

Der Server bietet uns die Methode sqlcmd an.

Machen Sie einfach ein

? x.sqlcmd(„select * from customer”)

 

Tritt ein Fehler auf, wird ein .f. zurückgeliefert und die Fehlernummer und der Fehlercode wird unter

? x.nerror

? x.cerror

geliefert.

Wenn alles geklappt hat, dann haben Sie mehrere gefüllt Eigenschaften zum Abfragen

? x.fieldcount

gibt die Anzahl der Felder zurück.

? x.fieldname(x)

gibt Ihnen die Feldnamen zurück.

? x.fields.feldname

gibt Ihnen den Wert des Feldes zurück, vom aktuellen Datensatz

? x.movenext()

? moveprev()

macht einen SKIP und einen SKIP –1 innerhalb des erzeugten Cursors am Server.

Sehen Sie wie effektiv Visual FoxPro sein kann? Das ganze ohne RDS und doppeltem Boden. <g>

Mit

?x.fields.company

erhalten wir also den Inhalt des Dateifeldes COMPANY als Eigenschaft eines Objectes geliefert.

Als nächstes wenden wir uns an

Das VFP-Clientprogramm

Es soll direkt aus einem Visual FoxPro Programm heraus eine Abfrage an den VFP-Server geschickt werden.

Wir benötigen wieder ein Projekt und ein Programm. Beides nennen wir VFPWORD.

In das Programm kopieren Sie beiliegenden Code:

define class customer as custom olepublic

procedure getcustomer

local ocustomer, lcstring

lcstring=substr(left(sys(16),rat("\",sys(16))),at(":",sys(16))-1)

SET defa TO (lcstring)

set proc to vfpclient

 

*-- Wenn Sie eine Form verwenden, dann remarken Sie die

*-- folgenden 2 Zeilen und verwenden Sie die do form Zeile

ocustomer = createobject("vfpclient")

ocustomer.visible = .t.

 

*do form vfpclient name ocustomer linked

read events

endproc

enddefine

 

Es wird eine Form am Bildschirm erscheinen lassen, die Sie als Code hier abgebildet sehen. Speichern Sie diesen in ein PRG namens VFPCLIENT

DEFINE CLASS vfpclient AS form

 

   Height = 185

   Width = 407

   Desktop = .T.

   ShowWindow = 2

   DoCreate = .T.

   AutoCenter = .T.

   BorderStyle = 2

   Caption = "VFP-Client"

   AlwaysOnTop = .T.

   ovfp = .NULL.

   Name = "vfpclient"

 

   ADD OBJECT label1 AS label WITH ;

      Caption = "Kundennr:", ;

      Height = 20, ;

      Left = 0, ;

      Top = 12, ;

      Width = 60, ;

      Name = "Label1"

 

   ADD OBJECT text1 AS textbox WITH ;

      Value = "", ;

      Height = 23, ;

      Left = 60, ;

      Top = 8, ;

      Width = 48, ;

      Name = "Text1"

 

   ADD OBJECT command1 AS commandbutton WITH ;

      Top = 8, ;

      Left = 108, ;

      Height = 24, ;

      Width = 96, ;

      Caption = "Abfrage senden", ;

      Name = "Command1"

 

   ADD OBJECT label2 AS label WITH ;

      Caption = "Cust_id:", ;

      Height = 17, ;

      Left = 12, ;

      Top = 48, ;

      Width = 72, ;

      Name = "Label2"

 

   ADD OBJECT label3 AS label WITH ;

      Caption = "Company:", ;

      Height = 17, ;

      Left = 12, ;

      Top = 72, ;

      Width = 72, ;

      Name = "Label3"

 

   ADD OBJECT label4 AS label WITH ;

      Caption = "Contact:", ;

      Height = 17, ;

      Left = 12, ;

      Top = 96, ;

      Width = 72, ;

      Name = "Label4"

 

   ADD OBJECT label5 AS label WITH ;

      Caption = "Title:", ;

      Height = 17, ;

      Left = 12, ;

      Top = 120, ;

      Width = 72, ;

      Name = "Label5"

 

   ADD OBJECT text2 AS textbox WITH ;

      Height = 23, ;

      Left = 96, ;

      Top = 48, ;

      Width = 84, ;

      Name = "Text2"

 

   ADD OBJECT text3 AS textbox WITH ;

      Height = 23, ;

      Left = 96, ;

      Top = 72, ;

      Width = 288, ;

      Name = "Text3"

 

   ADD OBJECT text4 AS textbox WITH ;

      Height = 23, ;

      Left = 96, ;

      Top = 96, ;

      Width = 288, ;

      Name = "Text4"

 

   ADD OBJECT text5 AS textbox WITH ;

      Height = 23, ;

      Left = 96, ;

      Top = 120, ;

      Width = 288, ;

      Name = "Text5"

 

   ADD OBJECT command2 AS commandbutton WITH ;

      Top = 156, ;

      Left = 72, ;

      Height = 27, ;

      Width = 84, ;

      Caption = "Vorheriger", ;

      Name = "Command2"

 

   ADD OBJECT command3 AS commandbutton WITH ;

      Top = 156, ;

      Left = 180, ;

      Height = 27, ;

      Width = 84, ;

      Caption = "Nächster", ;

      Name = "Command3"

 

   ADD OBJECT command4 AS commandbutton WITH ;

      Top = 156, ;

      Left = 288, ;

      Height = 27, ;

      Width = 84, ;

      Caption = "Übernehmen", ;

      Name = "Command4"

 

   PROCEDURE Init

      thisform.ovfp = createobject("inetdcom.vfpserver")

   ENDPROC

 

   PROCEDURE command1.Click

      if not empty(ThisForm.Text1.value)

      lcs="select * from customer where cust_id=’";

      +upper(alltrim(ThisForm.Text1.value))+"'"

         if thisform.ovfp.sqlcmd(lcs) = .f.

            messagebox("Fehler:" ;

            +str(thisform.ovfp.nerror)+chr(13)+thisform.ovfp.cerror)

            return 0

         else

            ThisForm.Text2.value = thisform.ovfp.fields.cust_id

            ThisForm.Text3.value = thisform.ovfp.fields.company

            ThisForm.Text4.value = thisform.ovfp.fields.contact

            ThisForm.Text5.value = thisform.ovfp.fields.title

         endif

      endif

   ENDPROC


 

   PROCEDURE command2.Click

      thisform.ovfp.moveprev()

      ThisForm.Text2.value = thisform.ovfp.fields.cust_id

      ThisForm.Text3.value = thisform.ovfp.fields.company

      ThisForm.Text4.value = thisform.ovfp.fields.contact

      ThisForm.Text5.value = thisform.ovfp.fields.title

   ENDPROC

 

   PROCEDURE command3.Click

      thisform.ovfp.movenext()

      ThisForm.Text2.value = thisform.ovfp.fields.cust_id

      ThisForm.Text3.value = thisform.ovfp.fields.company

      ThisForm.Text4.value = thisform.ovfp.fields.contact

      ThisForm.Text5.value = thisform.ovfp.fields.title

   ENDPROC

 

   PROCEDURE command4.Click

      lcs = thisform.ovfp.fields.company + chr(13)

      lcs = lcs +  thisform.ovfp.fields.contact + chr(13)

      lcs = lcs +  thisform.ovfp.fields.title + chr(13)

      _cliptext = lcs

      thisform.ovfp = .null.

      clea events

      thisform.release

   ENDPROC

 

ENDDEFINE

Besonders wichtig sind folgende Einstellungen:

   Desktop = .T.

   ShowWindow = 2

   AutoCenter = .T.

   AlwaysOnTop = .T.

Diese Einstellungen läßt die Maske über WinWord erscheinen und verhält sich nun wie ein eigenens Programm.

   ovfp = .NULL.

 

Diese Eigenschaft wird unser INETDCOM Objekt speichern.

Den dazugehörigen Code finden Sie im INIT der Form.

Sobald Sie einen Wert im Abfragefeld TEXT1 eingegeben haben und auf Abfrage clicken, wird ein Selectbefehl aufbereitet und an den VFP-Server geschickt.

Hat alles geklappt, so werden die Ausgabefelder gefüllt. Ein Vorwärts und Rückwärtsblättern ist ebenfalls als Buttons verfügbar.

Im Button ”Command4“, “Übernehmen” wird ein String zusammengestellt und an die Zwischenablage übergeben. Für andere Programme also leicht zum übernehmen.

Nun wird das Object vom VFP-Server zerstört und ein Clea Events ausgelöst. Das wiederum löst ein Zerstören der Maske aus. Unser Meisterwerk verschwindet wieder vom Bildschirm.

Kompilieren Sie dieses Projekt nun zu einer EXE. Das ist sehr wichtig, da nur EXE´s etwas auf den Bildschirm erscheinen lassen können. Als DLL würde die Bildschirmausgabe unterdrückt werden. Und unsere Form ist nun mal eine Bildschirmausgabe.

Alles was wir noch benötigen ist

Der WinWord-Teil

Wir müssen nun noch ein kleines Macro schreiben, damit wir unseren Client aufrufen können

Unter WinWord im Menüpunkt Tools finden Sie Macros. Dort erzeugen Sie ein Macro mit dem Namen vfpcustomer und speichern Sie folgenden Code dort ab: 

Dim ovfpword As Object

Set ovfpword = CreateObject("vfpword.customer")

ovfpword.getcustomer

Set ovfpword = Nothing

Selection.Paste

 

Dieser Code erzeugt nun mit createobject unseren VFP-Client. Dieser wiederum erzeugt das RemoteObjekt auf unserem MTS Server.

Mit ovfpword.getcustomer erscheint unsere Form und übernimmt die Steuerung. Nachdem wie einen Customer ausgewählt haben, wird das Object wieder zerstört und mit Selection.Paste der Inhalt der Zwischenablage eingefügt.

Am einfachsten ist es, wenn Sie das Macro auf eine Toolbar legen. Verwenden Sie dazu den Menüpunkt View / Toolsbars / Customize, bzw. das deutsche Pendant dazu. Sie können Sich nun eine eigene Toolbar anlegen das Kommando MACRO auswählen und bekommen Ihr Macro „vfpcustomer“ zur Auswahl.

Ziehen Sie dieses per Drag und Drop auf die neue Toolbar und verändern Sie eventuell das Aussehen zu einem Icon.

Wenn Sie das Macro auch noch in Ihre Normal.DOT abspeichern, haben Sie die Funktionalität jederzeit zur Verfügung.

Es wäre noch darauf hinzuweisen, daß Sie

Vfpcustomer.exe

Vfpcustomer.tlb

brauchen, wenn Sie die Maske auf einen anderen Computer einsetzen wollen.

Um es in der Registry einzutragen, verwenden Sie

vfpcustomer /regserver

Um es wieder zu deinstallieren, verwenden Sie

Vfpcustomer / unreg

Damit enden hier meine Sessionnotes. Sie sollten nun in der Lage sein, selbst Server zu schreiben, die von den verschiedensten Programmen verwendet werden können. Ich wünsche Ihnen nun viel Erfolg und auch noch viel Spaß bei der Programmierung.

Peter Herzog ist Gesellschafter der ProLib Software GmbH (http://www.prolib.de) seit 1996 ein Microsoft MVP (Most Valuable Professional) und Sie erreichen Ihn unter peter.herzog@prolib.de