3.6 Die RSCOM-DLL in Delphi

 


Mit Delphi kann eine Windows-Funktionsbibliothek (Dynamic Linc Library, DLL) für den Einsatz in unterschiedlichen Programmiersprachen programmiert werden. Insbesondere bei der Arbeit mit Visual Basic ist dies ein einfacher und problemloser Zugang zur seriellen Schnittstelle.

 

Der Quelltext einer DLL unterscheidet sich kaum von dem eines normalen Programms. Erzeugt man in Delphi 4 ein neues Projekt und wählt dazu den Typ DLL, dann erscheint bereits der Rahmen mit dem Schlüsselwort "library" am Anfang. Nun können wie gewohnt mit "uses" die verwendeten Units angegeben werden. Dann folgen die globalen Variablen.

 

library RSCOM;

uses Windows, SysUtils, Classes;

var  SaveExit: Pointer;

     PortHandle: THandle;

     StartTime: Int64;

     TimeUnit: Real = 0.000838;

 

Es folgen die einzelnen Prozeduren und Funktionen. Für die Übergabe der Parameter aus anderen Programmiersprachen ist der Zusatz "stdcall" wichtig. Er bewirkt unter anderem, dass Parameter nicht in Registern sondern auf den Stack übergeben werden. Wenn mehr als ein Parameter an eine Prozedur oder Funktion übergeben werden soll, bewirkt diese Einstellung, dass Parameter in der Reihenfolge von rechts nach links übergeben werden.

 

Aufmerksamkeit erfordert Übergabe von Zeichenketten. Hier muss grundsätzlich der Typ PChar (Zeiger auf einen Nullterminierten String) verwendet werden. Dies ist wichtig für OpenCOM, SendString und ReadString. Diese Anpassungen sollen hier für die Prozeduren TimeOuts und OpenCOM gezeigt werden.

 

procedure TIMEOUTS (TOut: Integer); stdcall;

var TimeOut:TCOMMTIMEOUTS;

begin

   TimeOut.ReadIntervalTimeout:=1;

   TimeOut.ReadTotalTimeoutMultiplier:=1;

   TimeOut.ReadTotalTimeoutConstant:=TOut;

   TimeOut.WriteTotalTimeoutMultiplier:=10;

   TimeOut.WriteTotalTimeoutConstant:=TOut;

   SetCommTimeouts(PortHandle,TimeOut);

end;

 

function OPENCOM (OpenString: pchar): Integer;

var PortStr, Parameter :String;

    DCB: TDCB;

begin

   Result := 0;

   if PortHandle > 0 then CloseHandle(PortHandle);

   Parameter := OpenString;

   PortStr := copy (Parameter,1,4);

   PortHandle:=CreateFile(PChar(PortStr),GENERIC_READ or

     GENERIC_WRITE,0,NIL,OPEN_EXISTING,0,0);

   GetCommState(PortHandle,DCB);

   BuildCommDCB(PChar(Parameter),dcb);

   DCB.Flags := 1;

   if SetCommState(PortHandle,DCB)then Result := 1;

   TimeOuts (10);

end;

 

Alle bisherigen Prozeduren aus der Unit RSCOM.PAS können mit der Aufrufkonvention stdcall in die DLL übernommen werden. Grundsätzlich ist in einer DLL für Windows32 die Groß/Kleinschreibung wichtig. Damit es bei der Übergabe nicht zu Fehlern kommt, werden hier alle Funktionen und Prozeduren mit Großbuchstaben bezeichnet. In Delphi war man dagegen frei in der Schreibweise.

 

Alle Funktionen und Prozeduren, die nach außen exportiert werden sollen, müssen am Ende des Quelltextes mit "exports" in einer Index-Liste angegeben werden.

 

exports

  OPENCOM index 1,

  TIMEOUTS index 2,

  BUFFERSIZE index 3,

  CLOSECOM index 4,

  SENDBYTE index 5,

  READBYTE index 6,

  SENDSTRING index 7,

  READSTRING index 8,

  CLEARBUFFER index 9,

  INBUFFER index 10,

  OUTBUFFER index 11,

  DTR index 12,

  RTS index 13,

  TXD index 14,

  CTS index 15,

  DSR index 16,

  RI  index 17,

  DCD index 18,

  INPUTS index 19,

  TIMEINIT index 20,

  TIMEREAD index 21,

  DELAY index 22,

  REALTIME index 23,

  NORMALTIME index 24;

 

 

Besondere Aufmerksamkeit erfordern der Start und die Beendigung der DLL. Hier muss sichergestellt werden, dass die Schnittstellen auch dann geschlossen werden, wenn ein Programm, das die DLL aufgerufen hat, unvorschriftsmäßig beendet wird.

 

Delphi stellt in einer DLL die Variable DLLProc als einen Zeiger auf eine Prozedur zur Verfügung, die von einem DLL-Eintrittspunkt aufgerufen wird. Diese Variable ist bereits in der Unit SYSINIT.DCU deklariert, die automatisch in jedes DLL-Projekt eingebunden wird. Man braucht diesen Pointer nur mit der Adresse einer Prozedur zu füllen, die beim DLL-Eintritt aufgerufen werden soll, also z. B. beim ersten Aufruf der DLL aus einem VB-Programm. Eine Prozedur, die DLLProc zugewiesen wird, muss einen Parameter des Typs Integer erhalten.

 

procedure LibraryProc(Reason: Integer);

 

Beim Aufruf der Prozedur enthält der Parameter Reason einen Wert zwischen 0 und 3, der den genauen Grund für den Aufruf enthält. In der Procedur LibraryProc wird eine eventuell noch geöffnete Schnittstelle geschlossen. Ein erfolgreicher Aufruf von OPENCOM weist der globalen Variablen PortHandle ein gültiges Handle zu. Wenn nun der Entry-Point erneut aufgerufen wird, bevor die Schnittstelle geschlossen werden konnte, findet die Prozedur LibraryProc das Handle vor und schließt sie. Damit die Prozedur tatsächlich ausgeführt wird, muss im Hauptteil der DLL zwischen begin und end die Adresse der Prozedur, also @LibraryProc der Variablen DLLProc zugewiesen werden.

 

 

procedure LibExit;

begin

  if PortHandle> 0 then Closecom;

  ExitProc := SaveExit;

end;

 

procedure LibraryProc(Reason: Integer);

begin

 if (Reason = DLL_PROCESS_DETACH) then

 if (PortHandle> 0) then Closecom;

end;

 

 

begin

  SaveExit := ExitProc;

  ExitProc := @LibExit;

  DLLProc := @LibraryProc;

end.

 

Genauso wichtig ist das korrekte Verlassen der DLL. So wie DLLProc beim Start der DLL verwendet wird, ist ExitProc ein Zeiger auf eine Prozedur, die beim Entfernen der DLL ausgeführt werden soll. Es ist hier die Prozedur LibExit, in der ebenfalls die Schnittstelle geschlossen wird. Ein alter Wert des Zeigers ExitProg wird in SaveExit zwischengespeichert und beim Verlassen wiederhergestellt.

 

Download: Die RSCOM.DLL 

weiter
zurück