:Revision=4
:html
<<
128.118
COM-Objekt|COM
$NoSort
--
Das IP-Objekt <!RW>COM dient dem Zugriff auf beliebige COM-Objekte
COM = Common Object Modell

 <b><u>Wichtig:</u></b>
Da die Realisierung eines COM Servers nicht im Bereich des Testprogrammes liegt und jeder COM Server beliebig gestaltet sein kann, ist die MCD Elektronik nicht in der Lage, Hilfstellung zu Problemen mit COM Objekten zu geben, die auerhalb des IP-Objektes COM liegen. Dies betrifft sowohl Hilfe zu syntaktischen Fragen als auch zu der Funktion eines bestimmten COM Servers. (Soweit dieser nicht von MCD stammt).</b>
>>

<<
128.118.1
Der Datentyp COMObject|ComObject
$NoSort
--

Das IP-Object <!RW>COM fhrt einen neuen Datentyp <!RW>ComObject ein, der zu keinem anderen Typen kompatibel ist und der internen Verwaltung des Zugriffs auf die COM Server dient.
>>
<<
128.118.1.1
Deklaration eines COMObjektes|Deklaration
!128.118.1.2
--
Ein COMObject wird wie eine Variable im VAR Bereich definiert:
<!CODE>
VAR
  rDelay : real;
  coCANoe : comobject;
<!TXT>

Ein derart definiertes ComObject ist dem Interpreter bekannt, besitzt aber noch keinen Inhalt und kann daher nicht direkt verwendet werden.
>>
<<
128.118.1.2
Instantiierung
!128.118.1.1
!128.118.1.3
--
Einen Inhalt und damit einen Verweis auf ein echtes, im System vorhandenes COM-Objekt wird mit Hilfe der Befehle <!RW>COM.Set, <!RW>COM.New oder <!RW>COM.Load oder durch direkte Zuweisung eines anderen COM-Unterobjektes hergestellt. Wurde das <!RW>ComObject mittels eines dieser Befehle instanziiert, so kann es wie ein eigenes IP-Objekt behandelt werden:
<!CODE>
STEP
  COM.New   (coCANoe, 'CANoe.Application');
  // ... Aktionen mit coCANOe durchfhren
  coCANoe.UI.Write.Output ('Hallo');
  coCANoe.Quit;
  COM.Delete (coCANoe);
END.
<!TXT>
>>
<<
128.118.1.3
Verwendung
!128.118.1.1
!128.118.1.2
!128.118.1.5
--
Ein ComObject kann (auer in den COM-Befehlen) nie allein verwendet werden. 
Stets wird auf eine Methode (Prozedur oder Funktion) oder eine Eigenschaft des ComObjects zugegriffen. 

Der Name dieser Methode oder Eigenschaft wird nach einem Punkt an das ComObject angehngt. Der Interpreter akzeptiert nach einem ComObject eine beliebige Folge weiterer Namen, die durch Punkte getrennt sind, da die Syntax nur innerhalb des COM-Servers implementiert ist. Der Interpreter sucht jedoch bei der Ausfhrung fr jeden weiteren Namen die entsprechende Realisierung innerhalb des echten COM-Objektes.

Folgende Aktionen sind mit den ComObject mglich:

<h5>1) Methodenaufruf (Prozeduraufruf)</h5>
<!SYN>
<!SW>coBeispiel.Methode [Parameterliste];
<!TXT>
<h5>2) Setzen einer Eigenschaft</h5>
<!SYN>
<!SW>coBeispiel.Eigenschaft [Parameterliste] := Ausdruck;
<!TXT>
<h5>3) Lesen einer Eigenschaft</h5>
<!SYN>
Debug.Show (1, <!SW>coBeispiel.Eigenschaft [Parameterliste]);
<!TXT>
<h5>4) Methodenaufruf (Funktionsaufruf)</h5>
<!SYN>
Debug.Show (1, <!SW>coBeispiel.Methode [Parameterliste]);
<!TXT>
<h5>5) Direkte Zuweisung eines UnterCOM-Objektes</h5>
<!SYN>
<!SW>coBeispiel := <!SW>coEinAnderes.<!SW>UnterObjekt;
<!TXT>
Ob eine ParameterListe vorhanden sein muss, hngt nur vom COM Objekt ab, das aufgerufen wird.

