[Windows] Working asynchronously with Com port on Delphi/Lazarus

From time to time i have tasks to read/write data to Com port, for example:

1. Sending/Receiving sms (using GSM modem)

2. Working with com port connected printer

3. GPS device

4. Some exotic devices, so on

there tons components you can find using google, but perhaps i was so lazy to find what i need or something else… anyway there werent anything dificult so  i did my own :)

for that we need 8 WinApi functions:


CreateFile
GetCommState
SetCommState
SetCommTimeouts
EscapeCommFunction
CloseHandle
WriteFile
ReadFile

Opening Port:


function TComPort.Open() : Boolean;
var
PortDCB : TDCB;
Timeouts : COMMTIMEOUTS;
begin
Result := False;
FHandle := CreateFile(PChar(FName),
GENERIC_READ or GENERIC_WRITE,
0, nil, OPEN_EXISTING,
0, 0); //trying to open com port

if (FHandle = INVALID_HANDLE_VALUE) then
exit;//com port was nor oppened for some reasons

FillChar(PortDCB, sizeof(TDCB), #0);
PortDCB.DCBlength := sizeof(TDCB);
GetCommState(FHandle, PortDCB); //getting port state

PortDCB.BaudRate := FBaudRate;
PortDCB.ByteSize := 8;
PortDCB.Parity := NOPARITY;
PortDCB.StopBits := ONESTOPBIT;
PortDCB.Flags := FFlags;//4243;

if (not SetCommState(FHandle, PortDCB)) then
exit;

Timeouts.ReadIntervalTimeout := MAXDWORD;
Timeouts.ReadTotalTimeoutMultiplier := MAXDWORD;
Timeouts.ReadTotalTimeoutConstant := FReadTimeOut; //read timeout
Timeouts.WriteTotalTimeoutMultiplier := MAXDWORD;
Timeouts.WriteTotalTimeoutConstant := FWriteTimeOut; //write timeout

if (not SetCommTimeouts(FHandle, Timeouts)) then
exit;

EscapeCommFunction(FHandle, 11);

Result := True;
end;

Reading from port:


function TComPort.Read() : String;
var
dwRead : Cardinal;
begin
Result := '';
//reading from port
ReadFile(FHandle, m_pBuf^, 1024, dwRead, nil);
Result := String(m_pBuf);
SetLength(Result, dwRead);
end;

Writing to port:


Function TComPort.Write(AData : string) : boolean;
var
m_ppBuf : Pointer;
dwWrote, dwCurWrote : Cardinal;
begin
Result := False;
m_ppBuf := @Pointer(AData)^;
dwWrote := 0;
while (dwWrote < Length(AData)) do

begin
//writing to port
if (not WriteFile(FHandle, Pointer(LongInt(m_ppBuf) + dwWrote)^, length(AData) - dwWrote, dwCurWrote, nil)) then
begin
exit;
end;

Inc(dwWrote, dwCurWrote);
end;

Result := True;
end;

P.S. Download class, sources and example application you can from:

http://alexmogurenko.com/Examples/ComPort.zip

One Response to “[Windows] Working asynchronously with Com port on Delphi/Lazarus”

  1. 1
    Dave Baxter Says:

    Alex. Thanks for this example, most useful, especialy as my D7 help system seems broken at the mo.

    Anyway, a question. Any reason why this spits fethers out, if you try to use a com port higher than com4? Running on XP Pro.

    I have some devices that present virtual ports to the app’s at or above COM5 by default. If I force them to create a virtual com port at COM1 for example (no physical device exists there) then your example works great. But COM5 or higher, all sorts of problems, pointer errors, out of bounds etc etc. Odd.

    XP of course, supports “COMx” ports where x = 1 to 255 if needed.

    The above email does work, just I may not be able to check it as often as I’d like.

    Regards.

    Dave B.

Leave a Reply