:Revision=6
:html
<<
128.122
DLL-Objekt|DLL
--
Das IP-Objekt DLL erlaubt den Zugriff auf (fast) beliebige DLLs. Hierdurch knnen bei der Programmentwicklung unbekannte Treiber-DLL etc. eingebunden werden.

Aufgrund der eingeschrnkten Typauswahl des Interpreters knnen jedoch nicht alle Aufrufparametertypen angeprochen werden.

Die Verwendung einer externen DLL luft immer nach einem bestimmten Schema ab:
<ol indent=20>
<li>ffnen der DLL - meldet die DLL beim Interpreter an</li>
<li>Registrieren der verwendeten Funktionen / Prozeduren - legt die Anzahl und Art der Parameter fest</li>
<li>Aufruf der Funktionen / Prozeduren</li>
<li>Schlieen der DLL</li>
</ol>

Das ffnen und Registrieren knnen im Startstep geschehen, die Definitionen bleiben bis zum Endstep erhalten. Bei Prfungs- oder Programmende werden alle offenen DLLs automatisch geschlossen. 
>>
<<
128.122.1
Funktionen des DLL-Objekts|Funktionen
--
>>
<<
128.122.1.1
DLL.Call|Call
!128.122.2.4
!128.122.2.5
$NoHelpDebug
!128.122.1.3
--
<!DEF>
function <!TW>DLL.Call (sDLLAlias, sProcAlias : string {; <i>Parameter</i> }) : <i>type</i>;
<!TXT>
Ruft die zuvor registrierte Funktion in der DLL auf und gibt einen Wert zurck. Die Parameter und der Datentyp des Ergebnisses ist abhngig von der Registrierung.
>>

<<
128.122.1.2
DLL.GetValue|GetValue
!128.122.2.5
--
<!DEF>
function <!TW>DLL.GetValue : real;
<!TXT>
Liefert den Rckgabewert der zuletzt aufgerufenen DLL-Routine. Dieser Wert ist nur dann sinnvoll, wenn zuvor eine Routine in einer DLL aufgerufen wurde, die einen Integerwert liefert. In allen anderen Fllen ist der zurckgegebene Wert nicht definiert.

Ist identisch mit der Prozedur <!RW>DLL.GetValue, nur als Funktion.
>>

<<
128.122.1.3
DLL.SafeCall|SafeCall
!128.122.1.1
--
<!DEF>
function <!TW>DLL.SafeCall (sDLLAlias, sProcAlias : string {; <i>Parameter</i> }) : <i>type</i>;
<!TXT>
Ruft die zuvor registrierte Funktion in der DLL auf und gibt einen Wert zurck. Die Parameter und der Datentyp des Ergebnisses ist abhngig von der Registrierung.

Ist identisch mit der Funktion <!RW>DLL.Call mit der Ausnahme, das Exceptions in der DLL, wegen Problemen bei Gleitkommaberchnungen abgefangen werden und nicht zum Abbruch der Funktion fhren. Dies ist fr einige Typen externe Dlls notwendig, weil diese das Exceptionhandling der Gleitkommaberechnung manipulieren (Fr mehr Informationen siehe 8087CW in MSDN oder Delphi-Hilfe).
>>

<<
128.122.2
Prozeduren des DLL-Objekts|Prozeduren
--
>>

<<
128.122.2.1
DLL.Open|Open
--
<!DEF>
procedure <!TW>DLL.OPEN (sAlias, sDLLFilename : string [; rPersistent : real]);
<!TXT>
ffnet die DLL in der Datei <!PW>sDLLFilename unter dem internen Alias <!PW>sAlias. Standarddateiendung ist DLL, Standardpfad ist das Verzeichnis mit der EXE-Datei des Prfprogrammes. Verzeichnisschablonen knnen verwendet werden. Ein Fehler wird erzeugt, wenn die DLL nicht gefunden wird oder nicht geffnet werden kann.

Eine zuvor unter dem gleichen Alias geffnete DLL wird geschlossen.

 <!PW>rPersistent ist ein logischer Wert, der festlegt, ob die DLL ber das Ende eines Testablaufes hinaus geffnet bleibt. <!RW>False (Default): Die DLL wird automatisch nach Ende eines Tests geschlossen und muss im nchsten Testablauf wieder geffnet werden. <!RW>True : Die DLL wird erst bei Programmende geschlossen.
>>

<<
128.122.2.2
DLL.Close|Close
--
<!DEF>
procedure <!TW>DLL.CLOSE (sAlias : string);
<!TXT>
Schliet die DLL mit dem Alias <!PW>sAlias. Alle Registrierungen werden gelscht. Sollte keine solche DLL offen sein, so passiert nichts.
>>

