[Windows] Working asynchronously with Com port on Delphi/Lazarus
Posted on March 7th, 2009 by admin
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
Filed under: Programming
October 30th, 2009 at 3:34 pm
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.