Die Aufrufarten knnen kombiniert werden:
<!CODE>
var
  coExcel, coWBK : comobject;
step
  COM.New (coExcel, 'Excel.Application');

  coExcel.visible:=true;
  coExcel.DisplayAlerts := False;

  WBK:=Excel.WorkBooks.Add;

  WBk.Worksheets.Item('Tabelle2').Range('E8', 'G12').Value := 'ABCDEFGHIJK';
  WBk.Worksheets.Item('Tabelle2').Range('E8', 'G12').Characters(1, 4).Font.Size := 20;
<!TXT>
>>
<<
128.118.1.4
Aufrufparamter in der Parameterliste|Parameter
--
Parameterlisten drfen auer Real-, String-, Vektor- und StringVetor-Werten auch COMObjecte enthalten. 

Fr Vektoren muss eine Besonderheit beachtet werden, siehe <a href="128.118.1.4.1">Sonderfall Vektoren</a>.

Felder, die in Visual Basic ber eckige Klammern angesprochen werden, werden im Interpreter in runden Klammern angesprochen.

Auch die Rckgabewerte von Eigenschaften oder Funktionen mssen Real, String oder Vector sein, eine Ausnahme gilt fr Werte, die innerhalb von COM-Aufrufen weiterverwendet werden, hier drfen auch COMObjekte zurckgegeben werden. Auch hier gelten Sonderregeln fr Vektoren.

Variablen, die als Parameter bergeben werden, werden in jedem Fall als Call By Reference bergeben, d.h. wenn der Server den Wert des Parameters ndert, ndert sich auch der Wert der Variablen. Dies gilt nicht fr Vektoren. Vektoren knnen NICHT als Call By Reference bergeben werden. Auch hier gelten vom normelen Interpreter abweichende Sonderreglen, siehe <a href="128.118.1.4.2">Sonderfall Call-By-Reference</a>.
>>
<<
128.118.1.4.1
Sonderfall Vektoren|Vektoren
--
Anders als bei 'normalen' Datentypen kann der Interpreter bei dem Datenaustausch nicht auf die automatische Typumwandlung des OLE Systems zurckgreifen, um die Datentypen mit dem Zielsystem abzugleichen. Vektoren mssen daher eine Zusatzinformation enthalten, die dem Interpreter sagt, in welcher Form die Daten bergeben werden sollen (Array of Byte, Array of Single, Array of Double etc.) Diese Zusatzinformation wird im ersten Element des Vektors gespeichert. Mglich Werte und damit Datentypen sind:
<!STBL>
<!+>Wert<!+>Datentyp<!>
<!c>16<!>ShortInt (Signed Int1)<!>
<!c>2<!>Smallint (Signed Int2)<!>
<!c>3<!>Integer (Signed Int4)<!>
<!c>20<!>Int64 (Signed Int8)<!>
<!c>17<!>Byte (Unsigned Int1)<!>
<!c>18<!>Word (Unsigned Int2)<!>
<!c>19<!>DWord (Unsigned Int4)<!>
<!c>21<!>QWord (Unsigned Int8)<!>
<!c>4<!>Single (Real4)<!>
<!c>5<!>Double (Real8)<!>
<!c>6<!>Currency<!>
<!ETBL>

Wenn der Vektor [1, 2, 3] als <!SW>Array <!SW>of <!SW>Byte bergeben werden soll, muss also eine 17 als erstes Element eingefgt werden. Der an den Interpreter zu bergebende Vektor ist also: [17, 1, 2, 3]. Die 17 wird nur intern benutzt und vor der bergabe an das Com-Objekt ausgefiltert.

Umgekehrt wird bei Rckgaben aus dem COM-Objekt im ersten Element eines Vektors der Datentyp mitgeliefert. Beispiel: Sendet ein COM-Objekt ein <!SW>Array <!SW>of <!SW>Single [1, 2, 3] zurck, so liefert der Interpreter den Vektor [4, 1, 2, 3].

Zum Einfgen des Format-Elements knnen entweder die normalen Interpreteroperationen (+, copy) oder die COM-Funktionen <!RW>COM.Pack und <!RW>COM.Unpack verwendet werden.
>>
<<
128.118.1.4.2
Sonderfall Call-By-Reference|Call-By-Reference
--
Wenn eine Methode eines COM Objektes einen Call-By-Reference Parameter erwartet, muss (wie im Interpreter) eine Variable angegeben werden.