<<
128.122.2.3
DLL.Register|Register
--
<!DEF>
procedure <!TW>DLL.REGISTER (sDLLAlias, sProcName, sParaDef : string [; sProcAlias : string]);
<!TXT>
<!DEF>
procedure <!TW>DLL.REGISTER (sDLLAlias : string; rProcIdx : real; sParaDef, sProcAlias : string);
<!TXT>
Sucht die Prozedur mit dem Namen <!PW>sProcName in der DLL zum <!PW>sDLLAlias. Ist ein <!PW>sProcAlias angegeben, so wird die Prozedur unter diesem Namen vermerkt, ansonsten unter ihrem <!PW>sProcName. Alternativ kann der Index der Prozedur statt ihres Namens angegeben werden. Dann ist ein <!PW>sProcAlias zwingend.

 <!PW>sParaDef legt das Aufrufformat der Prozedur fest:
Der erste Buchstabe gibt den Aufruftyp an.
'P' -> pascal, 'C' -> cdecl, 'S' -> stdcall
Der Aufruftyp MUSS UNBEDINGT mit dem Aufruftyp der Routine in der DLL bereinstimmen.
Der zweite Buchstabe mu ein Doppelpunkt ':' sein.
Die Lnge des zweiten Teils von <!PW>sParaDef variiert je nach Anzahl der Parameter der registrierten Routine. Die Codes fr die einzelnen Parameter werden durch Kommas getrennt. Folgende Codes sind definiert:

<!STBL>
<!+>Code<!+>Typ<!+>Beschreibung<!>
<!>'I'<!>Integer<!>Ganzzahl, Bereich -2<sup>31</sup>2<sup>31</sup>-1 bzw. -2147483648..2147483647<!>
<!>'B'<!>Byte<!>Ganzzahl, Bereich 0..2<sup>8</sup>-1  bzw. 0..255<!>
<!>'W'<!>Word<!>Ganzzahl, Bereich 0..2<sup>16</sup>-1  bzw. 0..65535<!>
<!>'T'<!>DWord<!>Ganzzahl, Bereich 0..2<sup>32</sup>-1  bzw. 0..4294967295<!>
<!>'L'<!>Boolean<!>Logikwert<!>
<!>'C'<!>Char<!>Zeichen (String mit Lnge 1 Zeichen)<!>
<!>'R'<!>Real<!>Fliekommazahl<!>
<!>'E'<!>Extended<!>Fliekommazahl<!>
<!>'D'<!>Double<!>Fliekommazahl<!>
<!>'S'<!>Single<!>Fliekommazahl<!>
<!>'P'<!>String<!>Zeichenkette<!>
<!>'A'<!>Array<!>Byte-Array<!>
<!ETBL>

Wird ein 'V' vor dem Code angegeben, so erfolgt der Aufruf Call-By-Reference (Zeiger auf den Parameter wird bergaben, Parameter kann gendert werden), ohne 'V' erfolgt die bergabe Call-By-Value (Wert des Parameters wird bergeben, Parameter kann nicht gendert werden). Fr Call-By-Reference Parameter mssen spter Variablen angegeben werden, Call-By-Value knnen beliebige Ausdrcke sein. Auch die Definition der Parameterliste ist uerst kritisch und mu sehr sorgfltig durchgefhrt werden, da fehlerhafte Parameterdefinitionen zu Fehler beim Aufruf, zu falschen Ergebnissen oder zum Absturz des Systems (auch mit Datenverlust) fhren knnen.
Erfolgt der Aufruf Call-By-Reference (mit 'v'), kann hinter 'P' und 'A' (String und Array) die Gre des Speicherplatzes angegeben werden, der fr den Rckgabewert der DLL bereitgestellt wird.
'P250' - es werden 250 Byte Rckgabepuffer bereitgestellt
'A2097152' - es wird ein Puffer von 2097152 Byte (2MB!) bereitgestellt.
Die DLL darf nicht mehr Byte zurckgeben als Puffer bereitgestellt wurde! Beim Aufruf wird sowohl fr 'A' als auch fr 'P' ein String erwartet. Der Unterschied besteht darin, dass bei 'P' der Rckgabestring als nullterminiert betrachtet wird, whrend bei 'A' der gesamte Puffer zurckgegeben wird. Der Interpreterschritt muss sich bei 'A' selbst darum kmmern, welcher Teil sinnvolle Daten enthlt.
Wird P und A mit V benutzt wird als referenze ein einfacher Pointer erwartet und kein Pointer auf den Pointer des Char Strings und des Array Pointers in der DLL.

Neu ab Rev.6:
Der Interpreter kann (auer Integer) weitere Rckgabetypen verarbeiten. Folgt nach der Parameterliste ein Doppelpunkt (':'), so wird dahinter die Angabe des Rckgabedatentyps erwartet. Folgende Datentypen sind mglich:

