[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.
June 6th, 2010 at 12:36 pm
TO Dave B.
Use ‘\\.\COMx’ in COM port name…
November 22nd, 2010 at 11:51 am
Hi Alex,
your code works perfectly on Delphi 7 XP, but fails on Delphi1010, Windows 7 64 bit.
It fails on this line : Result := String(m_pBuf);
Do you have any idea what might be going wrong?
November 22nd, 2010 at 3:44 pm
Actually i quit delphi programming, but you can try something like that:
str : String;
…
SetLength(str, bufLength);
MemCopy(@str[0], m_pBuf, bufLength);
Result = str;
//not sure but probably can help.
P.S. sorry dont even remember pascal syntactics, so can make mistakes
November 22nd, 2010 at 4:39 pm
Ok thanks, I’ll give it a try.
July 5th, 2011 at 12:19 am
What is the EscapeCommFunction(,11) for? MS docs only list values up to 9 http://msdn.microsoft.com/en-us/library/aa363254(v=vs.85).aspx