Diese Variable muss vom Datentyp zu dem vom COM Objekt erwarteten Datentyp passen, d.h. <!RW>REAL fr alle numerischen und <!RW>STRING fr Zeichenketten.
Andere Datentypen (Vektoren etc.) knnen nicht als Call-By-Reference bertragen werden.

Speziell fr die numerischen Typen muss der Interpeter jedoch exakt denselben Datentyp bereitstellen den die Methode erwartet. Da der Interpreter intern nur den Datentyp <!SW>Double kennt, klappt eine direkte bergabe auch nur fr diesen Datentyp. Fr alle anderen Datentypen innerhalb des COM-Objektes muss dem Interpreter dieser Datentyp mitgeteilt werden. 
Dies geschieht durch die Angabe eines speziellen reservierten Wortes hinter der Variable. 
Diese speziellen Worte sind:
<!STBL>
<!+>Bezeichner<!+>Funktion (Datentyp)<!>
<!c><!RW>AsInt1<!>ShortInt, Signed Int1<!>
<!c><!RW>AsInt2<!>SmallInt, Signed Int2<!>
<!c><!RW>AsInt4<!>Integer, Signed Int4<!>
<!c><!RW>AsInt8<!>Int64, Signed Int8<!>
<!c><!RW>AsSingle<!>Single, Real4<!>
<!c><!RW>AsDouble<!>Double, Real8<!>
<!c><!RW>AsCurrency<!>Currency<!>
<!c><!RW>AsDate<!>Date<!>
<!c><!RW>AsUInt1<!>Byte, Unsigned Int1<!>
<!c><!RW>AsUInt2<!>Word, Unsigned Int2<!>
<!c><!RW>AsUInt4<!>DWord, Unsigned Int4<!>
<!c><!RW>AsUInt8<!>QWord, Unsigned Int8<!>
<!c><!RW>AsBool<!>Boolean<!>
<!c><!RW>AsVariant<!>Variant<!>
<!ETBL>
Wenn keiner dieser Bezeichner angegeben ist, wird eine numerische Variable als <!SW>Double bergeben, die Angabe von <!RW>AsDouble ist also optional.

Statt <!RW>AsVariant hinter der Variablen anzugeben, kann auch <!RW> vor der Variablen angegeben werden. 

Beispiele (Annahme: es handelt sich immer um Call-By-Reference Parameter)
<!CODE>
co.Method (rVar);           // bergabe als Double
co.Method (rVar AsDouble);  // wie oben, nur explizit
co.Method (rVar AsInt4);    // bergabe als 4 Byte Integer mit Vorzeichen 
co.Method (rVar AsUInt1);   // bergabe als Byte (ohne Vorzeichen)
co.Method (var rVar);       // bergabe als Variant (alte Methode)
co.Method (rVar AsVariant); // bergabe als Variant (neue Methode)
<!TXT>
>>
<<
128.118.1.5
Lebensdauer
--
COM-Objekte werden "Referenz-gezhlt". D.h. sobald eine Referenz auf ein Objekt erzeugt wird (dies geschieht das erste mal beim Erstellen eines Objektes) wird ein Referenzzhler um eines erhht. Jedesmal, wenn eine Referenz auf das Objekt ungltig oder gelscht wird, wird der Zhler um eins verringert. Wenn der Zhler 0 erreicht (keine Referenz mehr) wird das Objekt selbst gelscht.

Durch ein <!RW>COM.New wird der Referenzzhler des Objektes also auf 1 gesetzt - die Referenz befindet sich in der ComObject-Variablen. Wird die ComObject-Variable bei Step-Ende vernichtet, so geht die Referenz verloren und das Objekt wird vernichtet. Ohne besondere Vorkehrungen existiert ein COM-Objekt also nur bis zum Ende des Steps, in dem es erzeugt wurde. 

Soll das Objekt aber lnger existieren, z.B. im Boot-Step erzeugt und im Leave-Step gelscht werden, so muss eine zustzliche Referenz auf das COM-Objekt erzeugt werden, die lnger existiert als die Variable im erzeugenden Step. Da es nicht mglich ist, eine ComObject Variable in die Globalen Daten abzulegen, wurde eine neue Tabelle eingefhrt, in die Referenzen mit <!RW>COM.Store abgelegt und mit <!RW>COM.Load ausgelesen werden knnen.