<!STBL>
<!+>Code<!+>Typ<!>
<!>'I'<!>Integer<!>
<!>'B'<!>Byte<!>
<!>'W'<!>Word<!>
<!>'T'<!>DWord<!>
<!>'L'<!>Boolean<!>
<!>'C'<!>Char<!>
<!>'VI'<!>Zeiger auf Integer<!>
<!>'VB'<!>Zeiger auf Byte (auch als bool / 1byte verwendbar)<!>
<!>'VW'<!>Zeiger auf Word<!>
<!>'VT'<!>Zeiger auf DWord<!>
<!>'VL'<!>Zeiger auf Boolean (longbool / 4byte) <!>
<!>'VC'<!>Zeiger auf Char<!>
<!>'VD'<!>Zeiger auf Double<!>
<!>'VS'<!>Zeiger auf Single<!>
<!>'VP'<!>Zeiger auf nullterminierten String<!>
<!>'VAxx'<!>Zeiger auf Array der Lnge xx<!>
<!ETBL>

Bei Arrays muss eine Lnge angegeben werde, bei nullterminierten String darf keine Lnge angegeben sein.
Zeiger werden dereferenziert. Der Rckgabewert wird beim Aufruf  von DLL.Call als Funktion geliefert. Beim Aufruf von DLL.Get als Prozedur gehen andere Rckgabetypen als Integer verloren.

Beispiele
<!CODE>
DLL.Open ('Kernel32', 'C:\Windows\System32\Kernel32.dll');

// Kernel32.Beep nimmt 2 Parameter : Tonhhe in Hz und Dauer in ms
DLL.REGISTER ('Kernel32', 'Beep', 'S:I,I:L');
Debug.Show(1, DLL.Call ('Kernel32', 'Beep', 1000, 500));

// Kernel32.GetCommandLineA liefert die Kommandozeile der Exe
DLL.REGISTER ('Kernel32', 'GetCommandLineA', 'S::vP');
Debug.Show(1, DLL.Call ('Kernel32', 'GetCommandLineA'));

// GetEnvironmentVariableA liefert den Inhalt einer Umgebungsvariablen
DLL.REGISTER ('Kernel32', 'GetEnvironmentVariableA', 'S:P,vP200,I:I');
SetLen (sData, 200);
Debug.Show(1, DLL.Call ('Kernel32', 'GetEnvironmentVariableA', 'TEMP', sData, 200));
Debug.Show(1, sData);

// FormatMessage kann einen Windows Fehlercode in Klartext umwandeln.
// Fr einige Pointer, an die NIL bergeben werden soll, wurde in der Deklaration
// der Datentyp integer angegeben und als Wert wird 0 genannt!
DLL.Register ('Kernel32', 'FormatMessageA', 'S:I,I,I,I,vP250,I,I:I');
rSize:=DLL.Call('Kernel32', 'FormatMessageA', $3000, 0,
                 8,           // der Fehlercode
                 0,
                 sData, 250,  // Puffer und Lnge
                 0);
while (rSize > 0) and (sData[rSize]<=' ') do Dec(rSize);
sData:=copy(sData,1,rSize);
Debug.Show (1, sData);

DLL.Close ('Kernel32');
<!TXT>
>>

<<
128.122.2.4
DLL.Call|Call
!128.122.1.1
$NoHelpDebug
--
<!DEF>
procedure <!TW>DLL.Call (sDLLAlias, sProcAlias : string [;  Parameter ...]);
<!TXT>
Ruft die Prozedur mit dem Alias sProcAlias in der DLL mit sDLLAlias auf. Anzahl und Art der erwarteten Parameter hngt von den Angaben bei der Registrierung der Prozedur ab. Der Interpreter akzeptiert beim Syntaxcheck hier beliebige Parameter.
Bei dieser Art des Aufrufes geht ein eventueller Rckgabewert (Funktionsergebnis) verloren. Lediglich ein Integer-Ergebnis kann nachtrglich mit DLL.GetValue abgeholt werden.
Fr Funktionen in der DLL ist daher der Aufruf von DLL.Call als Funktion vorzuziehen.
>>

<<
128.122.2.5
DLL.GetValue|GetValue
!128.122.1.2
--
<!DEF>
procedure <!TW>DLL.GetValue (var rResult :real);
<!TXT>
Liefert den Rckgabewert der zuletzt aufgerufenen DLL-Routine in <!PW>rResult. Dieser Wert ist nur dann sinnvoll, wenn zuvor eine Routine in einer DLL aufgerufen wurde, die einen Integerwert liefert. In allen anderen Fllen ist der zurckgegebene Wert nicht definiert.
Identisch mit der Funtkion <!RW>DLL.GetValue, nur als Prozedur.
>>
