自编的多线程串口通讯原码,
多给点分
unit SCommer;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,PKGUNIT;
const
PWM_GOTCOMMDATA = WM_USER + 1;
PWM_ERROCCUR = WM_USER+2;
PWM_COMMEVENT = WM_USER+3;
type
ECommsE0rror = class( Exception );
TReadThread = class( TThread )
protected
procedure Execute; override;
public
hCommFile: THandle;
hCloseEvent:THandle;
hCommWindow:THandle;
function SetupCommEvent(lpOverlappedCommEvent: POverlapped;
var lpfdwEvtMask: DWORD ): Boolean;
function SetupReadEvent(lpOverlappedRead: POverlapped;
lpszInputBuffer: LPSTR; dwSizeofBuffer: DWORD;
var lpnNumberOfBytesRead: DWORD ): Boolean;
function HandleCommEvent(lpOverlappedCommEvent: POverlapped;
var lpfdwEvtMask: DWORD; fRetrieveEvent: Boolean ):Boolean;
function HandleReadEvent(lpOverlappedRead: POverlapped;
lpszInputBuffer: LPSTR; dwSizeofBuffer: DWORD;
var lpnNumberOfBytesRead: DWORD ): Boolean;
function HandleReadData(lpszInputBuffer: LPCSTR; dwSizeofBuffer: DWORD ):Boolean;
function EventOccur(EvtType: byte):BOOL;
function ErrorsOccur(ErrType: byte):BOOL;
function ReceiveData(lpNewString: LPSTR; dwSizeofNewString: DWORD ): BOOL;
end;
TWriteThread = class( TThread )
protected
procedure Execute; override;
function HandleWriteData(lpOverlappedWrite: POverlapped;pDataToWrite: PChar;
dwNumberOfBytesToWrite: DWORD): Boolean;
public
hCommFile:THandle;
hCloseEvent:THandle;
hCommWindow:THandle;
function WriteComm(pDataToWrite: LPCSTR; dwSizeofDataToWrite: DWORD): Boolean;
function ErrorsOccur(ErrType:byte):BOOL;
end;
TReceiveDataEvent = procedure( Buffer: Pointer; BufferLength: Word ) of object;
TErrorsEvent = procedure(ErrType:byte) of object;
TCommEvent = procedure(EventType:byte) of object;
emParity = (NoParity,OddParity,EvenParity,MarkParity,SpaceParity);
emStopBits =(OneStopBit,One5StopBits,TwoStopBits);
TCOMMPORT = class(TComponent)//TCustomControl
private
ReadThread: TReadThread;
WriteThread: TWriteThread;
FCommPort: string;
lpModemStat: DWORD;
lpEvtMask: DWORD;
hCommFile: THandle;
dcb: Tdcb;
commtimeouts: TCommTimeouts;
hCloseEvent: THandle;
FOnReceiveData: TReceiveDataEvent;
FOnErrOccur: TErrorsEvent;
FOnCommEvent: TCommEvent;
FHWnd: THandle;
FBaudRate: DWORD;
FByteSize: byte;
FParity: emParity;
FStopBits: emStopBits;
FXONChar: char;
FXOFFChar: char;
FErrorChar: char;
FEofChar: char;
FEvtChar: char;
FCTSHolding,FDSRHolding,FRLSDHolding,FSDBufState: boolean;
//TimeOut Parameters
FReadIntervalTimeout : DWORD;
FReadTotalTimeoutMultiplier : DWORD;
FReadTotalTimeoutConstant : DWORD;
FWriteTotalTimeoutMultiplier : DWORD;
FWriteTotalTimeoutConstant : DWORD;
FInQueue : DWORD;
FOutQueue : DWORD;
function GetReceiveDataEvent: TReceiveDataEvent;
procedure SetReceiveDataEvent( AReceiveDataEvent: TReceiveDataEvent );
function GetErrEvent:TErrorsEvent;
procedure SetErrEvent(AErrEvent:TErrorsEvent);
function GetCommEvent:TCommEvent;
procedure SetCommEvent(ACommEvent:TCommEvent);
procedure CommWndProc( var msg: TMessage );
//setup the port parameters
procedure SetBaudRate(value
WORD);
procedure SetByteSize(value:BYTE);
procedure SetParity(value:emParity);
procedure SetStopBits(value:emStopBits);
procedure SetXONChar(value:CHAR);
procedure SetXOFFChar(value:CHAR);
procedure SetErrorChar(value:CHAR);
procedure SetEofChar(value:CHAR);
procedure SetEvtChar(value:CHAR);
//setup the timeout parameters
procedure setRIT(value
WORD);
procedure setRTTM(value
WORD);
procedure setRTTC(value
WORD);
procedure setWTTM(value
WORD);
procedure setWTTC(value
WORD);
procedure setInQueue(value
WORD);
procedure setOutQueue(value
WORD);
function GetCTS:boolean;
function GetDSR:boolean;
function GetRLSD:boolean;
Function GetTxBufState:Boolean;
protected
procedure CloseReadThread;
procedure CloseWriteThread;
procedure ReceiveData(Buffer: PChar; BufferLength: Word );
procedure EventOccur(EvtType:byte);
procedure ErrorsOccur(ErrType:byte);
public
constructor Create(AOwner:TComponent); override;
destructor Destroy; override;
function OpenComm: byte;
function Purge(Act:byte):boolean;
procedure CloseComm;
function Send( pDataToWrite: PChar; dwSizeofDataToWrite: Word ): Boolean;
procedure Dial(TelNo:string);
procedure Hangup;
function ChkSum(buf
ointer;LBound,RBound:byte):byte;
function CRC(buf
ointer;Lbound,RBound
WORD):WORD;
procedure PackDat(ps:TPackageStyle; sbuf
ointer;ssize:WORD;
var dbuf
ointer;var dsize:WORD);
function UnPackDat(ps:TPackageStyle; sbuf
ointer;ssize:WORD;
var dbuf
ointer;var dsize:WORD):Boolean;
function SetDTRStat(Stat:boolean):boolean;
published
{ Published declarations }
property CommPort: string read FCommPort write FCommPort;
property BaudRate: DWORD read FBaudRate write SetBaudRate default 9600;
property ByteSize: Byte read FByteSize write SetByteSize default 8;
property Parity: emParity read FParity write SetParity default NOPARITY;
property StopBits: emStopBits read FStopBits write SetStopBits default ONESTOPBIT;
property XONChar:char read FXONChar write SetXONChar;
property XOFFChar:char read FXOFFChar write SetXOFFChar;
property ErrorChar:char read FErrorChar write SetErrorChar;
property EofChar:char read FEofChar write SetEofChar;
property EvtChar:char read FEvtChar write SetEvtChar;
property ReadIntervalTimeout: DWORD read FReadIntervalTimeout write SetRIT default 250;
property ReadTotalTimeoutMultiplier: DWORD read FReadTotalTimeoutMultiplier write SetRTTM default 0;
property ReadTotalTimeoutConstant: DWORD read FReadTotalTimeoutConstant write setRTTC default 0;
property WriteTotalTimeoutMultiplier: DWORD read FWriteTotalTimeoutMultiplier write setWTTM default 0;
property WriteTotalTimeoutConstant: DWORD read FWriteTotalTimeoutConstant write setWTTC default 0;
property InQueue
WORD read FInQueue write SetInQueue default 1024;
property OutQueue
WORD read FOutQueue write SetOutQueue default 1024;
property CTSHolding:Boolean read GetCTS;
property DSRHolding:Boolean read GetDSR;
property RLSDHolding:Boolean read GetRLSD;
Property TxBufStat:Boolean read GetTxBufState;
property OnDataRecieve: TReceiveDataEvent
read GetReceiveDataEvent write SetReceiveDataEvent;
property OnErrors: TErrorsEvent read GetErrEvent write SetErrEvent;
property OnCommEvent: TCommEvent read GetCommEvent write SetCommEvent;
end;
const
PWM_COMMWRITE = WM_USER+10;
INPUTBUFFERSIZE = 4096;//2048;
procedure Register;
{===============================================================================
==============================}implementation{==================================
===============================================================================}
{var
CommsLogName: string;}
(******************************************************************************)
// TCOMMPORT PUBLIC METHODS
(******************************************************************************)
constructor TCOMMPORT.Create(AOwner:TComponent);
begin
inherited Create(AOwner);
FCommPort := 'COM1';
FBaudRate:=CBR_9600;
FByteSize:=8;
FParity:=NOPARITY;
FStopBits:=ONESTOPBIT;
FReadIntervalTimeout := 250;
FInQueue:=1024;
FOutQueue:=1024;
//CommsLogName := '';
ReadThread := nil;
WriteThread := nil;
hCommFile := 0;
if not (csDesigning in ComponentState) then
FHWnd := AllocateHWnd(CommWndProc);
end;
destructor TCOMMPORT.Destroy;
begin
if not (csDesigning in ComponentState) then DeallocateHWnd(FHwnd);
inherited Destroy;
end;
function TCOMMPORT.Purge(Act:byte):boolean;
begin
case Act of
1: result := PurgeComm(hCommFile,PURGE_TXABORT);
2: result := PurgeComm(hCommFile,PURGE_RXABORT);
3: result := PurgeComm(hCommFile,PURGE_TXCLEAR);
4: result := PurgeComm(hCommFile,PURGE_RXCLEAR);
else result :=False;
end;
end;
//0:´ò¿ª´®¿Ú³É¹¦£»1£º½¨Á¢¾Ö±úʧ°Ü2£ºÊ§°Ü3£ºCloseEventʧ°Ü4£º½¨Òé¶ÁÏß³Ìʧ°Ü5£º½¨ÒéдÏß³Ìʧ°Ü
function TCOMMPORT.OpenComm: byte;
var
fdwEvtMask
WORD;
hNewCommFile:THandle;
begin
if (hCommFile <> 0) then
begin
result := 2;
exit;
end;
hNewCommFile := CreateFile(PChar(FCommPort),GENERIC_READ+GENERIC_WRITE,0,
nil,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,0);
if hNewCommFile = INVALID_HANDLE_VALUE then
begin
result := 1;
exit;
end;
if GetFileType( hNewCommFile ) <> FILE_TYPE_CHAR then
begin
result := 2;
exit;
end;
hCommFile := hNewCommFile;
GetCommState( hNewCommFile, dcb );
GetCommMask(hCommFile, fdwEvtMask );
GetCommTimeouts(hCommFile, commtimeouts );
with CommTimeouts do
begin
ReadIntervalTimeout := FReadIntervalTimeout;
ReadTotalTimeoutMultiplier := FReadTotalTimeoutMultiplier;
ReadTotalTimeoutConstant := FReadTotalTimeoutConstant;
WriteTotalTimeoutMultiplier := FWriteTotalTimeoutMultiplier;
WriteTotalTimeoutConstant := FWriteTotalTimeoutConstant;
end;
SetCommTimeouts( hCommFile, commtimeouts );
GetCommState (hNewCommFile,dcb);
with dcb do
begin
BaudRate := FBaudRate;
ByteSize := FByteSize;
Parity := byte(FParity);
StopBits := byte(FStopBits);
XOnChar:=FXOnChar;
XOffChar:=FXOffChar;
ErrorChar:=FErrorChar;
EofChar:=FEofChar;
EvtChar:=FEvtChar;
end;
SetCommState( hNewCommFile, dcb );
SetupComm(hNewCommFile,FInQueue,FOutQueue);
hCloseEvent := CreateEvent( nil, True, False, nil );
if hCloseEvent = 0 then
begin
hCommFile := 0;
Result := 3;
Exit;
end;
try
ReadThread := TReadThread.Create(True);
except
result:=4;
exit;
end;
ReadThread.hCommFile := hCommFile;
ReadThread.hCloseEvent := hCloseEvent;
ReadThread.hCommWindow := FHWnd;
ReadThread.Resume;
ReadThread.Priority := tpHighest;
try
WriteThread := TWriteThread.Create(True);
except
result:=5;
exit;
end;
WriteThread.hCommFile := hCommFile;
WriteThread.hCloseEvent := hCloseEvent;
WriteThread.hCommWindow := FHWnd;
WriteThread.Resume;
WriteThread.Priority := tpHigher;//ReadThread
GetCommModemStatus(hNewCommFile,lpModemStat);
if (lpModemStat and MS_CTS_ON) <> 0 then
FCTSHolding:= true;
if (lpModemStat and MS_DSR_ON) <> 0 then
FDSRHolding:= true;
if (lpModemStat and MS_RLSD_ON) <> 0 then
FRLSDHolding:= true;
// GetCommMask(HNewCommFile,lpEvtMask);
GetTxBufState;
Result := 0;
end; {TCOMMPORT.OpenComm}
procedure TCOMMPORT.SetBaudRate(Value
WORD);
begin
if FBaudRate<>Value then
begin
FBaudRate:=Value;
GetCommState (hCommFile,dcb);
dcb.BaudRate :=Value;//FBaudRate;
SetCommState( hCommFile, dcb );
end;
end;
procedure TCOMMPORT.SetByteSize(value:BYTE);
begin
if FByteSize<>Value then
begin
FByteSize:=Value;
GetCommState (hCommFile,dcb);
dcb.ByteSize := FByteSize;
SetCommState( hCommFile, dcb );
end;
end;
procedure TCOMMPORT.SetParity(value:emParity);
begin
if FParity<>Value then
begin
FParity := Value;
GetCommState (hCommFile,dcb);
dcb.Parity := byte(FParity);
SetCommState( hCommFile, dcb );
end;
end;
procedure TCOMMPORT.SetStopBits(value:emStopBits);
begin
if FStopBits<>Value then
begin
FStopBits := Value;
GetCommState (hCommFile,dcb);
dcb.StopBits := byte(FStopBits);
SetCommState( hCommFile, dcb );
end;
end;
procedure TCOMMPORT.SetXONChar(value:CHAR);
begin
if FXONChar<>Value then
begin
FXONChar := Value;
GetCommState (hCommFile,dcb);
dcb.XONChar := FXONChar;
SetCommState( hCommFile, dcb );
end;
end;
procedure TCOMMPORT.SetXOFFChar(value:CHAR);
begin
if FXOFFChar<>Value then
begin
FXOFFChar := Value;
GetCommState (hCommFile,dcb);
dcb.XOFFChar := FXOFFChar;
SetCommState( hCommFile, dcb );
end;
end;
procedure TCOMMPORT.SetErrorChar(value:CHAR);
begin
if FErrorChar<>Value then
begin
FErrorChar := Value;
GetCommState (hCommFile,dcb);
dcb.ErrorChar := FErrorChar;
SetCommState( hCommFile, dcb );
end;
end;
procedure TCOMMPORT.SetEofChar(value:CHAR);
begin
if FEofChar<>Value then
begin
FEofChar := Value;
GetCommState (hCommFile,dcb);
dcb.EofChar:= FEofChar;
SetCommState( hCommFile, dcb );
end;
end;
procedure TCOMMPORT.SetEvtChar(value:CHAR);
begin
if FEvtChar<>Value then
begin
FEvtChar:=Value;
GetCommState (hCommFile,dcb);
dcb.EvtChar := FEvtChar;
SetCommState( hCommFile, dcb );
end;
end;
procedure TCOMMPORT.setRIT(value
WORD);
begin
if FReadIntervalTimeout<> value then
begin
FReadIntervalTimeout:=Value;
GetCommTimeouts( hCommFile, commtimeouts );
commtimeouts.ReadIntervalTimeout := FReadIntervalTimeout;
SetCommTimeouts( hCommFile, commtimeouts );
end;
end;
procedure TCOMMPORT.setRTTM(value
WORD);
begin
if FReadTotalTimeoutMultiplier <> value then
begin
FReadTotalTimeoutMultiplier:=Value;
GetCommTimeouts( hCommFile, commtimeouts );
commtimeouts.ReadTotalTimeoutMultiplier := FReadTotalTimeoutMultiplier;
SetCommTimeouts( hCommFile, commtimeouts );
end;
end;
procedure TCOMMPORT.setRTTC(value
WORD);
begin
if FReadTotalTimeoutConstant <> value then
begin
FReadTotalTimeoutConstant:=Value;
GetCommTimeouts( hCommFile, commtimeouts );
commtimeouts.ReadTotalTimeoutConstant := FReadTotalTimeoutConstant;
SetCommTimeouts( hCommFile, commtimeouts );
end;
end;
procedure TCOMMPORT.setWTTM(value
WORD);
begin
if FWriteTotalTimeoutMultiplier <> value then
begin
FWriteTotalTimeoutMultiplier:=Value;
GetCommTimeouts( hCommFile, commtimeouts );
commtimeouts.WriteTotalTimeoutMultiplier := FWriteTotalTimeoutMultiplier;
SetCommTimeouts( hCommFile, commtimeouts );
end;
end;
procedure TCOMMPORT.setWTTC(value
WORD);
begin
if FWriteTotalTimeoutConstant <> value then
begin
FWriteTotalTimeoutConstant:=Value;
GetCommTimeouts( hCommFile, commtimeouts );
commtimeouts.WriteTotalTimeoutConstant := FWriteTotalTimeoutConstant;
SetCommTimeouts( hCommFile, commtimeouts );
end;
end;
procedure TCOMMPORT.setInQueue(value
WORD);
begin
if FInQueue <> value then
begin
setupComm(hCommFile,FInQueue,FOutQueue);
FInQueue:=value;
end;
end;
procedure TCOMMPORT.setOutQueue(value
WORD);
begin
if FOutQueue <> value then
begin
setupComm(hCommFile,FInQueue,FOutQueue);
FOutQueue:=value;
end;
end;
Function TCOMMPORT.GetTxBufState:Boolean;
begin
GetCommMask(HCommFile, lpEvtMask);
if (lpEvtMask and EV_TXEMPTY) <> 0 then
FSDBufState := True else FSDBufState := False;
result := FSDBufState;
end;
function TCOMMPORT.GetCTS:boolean;
begin
GetCommModemStatus(hCommFile,lpModemStat);
if (lpModemStat and MS_CTS_ON) <> 0 then
FCTSHolding:= true else FCTSHolding:= false;
result:=FCTSHolding;
end;
function TCOMMPORT.GetDSR:boolean;
begin
GetCommModemStatus(hCommFile,lpModemStat);
if (lpModemStat and MS_DSR_ON) <> 0 then
FDSRHolding:= true else FDSRHolding:= false;
result:=FDSRHolding;
end;
function TCOMMPORT.GetRLSD:boolean;
begin
GetCommModemStatus(hCommFile,lpModemStat);
if (lpModemStat and MS_RLSD_ON) <> 0 then
FRLSDHolding:= true else FRLSDHolding:= false;
result:=FRLSDHolding;
end;
procedure TCOMMPORT.CloseComm;
begin
if hCommFile = 0 then Exit;
Sleep(200);
CloseReadThread;
CloseWriteThread;
CloseHandle( hCloseEvent );
CloseHandle( hCommFile );
hCommFile := 0;
end; {TCOMMPORT.CloseComm}
function TCOMMPORT.Send( pDataToWrite: PChar; dwSizeofDataToWrite: Word ): Boolean;
var
Buffer: Pointer;
begin
if WriteThread <> nil then
begin
Buffer := Pointer(LocalAlloc( LPTR, dwSizeofDataToWrite+1 ));
Move( pDataToWrite^, Buffer^, dwSizeofDataToWrite );
if PostThreadMessage( WriteThread.ThreadID, PWM_COMMWRITE,
WPARAM(dwSizeofDataToWrite), LPARAM(Buffer) ) then
begin
Result := true;
Exit;
end
end;
Result := False;
end; {TCOMMPORT.Send}
procedure TCOMMPORT.Dial(TelNo:string);
begin
Send(pchar('ATDT'+TelNo+#13),length(TelNo)+5);
end;
procedure TCOMMPORT.Hangup;
begin
Send('+++',3);
Sleep(2000);//Sleep(3000);
Send(pchar('ATH'#13#10),5);
end;
function TCOMMPORT.ChkSum(buf
ointer;LBound,RBound:byte):byte;
begin
result := CheckSum(buf,LBound,RBound);
end;
function TCOMMPORT.CRC(buf
ointer;Lbound,RBound
WORD):WORD;
begin
result := CRC16(buf,Lbound,RBound);
end;
procedure TCOMMPORT.PackDat(ps:TPackageStyle; sbuf
ointer;ssize:WORD;
var dbuf
ointer;var dsize:WORD);
begin
PackData(ps,sbuf,ssize,dbuf,dsize);
end;
function TCOMMPORT.UnPackDat(ps:TPackageStyle; sbuf
ointer;ssize:WORD;
var dbuf
ointer;var dsize:WORD):Boolean;
begin
result := UnPackData(ps,sbuf,ssize,dbuf,dsize);
end;
function TCOMMPORT.SetDTRStat(stat:boolean):boolean;
begin
if stat then
result := EscapeCommFunction(hCommFile,SETDTR)
else
result := EscapeCommFunction(hCommFile,CLRDTR);
end;
(******************************************************************************)
// TCOMMPORT PROTECTED METHODS
(******************************************************************************)
procedure TCOMMPORT.CloseReadThread;
begin
if ReadThread <> nil then
begin
SetEvent(hCloseEvent );
PurgeComm(hCommFile,PURGE_RXABORT+PURGE_RXCLEAR);
if WaitForSingleObject(ReadThread.Handle,10000)=WAIT_TIMEOUT then
ReadThread.Terminate;
ReadThread.Free;
ReadThread := nil;
end;
end; {TCOMMPORT.CloseReadThread}
procedure TCOMMPORT.CloseWriteThread;
begin
if WriteThread <> nil then
begin
SetEvent(hCloseEvent);
PurgeComm(hCommFile,PURGE_TXABORT+PURGE_TXCLEAR);
if WaitForSingleObject(WriteThread.Handle,10000)=WAIT_TIMEOUT then
WriteThread.Terminate;
WriteThread.Free;
WriteThread := nil;
end;
end; {TCOMMPORT.CloseWriteThread}
procedure TCOMMPORT.ReceiveData( Buffer: PChar; BufferLength: Word );
begin
if Assigned(FOnReceiveData) then FOnReceiveData(Buffer,BufferLength );
end;
procedure TCOMMPORT.EventOccur(EvtType:byte);
begin
if Assigned(FOnCommEvent) then FOnCommEvent(EvtType);
end;
procedure TCOMMPORT.ErrorsOccur(ErrType:byte);
begin
if Assigned(FOnErrOccur) then FOnErrOccur(ErrType);
end;
{procedure TCOMMPORT.RequestHangup;
begin
if Assigned(FOnRequestHangup) then
FOnRequestHangup( Self );
end;}
(******************************************************************************)
// TCOMMPORT PRIVATE METHODS
(******************************************************************************)
procedure TCOMMPORT.CommWndProc( var msg: TMessage );
begin
case msg.msg of
PWM_GOTCOMMDATA:
begin
ReceiveData(PChar(msg.LParam), msg.WParam );
LocalFree( msg.LParam );
end;
PWM_ERROCCUR: ErrorsOccur(msg.WParam);
PWM_COMMEVENT: EventOccur(msg.WParam);
end;
end;
function TCOMMPORT.GetReceiveDataEvent: TReceiveDataEvent;
begin
Result := FOnReceiveData;
end;
procedure TCOMMPORT.SetReceiveDataEvent( AReceiveDataEvent: TReceiveDataEvent );
begin
FOnReceiveData := AReceiveDataEvent;
end;
function TCOMMPORT.GetErrEvent:TErrorsEvent;
begin
result := FOnErrOccur;
end;
procedure TCOMMPORT.SetErrEvent(AErrEvent:TErrorsEvent);
begin
FOnErrOccur := AErrEvent;
end;
function TCOMMPORT.GetCommEvent:TCommEvent;
begin
result := FOnCommEvent;
end;
procedure TCOMMPORT.SetCommEvent(ACommEvent:TCommEvent);
begin
FOnCommEvent:= ACommEvent;
end;
(******************************************************************************)
// READ THREAD
(******************************************************************************)
procedure TReadThread.Execute;
var
szInputBuffer: array [0..INPUTBUFFERSIZE-1] of char;
nNumberOfBytesRead: DWORD;
HandlesToWaitFor: array[0..2] of THandle;
dwHandleSignaled: DWORD;
fdwEvtMask: DWORD;
overlappedRead: TOverlapped;
overlappedCommEvent: TOverlapped;
label
EndReadThread;
begin
FillChar( overlappedRead, Sizeof(overlappedRead), 0 );
FillChar( overlappedCommEvent, Sizeof(overlappedCommEvent), 0 );
overlappedRead.hEvent := CreateEvent( nil, True, True, nil);
{
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes, // pointer to security attributes
//nil &para;&Euml;&iquest;&Uacute;&sup2;&raquo;&Auml;&Uuml;±&raquo;×&Oacute;&Iuml;&szlig;&sup3;&Igrave;&frac14;&Igrave;&sup3;&ETH;
BOOL bManualReset, // flag for manual-reset event
//±&Oslash;&ETH;è&Oacute;&Atilde; ResetEvent&Ecirc;&Ouml;&para;&macr;&cedil;&acute;&Icirc;&raquo;×&acute;&Igrave;&not;&micro;&frac12;&Icirc;&THORN;&ETH;&Aring;&ordm;&Aring;×&acute;&Igrave;&not;
BOOL bInitialState, // flag for initial state
//&sup3;&otilde;&Ecirc;&frac14;×&acute;&Igrave;&not;&Ecirc;&Ccedil;&Oacute;&ETH;&ETH;&Aring;&ordm;&Aring;&micro;&Auml;
LPCTSTR lpName // pointer to event-object name
//&Ecirc;&Acirc;&frac14;&thorn;&para;&Ocirc;&Iuml;ó&micro;&Auml;&Atilde;&ucirc;×&Ouml;
);
}
if overlappedRead.hEvent = 0 then
begin
GetLastError;errorsoccur(128);
goto EndReadThread;
end;
overlappedCommEvent.hEvent := CreateEvent( nil, True, True, nil);
if overlappedCommEvent.hEvent = 0 then
begin
GetLastError;errorsoccur(128);
goto EndReadThread;
end;
HandlesToWaitFor[0] := hCloseEvent;
HandlesToWaitFor[1] := overlappedCommEvent.hEvent;
HandlesToWaitFor[2] := overlappedRead.hEvent;
if not SetCommMask(hCommFile, EV_ERR or EV_BREAK or EV_CTS or EV_DSR or
EV_RING or EV_RLSD or EV_RXCHAR or
EV_RXFLAG or EV_TXEMPTY) then
{
&Ouml;&cedil;&para;¨&Ograve;&ordf;&frac14;à&Ecirc;&Oacute;&micro;&Auml;&acute;&reg;&iquest;&Uacute;&Ecirc;&Acirc;&frac14;&thorn;
EV_ERR &pound;&ordm;&Iuml;&szlig;&Acirc;·×&acute;&Igrave;&not;&sup3;&ouml;&acute;í
EV_CTS &pound;&ordm;(clear to send)&ETH;&Aring;&ordm;&Aring;&cedil;&Auml;±&auml;×&acute;&Igrave;&not;
EV_DSR
data send ready)&ETH;&Aring;&ordm;&Aring;&cedil;&Auml;±&auml;×&acute;&Igrave;&not;
EV_RING
)&Otilde;&ntilde;&Aacute;&aring;
EV_RLSD &pound;&ordm;&pound;¨receive line signal detect&pound;&copy;&frac12;&Oacute;&Ecirc;&Otilde;&Iuml;&szlig;&Acirc;·&ETH;&Aring;&ordm;&Aring;&frac14;ì&sup2;&acirc;×&acute;&Igrave;&not;&cedil;&Auml;±&auml;
EV_RXCHAR &pound;&ordm;&frac12;&Oacute;&Ecirc;&Otilde;&micro;&frac12;&micro;&Auml;·&Aring;&Egrave;&euml;&Ecirc;&auml;&Egrave;&euml;&raquo;&ordm;&sup3;&aring;&Ccedil;&oslash;&micro;&Auml;×&Ouml;·&ucirc;
EV_RXFLAG &pound;&ordm;&frac12;&Oacute;&Ecirc;&Otilde;&micro;&frac12;&micro;&Auml;·&Aring;&Egrave;&euml;&Ecirc;&auml;&Egrave;&euml;&raquo;&ordm;&sup3;&aring;&Ccedil;&oslash;&micro;&Auml;&Ecirc;&Acirc;&frac14;&thorn;×&Ouml;·&ucirc;
EV_TXEMPTY&pound;&ordm;&Ecirc;&auml;&sup3;&ouml;&raquo;&ordm;&sup3;&aring;&Ccedil;&oslash;&Ouml;&ETH;·&cent;&Euml;&Iacute;&micro;&Auml;×&icirc;&ordm;ó&Ograve;&raquo;&cedil;&ouml;×&Ouml;·&ucirc;
}
begin
GetLastError;
errorsoccur(128);
goto EndReadThread;
end;
// Start waiting for CommEvents
if not SetupCommEvent( @overlappedCommEvent, fdwEvtMask ) then
begin
GetLastError;errorsoccur(128);
goto EndReadThread;
end;
// Start waiting for Read events.
if not SetupReadEvent(@overlappedRead,szInputBuffer, INPUTBUFFERSIZE, //need to analyse later
nNumberOfBytesRead ) then
begin
GetLastError;errorsoccur(128);
goto EndReadThread;
end;
// Keep looping until we break out.
while True do
begin
// Wait until some event occurs (data to read; error; stopping).
dwHandleSignaled := WaitForMultipleObjects(3, @HandlesToWaitFor,
False, INFINITE);
{
WaitForMultipleObjects &micro;±
1&iexcl;&cent;&Ouml;&cedil;&para;¨&micro;&Auml;&para;&Ocirc;&Iuml;ó&acute;&brvbar;&Oacute;&Uacute;&Ouml;&cedil;&para;¨&micro;&Auml;×&acute;&Igrave;&not;.
2&iexcl;&cent;&sup3;&not;&Ecirc;±&sup3;&ouml;&Iuml;&Ouml;.
}
// Which event occured?
case dwHandleSignaled of
WAIT_OBJECT_0: // Signal to end the thread.
begin
// Time to exit.
goto EndReadThread;
end;
WAIT_OBJECT_0 + 1: // CommEvent signaled.
begin
// Handle the CommEvent.
if not HandleCommEvent( @overlappedCommEvent, fdwEvtMask, TRUE ) then //need to analyse later
begin
GetLastError;
errorsoccur(128);
goto EndReadThread;
end;
// Start waiting for the next CommEvent.
if not SetupCommEvent( @overlappedCommEvent, fdwEvtMask ) then//need to analyse later
begin
GetLastError;
errorsoccur(128);
goto EndReadThread;
end;
{break;??}
end;
WAIT_OBJECT_0 + 2: // Read Event signaled.
begin
// Get the new data!
if not HandleReadEvent(@overlappedRead,szInputBuffer, INPUTBUFFERSIZE,
nNumberOfBytesRead ) then
begin
GetLastError;
//errorsoccur(128); ×&cent;&Ecirc;&Oacute;&sup2;&iquest;·&Ouml;8&Ocirc;&Acirc;28&Egrave;&Otilde;&ETH;&THORN;&cedil;&Auml;
//goto EndReadThread;
//HandlesToWaitFor[0] := hCloseEvent;
//HandlesToWaitFor[1] := overlappedCommEvent.hEvent;
//HandlesToWaitFor[2] := overlappedRead.hEvent;
end;
// Wait for more new data.
if not SetupReadEvent( @overlappedRead,szInputBuffer, INPUTBUFFERSIZE,
nNumberOfBytesRead ) then
begin
GetLastError;
errorsoccur(128);
goto EndReadThread;
end;
{break;}
end;
WAIT_FAILED: // Wait failed. Shouldn't happen.
begin
GetLastError;
errorsoccur(128);
goto EndReadThread;
end;
else
begin
errorsoccur(128);
goto EndReadThread;
end;
end; {case dwHandleSignaled}
end; {while True}
EndReadThread:
PurgeComm( hCommFile, PURGE_RXABORT + PURGE_RXCLEAR );
{
&iquest;&Eacute;&Ograve;&Ocirc;&para;&ordf;&AElig;ú&Ouml;&cedil;&para;¨&para;&Euml;&iquest;&Uacute;&micro;&Auml;&Ecirc;&auml;&Egrave;&euml;&Ecirc;&auml;&sup3;&ouml;&raquo;&ordm;&sup3;&aring;&Ccedil;&oslash;&micro;&Auml;&Euml;ù&Oacute;&ETH;×&Ouml;·&ucirc;&pound;&not;&Ograve;&sup2;&iquest;&Eacute;&Ograve;&Ocirc;&frac12;á&Ecirc;&oslash;&Eacute;&ETH;&Icirc;&acute;&Iacute;ê&sup3;&Eacute;&micro;&Auml;&sup2;&Ugrave;×÷
PURGE_TXABORT &frac12;á&Ecirc;&oslash;&Euml;ù&Oacute;&ETH;&ETH;&acute;&sup2;&Ugrave;×÷&sup2;&cent;&Ccedil;&Ograve;&Aacute;&cent;&frac14;&acute;·&micro;&raquo;&Oslash;.
PURGE_RXABORT &frac12;á&Ecirc;&oslash;&Euml;ù&Oacute;&ETH;&para;&Aacute;&sup2;&Ugrave;×÷&sup2;&cent;&Ccedil;&Ograve;&Aacute;&cent;&frac14;&acute;·&micro;&raquo;&Oslash;.
PURGE_TXCLEAR &Ccedil;&aring;&sup3;&yacute;&Ecirc;&auml;&sup3;&ouml;&raquo;&ordm;&sup3;&aring;&Ccedil;&oslash;
PURGE_RXCLEAR &Ccedil;&aring;&sup3;&yacute;&Ecirc;&auml;&Egrave;&euml;&raquo;&ordm;&sup3;&aring;&Ccedil;&oslash;
}
CloseHandle( overlappedRead.hEvent );
CloseHandle( overlappedCommEvent.hEvent );
end; {TReadThread.Execute}
function TReadThread.SetupReadEvent(lpOverlappedRead: POverlapped;
lpszInputBuffer: LPSTR; dwSizeofBuffer: DWORD;
var lpnNumberOfBytesRead: DWORD ): Boolean;
var
dwLastError: DWORD;
label
StartSetupReadEvent;
begin
StartSetupReadEvent:
Result := False;
if WaitForSingleObject(hCloseEvent,0)<>WAIT_TIMEOUT then//if WAIT_TIMEOUT <> WaitForSingleObject(hCloseEvent,0) then
Exit;
if ReadFile(hCommFile,lpszInputBuffer^,dwSizeofBuffer,
lpnNumberOfBytesRead,lpOverlappedRead) then
begin
if not HandleReadData(lpszInputBuffer,lpnNumberOfBytesRead) then
Exit;
goto StartSetupReadEvent;
end;
dwLastError := GetLastError;
if dwLastError = ERROR_IO_PENDING then
begin
Result := True;
Exit;
end;
if dwLastError = ERROR_INVALID_HANDLE then Exit;
ErrorsOccur(128);
end; {TReadThread.SetupReadEvent}
function TReadThread.HandleReadData(lpszInputBuffer: LPCSTR; dwSizeofBuffer: DWORD ): Boolean;
var
lpszPostedBytes: LPSTR;
tempstr: string;
begin
Result := False;
if dwSizeofBuffer <> 0 then
begin
tempstr := lpszInputBuffer;
lpszPostedBytes := PChar( LocalAlloc( LPTR, dwSizeofBuffer+1 ) );
if lpszPostedBytes = nil then
begin
GetLastError;
Exit;
end;
Move( lpszInputBuffer^, lpszPostedBytes^, dwSizeofBuffer );
lpszPostedBytes[dwSizeofBuffer] := #0;
Result := ReceiveData(lpszPostedBytes, dwSizeofBuffer);
end;
end; {TReadThread.HandleReadData}
function TReadThread.HandleReadEvent(lpOverlappedRead: POverlapped;
lpszInputBuffer: LPSTR; dwSizeofBuffer: DWORD;
var lpnNumberOfBytesRead: DWORD ): Boolean;
var
dwLastError: DWORD;
begin
Result := False;
if GetOverlappedResult( hCommFile,
lpOverlappedRead^, lpnNumberOfBytesRead, False ) then
begin
Result := HandleReadData(lpszInputBuffer, lpnNumberOfBytesRead );
Exit;
end;
dwLastError := GetLastError;
if dwLastError = ERROR_INVALID_HANDLE then Exit;
ErrorsOccur(128);
end; {TReadThread.HandleReadEvent}
function TReadThread.SetupCommEvent( lpOverlappedCommEvent: POverlapped;
var lpfdwEvtMask: DWORD ): Boolean;
var
dwLastError: DWORD;
label
StartSetupCommEvent;
begin
Result := False;
StartSetupCommEvent:
if WaitForSingleObject(hCloseEvent,0)<>WAIT_TIMEOUT then Exit;//if WAIT_TIMEOUT <> WaitForSingleObject( hCloseEvent,0 ) then Exit;
if WaitCommEvent( hCommFile, lpfdwEvtMask, lpOverlappedCommEvent ) then
begin
if not HandleCommEvent( nil, lpfdwEvtMask, False ) then Exit;
goto StartSetupCommEvent;
end;
dwLastError := GetLastError;
if dwLastError = ERROR_IO_PENDING then
begin
Result := True;
Exit
end;
if dwLastError = ERROR_INVALID_HANDLE then Exit;
end; {TReadThread.SetupCommEvent}
function TReadThread.HandleCommEvent(lpOverlappedCommEvent: POverlapped;
var lpfdwEvtMask: DWORD; fRetrieveEvent: Boolean): Boolean;
var
dwDummy
WORD;
szError:byte;
szEvent:byte;
dwErrors,dwLastError
WORD;
begin
Result := False;
if fRetrieveEvent then
if not GetOverlappedResult( hCommFile,lpOverlappedCommEvent^, dwDummy, False ) then
{
GetOverlappedResult ·&micro;&raquo;&Oslash;&para;&Euml;&iquest;&Uacute;&micro;&Auml; overlapped &sup2;&Ugrave;×÷&frac12;á&sup1;&ucirc;.
BOOL GetOverlappedResult(
HANDLE hFile, // handle of file, pipe, or communications device
LPOVERLAPPED lpOverlapped, // address of overlapped structure
LPDWORD lpNumberOfBytesTransferred, // address of actual bytes count
this is the number of bytes of
output data returned by the device driver
BOOL bWait // wait flag
&Ouml;&cedil;&para;¨&Ecirc;&Ccedil;·&ntilde;&micro;&Egrave;&acute;&yacute;&Iacute;ê&sup3;&Eacute;&Icirc;&acute;&frac12;á&Ecirc;&oslash;&micro;&Auml;overlapped&sup2;&Ugrave;×÷
TRUE&pound;&ordm;&micro;&Egrave;&acute;&yacute;&micro;&frac12;&sup2;&Ugrave;×÷&Iacute;ê&sup3;&Eacute;&sup2;&Aring;·&micro;&raquo;&Oslash;
FALSE&pound;&ordm;&Egrave;&ccedil;&sup1;&ucirc;&sup2;&Ugrave;×÷&Icirc;&acute;&Iacute;ê&sup3;&Eacute;&ordm;&macr;&Ecirc;&yacute;·&micro;&raquo;&Oslash;FALSE&sup2;&cent;&Ccedil;&Ograve;GetLastError ·&micro;&raquo;&Oslash; ERROR_IO_INCOMPLETE.
);
}
begin
dwLastError := GetLastError;
if dwLastError = ERROR_INVALID_HANDLE then Exit;
Exit;
end;
if (lpfdwEvtMask and EV_ERR) <> 0 then
begin
if not ClearCommError(hCommFile, dwErrors, nil ) then
begin
dwLastError := GetLastError;
if dwLastError = ERROR_INVALID_HANDLE then Exit;
Exit;
end;
szError := 0;
if dwErrors = 0 then szError:=0;
if (dwErrors and CE_FRAME) <> 0 then SzError:=SzError + 1;
if (dwErrors and CE_OVERRUN) <> 0 then SzError:= SzError + 2;
if (dwErrors and CE_RXPARITY) <> 0 then SzError:= SzError + 4;
if (dwErrors and not (CE_FRAME + CE_OVERRUN + CE_RXPARITY)) <> 0
then SzError:= SzError+8;
if not ErrorsOccur(SzError) then exit;
Result := True;
Exit
end;
szEvent := 0;
if (lpfdwEvtMask and EV_BREAK) <> 0 then
begin
szEvent := szEvent + 1; //if not EventOccur(1) then exit;
end;
if (lpfdwEvtMask and EV_CTS) <> 0 then
begin
szEvent := szEvent + 2;//if not EventOccur(2) then exit;
end;
if (lpfdwEvtMask and EV_DSR) <> 0 then
begin
szEvent := szEvent + 4;//if not EventOccur(3) then exit;
end;
if (lpfdwEvtMask and EV_RING) <> 0 then
begin
szEvent := szEvent + 8;//if not EventOccur(4) then exit;
end;
if (lpfdwEvtMask and EV_RLSD) <> 0 then
begin
szEvent := szEvent + 16;//if not EventOccur(5) then exit;
end;
if (lpfdwEvtMask and EV_RXCHAR) <> 0 then
begin
szEvent := szEvent + 32;//if not EventOccur(6) then exit;
end;
if (lpfdwEvtMask and EV_RXFLAG) <> 0 then begin
szEvent := szEvent + 64;//if not EventOccur(7) then exit;
end;
if (lpfdwEvtMask and EV_TXEMPTY) <> 0 then
begin
szEvent := szEvent + 128;//if not EventOccur(8) then exit;
end;
EventOccur(szEvent);
Result:=true;
end; {TReadThread.HandleCommEvent}
function TReadThread.ReceiveData( lpNewString: LPSTR; dwSizeofNewString: DWORD ): BOOL;
begin
Result := PostMessage(hCommWindow, PWM_GOTCOMMDATA,
WPARAM(dwSizeofNewString), LPARAM(lpNewString));
end;
function TReadThread.EventOccur(EvtType:byte):BOOL;
begin
Result := PostMessage(hCommWindow, PWM_COMMEVENT, WPARAM(EvtType),0);
end;
function TReadThread.ErrorsOccur(ErrType:byte):BOOL;
begin
Result := PostMessage(hCommWindow, PWM_ERROCCUR,WPARAM(ErrType),0);
end;
(******************************************************************************)
// WRITE THREAD
(******************************************************************************)
procedure TWriteThread.Execute;
var
msg: TMsg;
dwHandleSignaled: DWORD;
overlappedWrite: TOverLapped;
label
EndWriteThread;
begin
FillChar( overlappedWrite, SizeOf(overlappedWrite), 0 );
overlappedWrite.hEvent := CreateEvent( nil, True, True, nil );
if overlappedWrite.hEvent = 0 then
begin
GetLastError;
ErrorsOccur(128);
goto EndWriteThread;
end;
while True do
begin
if not PeekMessage( msg, 0, 0, 0, PM_REMOVE ) then
begin
dwHandleSignaled := MsgWaitForMultipleObjects(1, hCloseEvent, False,INFINITE, QS_ALLINPUT);
case dwHandleSignaled of
WAIT_OBJECT_0:goto EndWriteThread;
WAIT_OBJECT_0 + 1: continue;// New message was received.
WAIT_FAILED: // Wait failed. Shouldn't happen.
begin
GetLastError;
ErrorsOccur(128);
goto EndWriteThread;
end;
else // This case should never occur.
begin
ErrorsOccur(128);
goto EndWriteThread;
end;
end;{case}
end; {if}
if WaitForSingleObject(hCloseEvent,0)<>WAIT_TIMEOUT then//if WAIT_TIMEOUT <> WaitForSingleObject(hCloseEvent,0) then
goto EndWriteThread;
if msg.hwnd <> 0 then
begin
TranslateMessage(msg);
DispatchMessage(msg);
Continue;
end;
case msg.message of
PWM_COMMWRITE: // New string to write to Comm port.
begin
if not HandleWriteData( @overlappedWrite,
PChar(msg.lParam), DWORD(msg.wParam) ) then
begin
LocalFree( HLOCAL(msg.lParam) );
goto EndWriteThread;
end;
LocalFree( HLOCAL(msg.lParam) );
end;
end; {case}
end; {main loop}
EndWriteThread:
PurgeComm(hCommFile, PURGE_TXABORT + PURGE_TXCLEAR);
CloseHandle(overlappedWrite.hEvent);
end; {TWriteThread.Execute}
function TWriteThread.HandleWriteData( lpOverlappedWrite: POverlapped;
pDataToWrite: PChar; dwNumberOfBytesToWrite: DWORD): Boolean;
var
dwLastError,
dwNumberOfBytesWritten,
dwWhereToStartWriting,
dwHandleSignaled: DWORD;
HandlesToWaitFor: array[0..1] of THandle;
begin
dwNumberOfBytesWritten := 0;
dwWhereToStartWriting := 0; // Start at the beginning.
HandlesToWaitFor[0] := hCloseEvent;
HandlesToWaitFor[1] := lpOverlappedWrite^.hEvent;
repeat
if not WriteFile(hCommFile,pDataToWrite[dwWhereToStartWriting],dwNumberOfBytesToWrite, dwNumberOfBytesWritten,lpOverlappedWrite) then
begin
dwLastError := GetLastError;
if (dwLastError = ERROR_INVALID_HANDLE) then
begin
Result := False;
Exit;
end;
if dwLastError <> ERROR_IO_PENDING then
begin
ErrorsOccur(128);
Result := False;
Exit;
end;
dwHandleSignaled := WaitForMultipleObjects(2, @HandlesToWaitFor,False, INFINITE);
case dwHandleSignaled of
WAIT_OBJECT_0: // CloseEvent signaled!
begin
Result := False;
Exit;
end;
WAIT_OBJECT_0 + 1: // Wait finished.
begin
// Time to get the results of the WriteFile
end;
WAIT_FAILED: // Wait failed. Shouldn't happen.
begin
GetLastError;
ErrorsOccur(128);
Result := False;
Exit
end;
else // This case should never occur.
begin
ErrorsOccur(128);
Result := False;
Exit
end;
end; {case}
if not GetOverlappedResult(hCommFile,lpOverlappedWrite^,dwNumberOfBytesWritten, TRUE) then
begin
dwLastError := GetLastError;
if dwLastError = ERROR_INVALID_HANDLE then
begin
Result := False;
Exit;
end;
ErrorsOccur(128);
Result := False;
Exit;
end;
end; {WriteFile failure}
Dec( dwNumberOfBytesToWrite, dwNumberOfBytesWritten );
Inc( dwWhereToStartWriting, dwNumberOfBytesWritten );
until (dwNumberOfBytesToWrite <= 0);
Result := True;
end; {TWriteThread.HandleWriteData}
function TWriteThread.WriteComm( pDataToWrite: LPCSTR; dwSizeofDataToWrite: DWORD ): Boolean;
begin
Result := PostThreadMessage( ThreadID, PWM_COMMWRITE,
WParam(dwSizeofDataToWrite), LParam(pDataToWrite) );
end;
function TWriteThread.ErrorsOccur(ErrType:byte):BOOL;
begin
Result := PostMessage(hCommWindow, PWM_ERROCCUR,WPARAM(ErrType),0);
end;
procedure Register;
begin
RegisterComponents('DCM', [TCOMMPORT]);
end;
end.