📄 unicommx.pas
字号:
unit UniCommX;
{----------------------------------------------
UniCommX
Version 1.05
Copyright 1999-2001 AT Corp.Ltd
-----------------------------------------------}
interface
//{$DEFINE DEBUG_FILE}
//{$DEFINE DEBUG_MSG}
{
DEFINE DEBUG_FILE 会生成调试文件
DEFINE DEBUG_MSG 会生成调试信息,可通过 GetAndClearDebugMsg 函数得到
在软件正式发行时,要屏蔽掉调试信息
}
uses
SysUtils, Classes, Messages, Windows, Forms, Syncobjs, ActiveX;
const
cnNullID = 0; // 通信设备类型-未用
cnDownLoaderID = 1; // 通信设备类型-通信座
cnCuteHouseID = 3; // 通信设备类型-智能机房
cnTimePosID = 2; // 通信设备类型-考勤机
cnDataTransferID = 255; // 通信设备类型-数据传输
csInit = 1; // 通信状态 - 要求初始化
csWaitForInit = 2; // 通信状态 - 等待初始化完成
csWaitForConnect = 3; // 通信状态 - 等待连接信息
csPreHandShake = 4; // 通信状态 - 进行软件握手之前的预处理
csHandShake = 5; // 通信状态 - 进行软件握手
csResponseCommand = 6; // 通信状态 - 需要回应命令
csNotifyHangup = 7; // 通信状态 - 需要挂机
csHalt = 8; // 通信状态 - 挂机
csUser = 9; // 通信状态 - 自定义
srACK = 1; // 发送命令回应-确认
srNAK = 2; // 发送命令回应-否定
srGetData = 3; // 发送命令回应-收到数据
srNullCommand = 4; // 发送命令回应-要发送的命令为空
srOffLine = 5; // 发送命令回应-连接已经断开
srTerminate = 6; // 发送命令回应-发送被中止
WMT_InitCompleted = WM_USER + 1; // 事件-初始化完成
WMT_ConnectState = WM_USER + 2; // 事件-连接状态改变
WMT_Progress = WM_USER + 3; // 事件-通信进度改变
WMT_CommCompleted = WM_USER + 4; // 事件-通信完成
WMT_DealData = WM_USER + 6; // 事件-接收到数据需要处理
csHandShakeCommand = ' SWAT '; // 握手命令
COMMAND_HEAD = #$FF#$FF; // 为防止干扰,所有命令前添加此命令头
csEngineVersion = '3.1.2'; // 通信引擎版本
type
// 设备状态:空闲、正在初始化、等待连接、连接成功
TUniDeviceState = (dsIdle, dsInitDevice, dsWaitForConnect, dsConnected);
// 设备类型:未知、串口、直接Modem驱动、TAPI、WinSocket。其中WinSocket未实现
TUniDeviceType = (dtUnknown, dtComPort, dtDirectModem, dtTAPI, dtWinSocket);
// 通信速率:自定义、110、300......256000波特
TUniBaudRate = (brCustom, br110, br300, br600, br1200, br2400, br4800, br9600,
br14400, br19200, br38400, br56000, br57600, br115200, br128000, br256000);
// ProtocolExecutor的通信模式:Commander(命令发送者)、Responder(命令响应者)
TUniTransferMode = (tmCommander, tmResponder);
// 通信优化模式:性能优先、低CPU占用率优先
FOptimizeMode = (omMaxPerformance, omMinCPUUtilize);
// UnicomPort Event
// 事件:初始化完成。InitResult表示初始化成功与否。如果初始化不成功,则此设备不可用
TInitCompletedEvent = procedure(Sender: TObject; InitResult: Boolean) of object;
// 事件:连接状态改变。Connected表示当前是否连接成功;IsInitiative表示是否主动连接
TConnectStateEvent = procedure(Sender: TObject; Connected: Boolean; IsInitiative: Boolean) of object;
// 事件:通信进度改变。Percent从0到100表示当前进度
TProgressEvent = procedure(Sender: TObject; Percent: Integer) of object;
// 事件:通信完成。CommSuccess表示通信成功与否;IsInitiative表示是否主动连接
TCommCompletedEvent = procedure(Sender: TObject; CommSuccess: Boolean; isInitiative: Boolean) of object;
// 事件:接收到数据。Buffer中为数据
TDataArriveEvent = procedure(Sender: TObject; const Buffer: string) of object;
// 事件:数据处理。 DisableOutBuffer: 是否将OutDataBuffer置为无效。当数据传送完毕后,如果对方还要求这些数据,则根据OutDataBuffer值决定传送与否
TDealDataEvent = procedure(Sender: TObject; inBuf: Pointer; InBufSize: Integer; var DisableOutBuffer: Boolean) of object;
// 记录:命令回应格式
TCommandEchos = record
Echo_Head: string; //期望的回应数据头
Echo_Size: Integer; //期望的数据包大小
Echo_HaveCRC: Boolean; //回应是否带有CRC校验
end;
// 记录:主机命令
THostCommand = record
Comment: string; //命令注释
Command: string; //待发的命令
Send_Interval: Integer; //重发间隔,即每次重发超时时间间隔(毫秒)
No_Response_Interval: Integer; //无回应重发间隔,即收不到任何数据时最大时间间隔(毫秒)
Max_Send_Times: Integer; //最大重发次数
Echos: array of TCommandEchos; //期望的回应(如果不希望有回应,则此Array成员个数为0)
curACK: string; //ACK(如返回结果可能有ACK)
curNAK: string; //NAK(如返回结果可能有NAK)
end;
// 记录:当Responder收到数据判断是否为Commander命令时,使用此记录中的数据判断
TCommandTag = record
CommandHead: string; // Commander命令头
Comment: string; // 注释
CommandLength: Integer; //Commander命令长度
CommandCode: Integer; //Commander命令编码
HaveCRC: Boolean; //Commander命令是否带有CRC校验
end;
TCustomDeviceClass = class of TCustomCommDevice;
// TCustomCommDevice 实现了通用的通信设备所共有的特性与功能。抽象类。
TCustomCommDevice = class
protected
FDeviceName: string; // 设备名称,如串口的'COM1'等
FDeviceType: TUniDeviceType; // 设备类型,如串口、TAPI等
FBaudRate: TUniBaudRate; // 设备的速率。一般为57600波特
FActived: Boolean; // 是否已经激活。只有激活时才能接收发送数据
FDeviceState: TUniDeviceState; // 当前的设备状态。如空闲、正在初始化、等待连接、连接成功
FDataArriveEvent: TDataArriveEvent; // 接收到数据时会调用此事件
FInitCompletedEvent: TInitCompletedEvent; // 初始化完成时会调用此事件
FConnectedEvent: TConnectStateEvent; // 连接状态改变时会调用本事件
FIsInitiative: Boolean; // 如果连接成功,本标志表明是否主动连接
InitiativelyConnecting: Boolean; // 当前是否正在进行主动连接
FLastInitiativeTime: DWord; // 最后一次主动连接的Tick
FInitiativeTimeOut: DWord; // 主动连接超时
FEvent_DataArrive: THandle; // 接收到数据时此事件为有信号态
FEvent_InitState: THandle; // 初始化完成时此事件为有信号态
FEvent_ConnectState: THandle; // 连接状态改变时此事件为有信号态
FInitSuccess: Boolean; // 是否初始化成功
FConnected: Boolean; // 是否连接成功
FDeviceValid: Boolean; // 设备是否可用(初始化成功时可用)
FDatas: string; // 接收数据缓冲区
procedure NotifyConnection(ConnectResult: Boolean); virtual; // 通知连接状态改变
procedure NotifyInitCompleted(InitResult: Boolean); virtual; // 通知初始化完成
procedure NotifyDataArrive(Data: string); virtual; // 通知接收到数据
procedure SetActived(value: Boolean); virtual; abstract; // 设定激活标志
procedure SetBaudRate(value: TUniBaudRate); virtual; abstract; // 设定通信速率
procedure SetDeviceName(value: string); virtual; abstract; // 设定设备名称
procedure OpenDevice; virtual; abstract; // 打开设备
procedure CloseDevice; virtual; // 关闭设备
function GetBusy: Boolean; virtual; // 判断设备是否正在忙
public
constructor Create; dynamic; // 建构式
destructor Destroy; override; // 析构式
class procedure EnumDevice(Device: TStrings); virtual; abstract; // 列举所有可用设备
class function TypeImplemented(value: TUniDeviceType): Boolean; virtual; abstract; // 判断是否实现了某种设备类型
function InitiativelyConnect(Params: string): Boolean; virtual; // 主动连接
procedure SendData(Data: string); virtual; abstract; // 发送数据
function GetDataAndClearBuf: string; virtual; abstract; // 接收数据,并清楚接收缓冲区
procedure CloseConnection; virtual; abstract; // 关闭连接
property Actived: Boolean read FActived write SetActived; // 激活标志。激活时才能接收发送数据
property BaudRate: TUniBaudRate read FBaudRate write SetBaudRate; //设备通信的速率。一般为57600波特
property DeviceName: string read FDeviceName write SetDeviceName; // 设备名称,如串口的'COM1'等
property DeviceType: TUniDeviceType read FDeviceType; // 设备类型,如串口、TAPI等
property Busy: Boolean read GetBusy; // 设备是否正在忙
property IsInitiative: Boolean read FIsInitiative; // 如果连接成功,本标志表明是否主动连接
property Event_DataArrive: THandle read FEvent_DataArrive; // 接收到数据时此事件为有信号态
property Event_InitState: THandle read FEvent_InitState; // 初始化完成时此事件为有信号态
property Event_ConnectState: THandle read FEvent_ConnectState; // 连接状态改变时此事件为有信号态
property InitSuccess: Boolean read FInitSuccess; // 是否初始化成功
property Connected: Boolean read FConnected; // 是否连接成功
property DeviceValid: Boolean read FDeviceValid; // 设备是否可用(初始化成功时可用)
property OnInitState: TInitCompletedEvent read FInitCompletedEvent write FInitCompletedEvent; // 初始化完成时会调用此事件
property OnConnectState: TConnectStateEvent read FConnectedEvent write FConnectedEvent; // 连接状态改变时会调用本事件
property OnDataArrive: TDataArriveEvent read FDataArriveEvent write FDataArriveEvent; // 接收到数据时会调用此事件
end;
TCustomProtocolExecutorClass = class of TCustomProtocolExecutor;
// TCustomProtocolExecutor 实现了协议处理类所共有的特性与功能。抽象类。
TCustomProtocolExecutor = class
protected
OwnerHwnd: THandle; // 上级的句柄,用来发送通知消息
FCommSuccess: Boolean; // 本次通信是否成功
FSenderID: Integer; // 发送者要求的协议类型
FProtocolVersion: Integer; // 发送者要求的协议版本
FDatas: TStrings; // 接收数据缓冲区
FProcessRatio: Integer; // 通信进度
FDataBuff: string; // 接收中转数据缓冲区
FInBuff: Pointer; // 接收数据缓冲区
FInBuffSize: Cardinal; // 接收数据缓冲区大小
FOutBuff: Pointer; // 发送数据缓冲区
FOutBuffSize: Cardinal; // 发送数据缓冲区大小
FOutBuffEnabled: Boolean; // 发送缓冲区是否有效
FWaiting: Boolean; // 是否正在等待数据处理
public
isInitiative: Boolean; // 当前正在处理的连接是否是主动连接
DataTag: string; // 当前的数据标志,当OutBuff改变后会自动生成新的标志,用于断点续传
constructor Create(SenderID, ProtocolVersion: Integer; Hwnd: THandle); dynamic; // 建构式,根据给定的协议类型以及版本创建响应的协议处理类实例
destructor Destroy; override; // 析构式
class function ProtocolImplemented(ProtocolType: Integer; ProtocolVersion: Integer; isCommander: Boolean): Boolean; virtual; abstract; // 判断是否实现了给定的协议类型以及版本的处理
class function SaveUncompletedData: Boolean; virtual; abstract; // 本协议是否需要保存未完成的通信的数据
function ProcessProtocol(var FCommState: Integer; SendResult: Integer; Packet: string; Parameters: TStrings): THostCommand; virtual; abstract; // 服务器模式下的通信处理
function RespondCommand(var FCommState: Integer; Data: string; Parameters: TStrings; var lastCmdComment: string; var dwSleep: Cardinal): string; virtual; // 客户模式下的通信处理
property CommSuccess: Boolean read FCommSuccess; // 本次通信是否成功
property Datas: TStrings read FDatas; // 本次通信的接收到的数据缓冲区
property ProcessRatio: Integer read FProcessRatio; // 协议处理的进度。0..100
property InBuffSize: Cardinal read FInBuffSize write FInBuffSize; // 接收到的数据缓冲区大小,只用于数据上下传
property InBuff: Pointer read FInBuff write FInBuff; // 接收到的数据缓冲区,只用于数据上下传
property OutBuffSize: Cardinal read FOutBuffSize write FOutBuffSize; // 待发送的数据缓冲区大小,只用于数据上下传
property OutBuff: Pointer read FOutBuff write FOutBuff; // 待发送的数据缓冲区,只用于数据上下传
property OutBuffEnabled: Boolean read FOutBuffEnabled write FOutBuffEnabled; // 待发缓冲区是否可用。如果不可用则待发缓冲区的数据不会被发送
property Waiting: Boolean read FWaiting write FWaiting; // 是否正在等待DealData
end;
// TCommThread 实现了对CommDevice以及ProtocolExecutor的协调处理,使其完成通信进程
TCommThread = class(TThread)
private
FActived: Boolean; // 是否激活
FCommState: Integer; // 当前的通信状态
Event_Terminate: THandle; // 事件:需要退出通信
OwnerHwnd: THandle; // 上级的句柄,用来发送通知消息
FParameters: TStrings; // 通信参数
FCommDevice: TCustomCommDevice; // 当前所用的通信设备
FProtocolExecutorList: TList; // 协议处理缓冲区。每次通信完成后,当前的协议处理者会加入到此缓冲区
FCurrentProtocolExecutor: TCustomProtocolExecutor; // 当前的协议处理者。每次通信都会重新生成
FHostCMD: THostCommand; // 保存待发命令
FSenderID: Longint; // 发送者要求的协议类型
FProtocolVersion: LongWord; // 协议版本
FPacket: string; // 接收到的数据包
FLastSendResult: Integer; // 上一次发送命令的结果
FDefaultProtocolType: Integer; // 默认协议类型
FDefaultProtocolVersion: Integer; // 默认协议版本
FDefaultTransferMode: TUniTransferMode; //默认传输模式:客户/服务器
FCurrentTransferMode: TUniTransferMode; //当前的传输模式
FOutBuff: Pointer; // 发送数据缓冲区
FOutBuffSize: Cardinal; // 发送数据缓冲区大小
DataTag: string; // 数据标志,用于续传
FOptimize: FOptimizeMode; // 优化方式
function SendCmd: Integer; // 发送命令,并取得回应
procedure SetActived(value: boolean); // 设定是否激活
procedure SetParameters(value: TStrings); // 设定通信参数
function GetDataCount: Integer; // 取得数据总量
function GetData(Index: Integer): string; // 取得数据
procedure DiscardData(Index: Integer); // 删除数据
function GetProcessRatio: Integer; // 取得通信进度
procedure SafeTerminate; // 安全终止线程
procedure SetTransferMode(value: TUniTransferMode); // 设定传输模式:Commander或者Responder
procedure CreateProtocolExecutor; // 根据传输模式以及协议类型创建相应的协议处理者
procedure SetOutBuff(value: Pointer); // 设定待发数据缓冲区
procedure SetOutBuffSize(value: Cardinal); //设定待发数据缓冲区大小
protected
procedure Execute; override; // 线程执行函数
procedure Process_Communication_Event; // 处理通信中的事件
function HandShakeCommand: THostCommand; // 生成握手命令
function GetBusy: Boolean; // 判断通信是否正忙
function GetCurrentData: string; // 取得当前的数据,即使通信没有完成
public
constructor Create(OwnerHandle: THandle; CommDevice: TCustomCommDevice); // 建构式
destructor Destroy; override; // 析构式
property DataCount: Integer read GetDataCount; // 数据总量
property Data[Index: Integer]: string read GetData; // 取得数据
property OutBuffSize: Cardinal read FOutBuffSize write SetOutBuffSize; // 待发缓冲区大小
property OutBuff: Pointer read FOutBuff write SetOutBuff; // 待发缓冲区
published
property Actived: Boolean read FActived write SetActived; // 是否激活
property Parameters: TStrings read FParameters write SetParameters; // 通信参数
property CurrentData: string read GetCurrentData; // 取得当前数据
property ProcessRatio: Integer read GetProcessRatio; // 取得当前通信进度
property CurrentProtocolExecutor: TCustomProtocolExecutor read FCurrentProtocolExecutor; // 当前的协议处理者
property Busy: Boolean read GetBusy; //是否通信正忙
property DefaultProtocolType: Integer read FDefaultProtocolType write FDefaultProtocolType; // 设定默认的协议类型
property DefaultProtocolVersion: Integer read FDefaultProtocolVersion write FDefaultProtocolVersion; // 默认的协议版本
property DefaultTransferMode: TUniTransferMode read FDefaultTransferMode write SetTransferMode; // 默认的传输类型
property OptimizeMode: FOptimizeMode read FOptimize write FOptimize; // 默认的优化方式,可以在通信中动态设置
end;
// TUniComm 实现对 TCommThread 的封装,最终用户接口
TUniComm = class(TComponent)
private
FHWnd: THandle; // 自己的消息句柄
FParameters: TStringList; // 通信参数
FCommThread: TCommThread; // 通信线程
FCommDevice: TCustomCommDevice; // 通信设备
FActived: Boolean; // 是否激活
FDatas: TList; // 接收到的数据
FBaudRate: TUniBaudRate; // 通信速率
FDeviceName: string; // 通信设备名称
FInitCompletedEvent: TInitCompletedEvent; // 事件,初始化成功后触发
FConnectStateEvent: TConnectStateEvent; // 事件,连接状态改变后触发
FProgressEvent: TProgressEvent; // 事件,通信进度改变后触发
FCommCompletedEvent: TCommCompletedEvent; // 事件,通信完成后触发
FDealDataEvent: TDealDataEvent; // 事件,表明接收到数据需要处理
// 当前传输模式。当传输模式为主动时,握手时按照默认协议类型以及默认协议版本创建相应的主动协议处理插件
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -