VBX registration is non-functional in VB4 16-bit (VBRegisterModel is a no-op, VBGetModelInfo never called). Native Delphi component avoids all DLL/export/registration issues — compiles directly into the IDE. TKPComm is a TComponent descendant calling the Windows 3.1 comm API directly. Uses RegisterClass/CreateWindow for WM_COMMNOTIFY dispatch with the component instance pointer stored in cbWndExtra. Includes a test application (KPTEST) with send/receive UI built entirely in code. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
267 lines
6.4 KiB
ObjectPascal
267 lines
6.4 KiB
ObjectPascal
unit TestMain;
|
|
|
|
{ Test application for the TKPComm serial communications component. }
|
|
{ Form and all controls are created in code (no DFM required). }
|
|
|
|
interface
|
|
|
|
uses
|
|
SysUtils, Classes, WinTypes, WinProcs, Messages,
|
|
Forms, Controls, StdCtrls, KPComm;
|
|
|
|
type
|
|
TMainForm = class(TForm)
|
|
private
|
|
FComm: TKPComm;
|
|
FLabelPort: TLabel;
|
|
FEditPort: TEdit;
|
|
FLabelSettings: TLabel;
|
|
FEditSettings: TEdit;
|
|
FBtnOpen: TButton;
|
|
FBtnClose: TButton;
|
|
FLabelStatus: TLabel;
|
|
FLabelRecv: TLabel;
|
|
FMemoRecv: TMemo;
|
|
FEditSend: TEdit;
|
|
FBtnSend: TButton;
|
|
FLabelInfo: TLabel;
|
|
procedure BtnCloseClick(Sender: TObject);
|
|
procedure BtnOpenClick(Sender: TObject);
|
|
procedure BtnSendClick(Sender: TObject);
|
|
procedure CommEvent(Sender: TObject);
|
|
procedure UpdateStatus;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
end;
|
|
|
|
var
|
|
MainForm: TMainForm;
|
|
|
|
implementation
|
|
|
|
|
|
procedure TMainForm.BtnCloseClick(Sender: TObject);
|
|
begin
|
|
FComm.PortOpen := False;
|
|
FMemoRecv.Lines.Add('--- Port closed ---');
|
|
UpdateStatus;
|
|
end;
|
|
|
|
|
|
procedure TMainForm.BtnOpenClick(Sender: TObject);
|
|
begin
|
|
try
|
|
FComm.CommPort := StrToInt(FEditPort.Text);
|
|
FComm.Settings := FEditSettings.Text;
|
|
FComm.RThreshold := 1;
|
|
FComm.PortOpen := True;
|
|
FMemoRecv.Lines.Add('--- Port opened on COM' +
|
|
FEditPort.Text + ' at ' + FEditSettings.Text + ' ---');
|
|
except
|
|
on E: Exception do
|
|
FMemoRecv.Lines.Add('Open failed: ' + E.Message);
|
|
end;
|
|
UpdateStatus;
|
|
end;
|
|
|
|
|
|
procedure TMainForm.BtnSendClick(Sender: TObject);
|
|
begin
|
|
if Length(FEditSend.Text) = 0 then
|
|
Exit;
|
|
try
|
|
FComm.Output := FEditSend.Text + #13;
|
|
FMemoRecv.Lines.Add('TX: ' + FEditSend.Text);
|
|
FEditSend.Text := '';
|
|
except
|
|
on E: Exception do
|
|
FMemoRecv.Lines.Add('Send failed: ' + E.Message);
|
|
end;
|
|
UpdateStatus;
|
|
end;
|
|
|
|
|
|
procedure TMainForm.CommEvent(Sender: TObject);
|
|
var
|
|
S: string;
|
|
begin
|
|
case FComm.CommEvent of
|
|
comEvReceive:
|
|
begin
|
|
S := FComm.Input;
|
|
if Length(S) > 0 then
|
|
FMemoRecv.Lines.Add('RX: ' + S);
|
|
end;
|
|
comEvCTS:
|
|
FMemoRecv.Lines.Add('CTS changed');
|
|
comEvDSR:
|
|
FMemoRecv.Lines.Add('DSR changed');
|
|
comEvCD:
|
|
FMemoRecv.Lines.Add('CD changed');
|
|
comEvRing:
|
|
FMemoRecv.Lines.Add('Ring');
|
|
comEvEOF:
|
|
FMemoRecv.Lines.Add('EOF received');
|
|
comEvtBreak:
|
|
FMemoRecv.Lines.Add('Break received');
|
|
comEvtFrame:
|
|
FMemoRecv.Lines.Add('Framing error');
|
|
comEvtOverrun:
|
|
FMemoRecv.Lines.Add('Overrun error');
|
|
comEvtRxOver:
|
|
FMemoRecv.Lines.Add('RX buffer overflow');
|
|
comEvtParity:
|
|
FMemoRecv.Lines.Add('Parity error');
|
|
comEvtTxFull:
|
|
FMemoRecv.Lines.Add('TX buffer full');
|
|
end;
|
|
UpdateStatus;
|
|
end;
|
|
|
|
|
|
constructor TMainForm.Create(AOwner: TComponent);
|
|
begin
|
|
inherited CreateNew(AOwner);
|
|
|
|
Caption := 'KPComm Test';
|
|
Width := 500;
|
|
Height := 380;
|
|
BorderStyle := bsSingle;
|
|
|
|
{ Serial component }
|
|
FComm := TKPComm.Create(Self);
|
|
FComm.OnComm := CommEvent;
|
|
|
|
{ Row 1: Port and Settings }
|
|
FLabelPort := TLabel.Create(Self);
|
|
FLabelPort.Parent := Self;
|
|
FLabelPort.Left := 8;
|
|
FLabelPort.Top := 12;
|
|
FLabelPort.Caption := 'Port:';
|
|
|
|
FEditPort := TEdit.Create(Self);
|
|
FEditPort.Parent := Self;
|
|
FEditPort.Left := 44;
|
|
FEditPort.Top := 8;
|
|
FEditPort.Width := 32;
|
|
FEditPort.Text := '1';
|
|
|
|
FLabelSettings := TLabel.Create(Self);
|
|
FLabelSettings.Parent := Self;
|
|
FLabelSettings.Left := 88;
|
|
FLabelSettings.Top := 12;
|
|
FLabelSettings.Caption := 'Settings:';
|
|
|
|
FEditSettings := TEdit.Create(Self);
|
|
FEditSettings.Parent := Self;
|
|
FEditSettings.Left := 148;
|
|
FEditSettings.Top := 8;
|
|
FEditSettings.Width := 140;
|
|
FEditSettings.Text := '9600,N,8,1';
|
|
|
|
{ Row 2: Open/Close buttons and status }
|
|
FBtnOpen := TButton.Create(Self);
|
|
FBtnOpen.Parent := Self;
|
|
FBtnOpen.Left := 8;
|
|
FBtnOpen.Top := 38;
|
|
FBtnOpen.Width := 65;
|
|
FBtnOpen.Height := 25;
|
|
FBtnOpen.Caption := 'Open';
|
|
FBtnOpen.OnClick := BtnOpenClick;
|
|
|
|
FBtnClose := TButton.Create(Self);
|
|
FBtnClose.Parent := Self;
|
|
FBtnClose.Left := 80;
|
|
FBtnClose.Top := 38;
|
|
FBtnClose.Width := 65;
|
|
FBtnClose.Height := 25;
|
|
FBtnClose.Caption := 'Close';
|
|
FBtnClose.Enabled := False;
|
|
FBtnClose.OnClick := BtnCloseClick;
|
|
|
|
FLabelStatus := TLabel.Create(Self);
|
|
FLabelStatus.Parent := Self;
|
|
FLabelStatus.Left := 160;
|
|
FLabelStatus.Top := 44;
|
|
FLabelStatus.Caption := 'Closed';
|
|
|
|
{ Receive area }
|
|
FLabelRecv := TLabel.Create(Self);
|
|
FLabelRecv.Parent := Self;
|
|
FLabelRecv.Left := 8;
|
|
FLabelRecv.Top := 70;
|
|
FLabelRecv.Caption := 'Received:';
|
|
|
|
FMemoRecv := TMemo.Create(Self);
|
|
FMemoRecv.Parent := Self;
|
|
FMemoRecv.Left := 8;
|
|
FMemoRecv.Top := 86;
|
|
FMemoRecv.Width := 476;
|
|
FMemoRecv.Height := 186;
|
|
FMemoRecv.ScrollBars := ssVertical;
|
|
FMemoRecv.ReadOnly := True;
|
|
|
|
{ Send row }
|
|
FEditSend := TEdit.Create(Self);
|
|
FEditSend.Parent := Self;
|
|
FEditSend.Left := 8;
|
|
FEditSend.Top := 280;
|
|
FEditSend.Width := 400;
|
|
|
|
FBtnSend := TButton.Create(Self);
|
|
FBtnSend.Parent := Self;
|
|
FBtnSend.Left := 416;
|
|
FBtnSend.Top := 280;
|
|
FBtnSend.Width := 65;
|
|
FBtnSend.Height := 25;
|
|
FBtnSend.Caption := 'Send';
|
|
FBtnSend.Enabled := False;
|
|
FBtnSend.OnClick := BtnSendClick;
|
|
|
|
{ Status info line }
|
|
FLabelInfo := TLabel.Create(Self);
|
|
FLabelInfo.Parent := Self;
|
|
FLabelInfo.Left := 8;
|
|
FLabelInfo.Top := 316;
|
|
FLabelInfo.Width := 476;
|
|
FLabelInfo.Caption := 'RX: 0 TX: 0 Event: 0';
|
|
end;
|
|
|
|
|
|
procedure TMainForm.UpdateStatus;
|
|
var
|
|
S: string;
|
|
begin
|
|
if FComm.PortOpen then
|
|
FLabelStatus.Caption := 'Open'
|
|
else
|
|
FLabelStatus.Caption := 'Closed';
|
|
|
|
FBtnOpen.Enabled := not FComm.PortOpen;
|
|
FBtnClose.Enabled := FComm.PortOpen;
|
|
FBtnSend.Enabled := FComm.PortOpen;
|
|
FEditSend.Enabled := FComm.PortOpen;
|
|
|
|
S := 'RX: ' + IntToStr(FComm.InBufferCount) +
|
|
' TX: ' + IntToStr(FComm.OutBufferCount);
|
|
if FComm.PortOpen then
|
|
begin
|
|
if FComm.CTSHolding then
|
|
S := S + ' CTS: On'
|
|
else
|
|
S := S + ' CTS: Off';
|
|
if FComm.DSRHolding then
|
|
S := S + ' DSR: On'
|
|
else
|
|
S := S + ' DSR: Off';
|
|
if FComm.CDHolding then
|
|
S := S + ' CD: On'
|
|
else
|
|
S := S + ' CD: Off';
|
|
end;
|
|
S := S + ' Event: ' + IntToStr(FComm.CommEvent);
|
|
FLabelInfo.Caption := S;
|
|
end;
|
|
|
|
|
|
end.
|