Beispiel 1a ohne <!RW>COM.Store
<!CODE>
var
  co : ComObject;
step
  COM.New (co, 'MyTest.Object');	// Referenzzhler=1
  co. ....
end.  // implizite Vernichtung der Referenz und des Objektes bei Step-Ende		                    
<!TXT>
Da die Variable co mit Stepende vernichtet wird, wird der Referenzzhler um eins verringert, erreicht also 0 und das COM-Objekt wird zerstrt.

Beispiel 1b (auch ohne <!RW>COM.Store)
<!CODE>
var
  co : ComObject;
step
  COM.New (co, 'MyTest.Object');	// Referenzzhler=1
  co. ....
  COM.Delete (co);	// Explizite Vernichtung der der Referenz und des Objektes 
end.  
<!TXT>
Wie zuvor, nur wird hier die Referenz explizit gelscht.

Beispiel 2a (<!RW>COM.Store)
<!CODE>
var
  co : ComObject;
step
  COM.New (co, 'MyTest.Object');	// Referenzzhler=1
  COM.Store (co, 'MyTest.Object');	// Referenzzhler=2
  co. ....
end.  // implizite Vernichtung der Referenz in co bei Step-Ende		                    
      // Referenzzhler=1, da immer noch eine Referenz in der Tabelle 
<!TXT>
Beispiel 2b (<!RW>COM.Load)
<!CODE>
var
  co : ComObject;
step
  COM.Load (co, 'MyTest.Object');	// Referenzzhler=2
  co. ....
end.  // implizite Vernichtung der Referenz in co bei Step-Ende		                    
      // Referenzzhler=1, da immer noch eine Referenz in der Tabelle 
<!TXT>
Nun wird eine zweite Referenz in der Tabelle abgelegt. Wenn nun die erste Referenz in <!SW>co verloren geht, existiert immer noch eine Referenz in der Tablle, das Objekt wird also nicht zerstrt. Vielmehr kann in einem anderen Step die Referenz gelesen werden (dies erzeugt eine weitere Referenz in der Variablen) und das Objekt weiter verwendet werden.
Die Referenz in der Tabelle muss entweder explizit gelscht werden (<!RW>COM.Delete) oder geht bei Programmende automatisch verloren.
>>

<<
128.118.2
Funktionen des COM-Objekts|Funktionen
--
>>
<<
128.118.2.1
COM.IsActive|IsActive
--
<!DEF>
function <!TW>COM.IsActive : real;
<!TXT>
Liefert True, wenn <!RW>COM in der Grundeinstellung aktiviert ist.

Beispiel:
<!CODE>
if COM.IsActive then
begin
  Debug.SHOW(1, 'COM ist Aktive!');
  // ... z.B. COM Objekt laden
end;
<!TXT>

>>
<<
128.118.2.2
COM.Pack|Pack
--
<!DEF>
function <!TW>COM.Pack (vData : vector; rType : real) : vector;
<!TXT>
Macht aus dem Interpreter Vektor <!PW>vData ein Vektor, der fr COM-Operationen verwendet werden kann und als Array of &lt;<!PW>rType&gt; an das COM-Objekt bergeben wird.

Zulssige Werte fr <!PW>rType:
<!STBL>
<!>Smallint<!>=<!>2<!>
<!>Integer<!>=<!>3<!>
<!>Single<!>=<!>4<!>
<!>Double<!>=<!>5<!>
<!>Currency<!>=<!>6<!>
<!>Byte<!>=<!>17<!>
<!ETBL>

Die Funktion Pack fhrt im Prinzip folgende Aktion aus:
<!CODE>
lPacked:=[rType]+vData;
<!TXT>

Zustzlich wird aber noch <!PW>rType auf Gltigkeit geprft.
>>

<<
128.118.2.3
COM.Unpack|Unpack
--
<!DEF>
function <!TW>COM.Unpack (vPacked : vector;<u> <!SW>1 </u>) : vector;
<!TXT>
Entfernt die Typangabe aus dem fr COM-Operationen gepackten Vektor.

Entspricht folgender Operation:
<!CODE>
vData:=copy(vPacked, 2, len(vPacked)-1));
<!TXT>

<hr align=left width=10% size=1>

<!DEF>
function <!TW>COM.Unpack (vPacked : vector;<u> <!SW>2 </u>) : real;
<!TXT>
Liefert den Datentyp des fr COM-Operationen gepackten Vektors.

Entspricht folgender Operation:
<!CODE>
rType:= vPacked[1];
<!TXT>
>>

<<
128.118.2.4
COM.Exists|Exists
!128.118.3.3
--
<!DEF>
function <!TW>COM.Exists ( sName : string ) : real;
<!TXT>
Liefert <!RW>True, wenn <!PW>sName vorhanden ist.
>>

<<
128.118.3
Prozeduren des COM-Objekts|Prozeduren
--
>>
<<
128.118.3.1
COM.New|New
--
<!DEF>
procedure <!TW>COM.New (var coData : comobject; sServerName : string [; sRemoteHost : string]);
<!TXT>
Startet eine COM-Server. <!PW>sServerName gibt den Namen des Servers an, so, wie er in der Registry eingetragen ist. Bei erfolgreichen Aufruf enthlt das ComObject <!PW>coData einen Verweis auf das durch diesen Server realisierte COM Objekt. ber den optionalen Parameter <!PW>sRemoteHost kann ein fremder Rechner angegeben werden. Die Angabe des RemoteHost mu in der Form: '\\ComputerName' erfolgen. In dies der Fall, wird DCOM verwendet, um den Server auf dem entfernten Rechner zu starten.
>>
<<
128.118.3.2
COM.Set|Set
--
<!DEF>
procedure <!TW>COM.Set (var coNew : comobject; coSubObject : comobject);
<!TXT>
Lt das ComObject <!PW>coNew auf das mit <!PW>coSubObject angegebene COM Objekt zeigen.

Beispiel:
<!CODE>
VAR
  rCount : real;
  coCANoe, coWrite : comobject;

STEP
  COM.New   (coCANoe, 'CANoe.Application');

  // in der folgenden Schleife muss jedes mal
  // erst die Sub-Objekte UI und Write gesucht werden!
  for rCount:=1 to 1000 do begion
    coCANoe.UI.Write.Output ('Hallo');
  end;

  // schneller ist folgende Konstruktion:
  // coWrite direkt auf das Write-Objekt zeigen lassen!
  COM.Set (coWrite, coCANoe.UI.Write);
  for rCount:=1 to 1000 do begion
    coWrite.Output ('Hallo');
  end;

  // folgender Aufruf ist nicht gltig, da ...Output
  // kein Objekt, sondern eine Methode ist:
  COM.Set (coWrite, coCANoe.UI.Write.Output);
  for rCount:=1 to 1000 do begion
    coWrite ('Hallo');
  end;
end.
<!TXT>

Statt einem Aufruf der Prozedur <!RW>COM.Set kann auch direkt eine Zuweisung erfolgen:
<!CODE> 
  // der Aufruf von:
  COM.Set (coWrite, coCANoe.UI.Write.Output);

  // ist absolut quivalent zu:
  coWrite:=coCANoe.UI.Write.Output;
<!TXT>
>>
<<
128.118.3.3
COM.Store|Store
!128.118.3.4
--
<!DEF>
procedure <!TW>COM.Store (coData : comobject; sName : string);
<!TXT>
Speichert das ComObject <!PW>coData unter dem Namen <!PW>sName.
>>
<<
128.118.3.4
COM.Load|Load
!128.118.3.3
--
<!DEF>
procedure <!TW>COM.Load (var coData : comobject; sName : string);
<!TXT>
Holt ein zuvor gespeichertes ComObject mit dem Namen <!PW>sName nach <!PW>coData.
>>
<<
128.118.3.5
COM.Delete|Delete
--
<!DEF>
procedure <!TW>COM.Delete (var coData : comobject);
<!TXT>
Lscht ein ComObject. Lst damit die Verbindung zum COM-Server.
Ein weiterer Zugriff auf <!PW>coData ist nicht mehr erlaubt.
Ein Object wird automatisch bei Ende des Prfschrittes gelscht.

<!DEF>
procedure <!TW>COM.Delete (sName : string);
<!TXT>
Lscht ein unter dem Namen <!PW>sName gespeichertes ComObject. Gespeicherte ComObjects leben sonst ewig.
>>
