我的Serial.pas文件有问题,因为我正在尝试访问Com Ports,我遇到访问冲突,然后对于变量hCommPort,它说它的不可访问的值。在这篇文章的底部,最底部是我用来将我的com端口和波特率发送到Serial.pas的代码。
我已经到处寻找一个解决方案,但我似乎无法找到或者我只是不知道如何解决它而且我似乎不知道访问违规因为我有以前没有处理过。
非常感谢任何帮助
以下是Serial.pas
的完整代码unit Serial;
interface
uses
Windows, Messages, SysUtils, Classes,
Graphics, Controls, Forms, Dialogs;
// This is the Device Control Block record.
// It is the structure that contains the
// serial port setup parameters. This
// structure must be initialized before the
// serial port can be used. It is declared
// in the windows.pas unit and looks like this:
{type TDCB = record
DCBLength:DWord;
Baudrate:DWord;
Flags:LongInt;
wReserved:Word;
XONLim:Word;
XOFFLim:Word;
ByteSize:Byte;
Parity:Byte;
StopBits:Byte;
XONChar:Char;
XOFFChar:Char;
ErrorChar:Char;
EOFChar:Char;
EvtChar:Char;
wReserved1:Word;
end;}
type
// You can't do anything without a comm port.
TCommPort = (cpCOM1, cpCOM2, cpCOM3, cpCOM4,
cpCOM5, cpCOM6, cpCOM7, cpCOM8, cpCOM9);
// All of the baud rates that the DCB supports.
TBaudRate = (br110, br300, br600, br1200, br2400, br4800, br9600,
br14400, br19200, br38400, br56000, br115200, br128000, br256000, br009600);
// Parity types for parity error checking
TParityType = (pcNone, pcEven, pcOdd, pcMark, pcSpace);
TStopBits = (sbOne, sbOnePtFive, sbTwo);
TDataBits = (db4, db5, db6, db7, db8);
TFlowControl = (fcNone, fcXON_XOFF, fcRTS_CTS, fcDSR_DTR);
// Two new notify events.
TNotifyTXEvent = procedure(Sender : TObject; data : string) of object;
TNotifyRXEvent = procedure(Sender : TObject; data : string) of object;
// Set some constant defaults.
// These are the qquivalent of
// COM2:9600,N,8,1;
const
dflt_CommPort = cpCOM2;
dflt_BaudRate = br9600;
dflt_ParityType = pcNone;
dflt_ParityErrorChecking = False;
dflt_ParityErrorChar = 0;
dflt_ParityErrorReplacement = False;
dflt_StopBits = sbOne;
dflt_DataBits = db8;
dflt_XONChar = $11; {ASCII 11h}
dflt_XOFFChar = $13; {ASCII 13h}
dflt_XONLim = 1024;
dflt_XOFFLim = 2048;
dflt_ErrorChar = 0; // For parity checking.
dflt_FlowControl = fcNone;
dflt_StripNullChars = False;
dflt_EOFChar = 0;
type
TSerialPort = class(TComponent)
private
hCommPort : THandle; // Handle to the serial port.
fCommPort : TCommPort;
fBaudRate : TBaudRate;
fParityType : TParityType;
fParityErrorChecking : Boolean;
fParityErrorChar : Byte;
fParityErrorReplacement : Boolean;
fStopBits : TStopBits;
fDataBits : TDataBits;
fXONChar : byte; {0..255}
fXOFFChar : byte; {0..255}
fXONLim : word; {0..65535}
fXOFFLim : word; {0..65535}
fErrorChar : byte;
fFlowControl : TFlowControl;
fStripNullChars : Boolean; // Strip null chars?
fEOFChar : Byte;
fOnTransmit : TNotifyTXEvent;
fOnReceive : TNotifyRXEvent;
fAfterTransmit : TNotifyTXEvent;
fAfterReceive : TNotifyRXEvent;
ReadBuffer : String; // Where the results from the read goes.
procedure SetCommPort(CP : TCommPort);
procedure SetBaudRate(BR : TBaudRate);
procedure SetParityType(PT : TParityType);
procedure SetParityErrorChecking(SPEC : Boolean);
procedure SetParityErrorChar(PEC : Byte);
procedure SetParityErrorReplacement(PER : Boolean);
procedure SetStopBits(SSB: TStopBits);
procedure SetDataBits(SDB : TDataBits);
procedure SetXONChar(SXC : byte);
procedure SetXOFFChar(SXOC : byte);
procedure SetXONLim(SXOL : word);
procedure SetXOFFLim(SXFL : word);
procedure SetErrorChar(SEC : byte);
procedure SetFlowControl(SFC : TFlowControl);
procedure SetStripNullChars(SSNC : Boolean);
procedure SetEOFChar(SEOFC : Byte);
procedure Initialize_DCB;
protected
public
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
function OpenPort(MyCommPort : TCommPort) : Boolean;
function ClosePort : boolean;
procedure SendData(data : PChar; size : DWord);
function GetData : String;
function InputBufferCount: LongInt;
function PortIsOpen : boolean;
procedure FlushTX;
procedure FlushRX;
published
property CommPort : TCommport read fCommPort
write SetCommPort
default dflt_CommPort;
property BaudRate : TBaudRate read fBaudRate
write SetBaudRate
default dflt_BaudRate;
property ParityType : TParityType read fParityType
write SetParityType
default dflt_ParityType;
property ParityErrorChecking : Boolean read fParityErrorChecking
write SetParityErrorChecking
default dflt_ParityErrorChecking;
property ParityErrorChar : Byte read fParityErrorChar
write SetParityErrorChar
default dflt_ParityErrorChar;
property ParityErrorReplacement : Boolean read fParityErrorReplacement
write
SetParityErrorReplacement
default
dflt_ParityErrorReplacement;
property StopBits : TStopBits read fStopBits
write SetStopBits
default dflt_StopBits;
property DataBits : TDataBits read fDataBits
write SetDataBits
default dflt_DataBits;
property XONChar : byte read fXONChar
write SetXONChar
default dflt_XONChar;
property XOFFChar : byte read fXOFFChar
write SetXOFFChar
default dflt_XOFFChar;
property XONLim : word read fXONLim
write SetXONLim
default dflt_XONLim;
property XOFFLim : word read fXOFFLim
write SetXOFFLim
default dflt_XOFFLim;
property ErrorChar : byte read fErrorChar
write SetErrorChar
default dflt_ErrorChar;
property FlowControl : TFlowControl read fFlowControl
write SetFlowControl
default dflt_FlowControl;
property StripNullChars : Boolean read fStripNullChars
write SetStripNullChars
default dflt_StripNullChars;
property EOFChar : byte read fEOFChar
write SetEOFChar
default dflt_EOFChar;
property OnTransmit : TNotifyTXEvent read fOnTransmit
write fOnTransmit;
property OnReceive : TNotifyRXEvent read fOnReceive
write fOnReceive;
property AfterTransmit : TNotifyTXEvent read fAfterTransmit
write fAfterTransmit;
property AfterReceive : TNotifyRXEvent read fAfterReceive
write fAfterReceive;
end;
procedure Register;
implementation
// Create method.
constructor TSerialPort.Create(AOwner : TComponent);
begin
inherited Create(AOwner);
// Initalize the handle to the port as
// an invalid handle value. We do this
// because the port hasn't been opened
// yet, and it allows us to test for
// this condition in some functions,
// thereby controlling the behavior
// of the function.
//TSerialPort.Create(AOwner);
hCommPort := INVALID_HANDLE_VALUE;
// Set initial settings. Even though
// the default parameter was specified
// in the property, if you were to
// create a component at runtime, the
// defaults would not get set. So it
// is important to call them again in
// the create of the component.
fCommPort := dflt_CommPort;
fBaudRate := dflt_BaudRate;
fParityType := dflt_ParityType;
fParityErrorChecking := dflt_ParityErrorChecking;
fParityErrorChar := dflt_ParityErrorChar;
fParityErrorReplacement := dflt_ParityErrorReplacement;
fStopBits := dflt_StopBits;
fDataBits := dflt_DataBits;
fXONChar := dflt_XONChar;
fXOFFChar := dflt_XOFFChar;
fXONLim := dflt_XONLim;
fXOFFLim := dflt_XOFFLim;
fErrorChar := dflt_ErrorChar;
fFlowControl := dflt_FlowControl;
fStripNullChars := dflt_StripNullChars;
fEOFChar := dflt_EOFChar;
//fOnTransmit := nil;
//fOnReceive := nil;
end;
// Public method to open the port and
// assign the handle to it.
function TSerialPort.OpenPort(MyCommPort : TCommPort) : Boolean;
var
MyPort : PChar;
begin
// Make sure that the port is Closed first.
ClosePort;
MyPort := PChar('COM' + IntToStr(ord(fCommPort)+1));
hCommPort := CreateFile(MyPort,
GENERIC_READ OR GENERIC_WRITE,
0,
nil,
OPEN_EXISTING,
0,0);
// Initialize the port.
Initialize_DCB;
// Was successful if not and invalid handle.
result := hCommPort <> INVALID_HANDLE_VALUE;
end;
// Public method to Close the port.
function TSerialPort.ClosePort : boolean;
begin
FlushTX;
FlushRX;
// Close the handle to the port.
result := CloseHandle(hCommPort);
hCommPort := INVALID_HANDLE_VALUE;
end;
// Public Send data method.
procedure TSerialPort.SendData(data : PChar; size : DWord);
var
NumBytesWritten : DWord;
begin
if hCommPort = INVALID_HANDLE_VALUE then exit;
if assigned(fOnTransmit) then fONTransmit(self, Data);
WriteFile(hCommPort,
Data^,
Size,
NumBytesWritten,
nil);
// Fire the transmit event.
if assigned(fAfterTransmit) then fAfterTransmit(self, Data);
end;
function TSerialPort.InputBufferCount: LongInt;
var
oStatus: TComStat;
dwErrorCode: DWord;
begin
Result := 0;
if hCommPort = INVALID_HANDLE_VALUE then
Exit;
ClearCommError(hCommPort, dwErrorCode, @oStatus);
Result := oStatus.cbInQue;
end;
// Public Get data method.
function TSerialPort.GetData : String;
var
NumBytesRead : DWord;
// <<cbInQue>> Specifies the number
// of bytes received by the serial
// provider but not yet read by a
// ReadFile operation.
BytesInQueue : LongInt; // Number of bytes in the input buffer
oStatus: TComStat; // Variable for the ComStat structure.
dwErrorCode: DWord; // Variable to put the error codes in.
begin
if hCommPort = INVALID_HANDLE_VALUE then exit;
if assigned(fOnReceive) then fONReceive(self, ReadBuffer);
// Get the total number of bytes that
// are waiting to be read from the
// input buffer.
ClearCommError(hCommPort, dwErrorCode, @oStatus);
BytesInQueue := oStatus.cbInQue;
if BytesInQueue > 0 then begin
SetLength(ReadBuffer, BytesInQueue + 1);
ReadFile(hCommPort,
PChar(ReadBuffer)^,
BytesInQueue,
NumBytesRead,
nil);
SetLength(ReadBuffer, StrLen(PChar(ReadBuffer)));
end;
if assigned(fAfterReceive) then fAfterReceive(self, ReadBuffer);
result := ReadBuffer;
end;
// Destroy method.
destructor TSerialPort.Destroy;
begin
// Close the port first;
ClosePort;
inherited Destroy;
end;
// Initialize the device control block.
procedure TSerialPort.Initialize_DCB;
var
MyDCB : TDCB;
//file://MyCommTimeouts : TCommTimeouts;
begin
// Only want to perform the setup
// if the port has been opened and
// the handle assigned.
if hCommPort = INVALID_HANDLE_VALUE then exit;
// The GetCommState function fills in a
// device-control block (a DCB structure)
// with the current control settings for
// a specified communications device.
// (Win32 Developers Reference)
// Get a default fill of the DCB.
GetCommState(hCommPort, MyDCB);
case fBaudRate of
br110 : MyDCB.BaudRate := 110;
br300 : MyDCB.BaudRate := 300;
br600 : MyDCB.BaudRate := 600;
br1200 : MyDCB.BaudRate := 1200;
br2400 : MyDCB.BaudRate := 2400;
br4800 : MyDCB.BaudRate := 4800;
br9600 : MyDCB.BaudRate := 9600;
br14400 : MyDCB.BaudRate := 14400;
br19200 : MyDCB.BaudRate := 19200;
br38400 : MyDCB.BaudRate := 38400;
br56000 : MyDCB.BaudRate := 56000;
br128000 : MyDCB.BaudRate := 128000;
br256000 : MyDCB.BaudRate := 256000;
end;
// Parity error checking parameters.
case fParityType of
pcNone : MyDCB.Parity := NOPARITY;
pcEven : MyDCB.Parity := EVENPARITY;
pcOdd : MyDCB.Parity := ODDPARITY;
pcMark : MyDCB.Parity := MARKPARITY;
pcSpace : MyDCB.Parity := SPACEPARITY;
end;
if fParityErrorChecking then inc(MyDCB.Flags, $0002);
if fParityErrorReplacement then inc(MyDCB.Flags, $0021);
MyDCB.ErrorChar := char(fErrorChar);
case fStopBits of
sbOne : MyDCB.StopBits := ONESTOPBIT;
sbOnePtFive : MyDCB.StopBits := ONE5STOPBITS;
sbTwo : MyDCB.StopBits := TWOSTOPBITS;
end;
case fDataBits of
db4 : MyDCB.ByteSize := 4;
db5 : MyDCB.ByteSize := 5;
db6 : MyDCB.ByteSize := 6;
db7 : MyDCB.ByteSize := 7;
db8 : MyDCB.ByteSize := 8;
end;
// The 'flags' are bit flags,
// which means that the flags
// either turn on or off the
// desired flow control type.
case fFlowControl of
fcXON_XOFF : MyDCB.Flags := MyDCB.Flags or $0020 or $0018;
fcRTS_CTS : MyDCB.Flags := MyDCB.Flags or $0004 or
$0024*RTS_CONTROL_HANDSHAKE;
fcDSR_DTR : MyDCB.Flags := MyDCB.Flags or $0008 or
$0010*DTR_CONTROL_HANDSHAKE;
end;
if fStripNullChars then inc(MyDCB.Flags,$0022);
MyDCB.XONChar := Char(fXONChar);
MyDCB.XOFFChar := Char(fXONChar);
// The XON Limit is the number of
// bytes that the data in the
// receive buffer must fall below
// before sending the XON character,
// there for resuming the flow
// of data.
MyDCB.XONLim := fXONLim;
// The XOFF limit is the max number
// of bytes that the receive buffer
// can contain before sending the
// XOFF character, therefore
// stopping the flow of data.
MyDCB.XOFFLim := fXOFFLim;
// Character that signals the end of file.
if fEOFChar <> 0 then MyDCB.EOFChar := char(EOFChar);
// The SetCommTimeouts function sets
// the time-out parameters for all
// read and write operations on a
// specified communications device.
// (Win32 Developers Reference)
// The GetCommTimeouts function retrieves
// the time-out parameters for all read
// and write operations on a specified
// communications device.
// GetCommTimeouts(hCommPort, MyCommTimeouts);
// MyCommTimeouts.ReadIntervalTimeout := ...
// MyCommTimeouts.ReadTotalTimeoutMultiplier := ...
// MyCommTimeouts.etc...................
// SetCommTimeouts(hCommPort, MyCommTimeouts);
SetCommState(hCommPort, MyDCB);
end;
// Set the comm port.
procedure TSerialPort.SetCommPort(CP : TCommPort);
begin
if fCommPort <> CP then begin <------------- Here is where access violation happens
fCommPort := CP;
Initialize_DCB;
end;
end;
// Set the baud rate.
procedure TSerialPort.SetBaudRate(BR : TBaudRate);
begin
if fBaudRate <> BR then begin
fBaudRate := BR;
Initialize_DCB;
end;
end;
// Set the parity check type.
procedure TSerialPort.SetParityType(PT : TParityType);
begin
if fParityType <> PT then begin
fParityType := PT;
Initialize_DCB;
end;
end;
// Do we want to do parity error checking?
procedure TSerialPort.SetParityErrorChecking(SPEC : Boolean);
begin
if fParityErrorChecking <> SPEC then begin
fParityErrorChecking := SPEC;
Initialize_DCB;
end;
end;
// Set the parity error char.
procedure TSerialPort.SetParityErrorChar(PEC : Byte);
begin
if fParityErrorChar <> PEC then begin
fParityErrorChar := PEC;
Initialize_DCB;
end;
end;
// Set wether to replace parity errors with error char.
procedure TSerialPort.SetParityErrorReplacement(PER : Boolean);
begin
if fParityErrorReplacement <> PER then begin
fParityErrorReplacement := PER;
Initialize_DCB;
end;
end;
// Set the stop bits.
procedure TSerialPort.SetStopBits(SSB : TStopBits);
begin
if fStopBits <> SSB then begin
fStopBits := SSB;
Initialize_DCB;
end;
end;
// Set the data bits.
procedure TSerialPort.SetDataBits(SDB : TDataBits);
begin
if fDataBits <> SDB then begin
fDataBits := SDB;
Initialize_DCB;
end;
end;
// Set the XON Char.
procedure TSerialPort.SetXONChar(SXC : byte);
begin
if fXONChar <> SXC then begin
fXONChar := SXC;
Initialize_DCB;
end;
end;
// Set the XOFF Char.
procedure TSerialPort.SetXOFFChar(SXOC : byte);
begin
if fXOFFChar <> SXOC then begin
fXOFFChar := SXOC;
Initialize_DCB;
end;
end;
// Set the XON Limit.
procedure TSerialPort.SetXONLim(SXOL : word);
begin
if fXONLim <> SXOL then begin
fXONLim := SXOL;
Initialize_DCB;
end;
end;
// Set the XOFF Limit.
procedure TSerialPort.SetXOFFLim(SXFL : word);
begin
if fXOFFLim <> SXFL then begin
fXOFFLim := SXFL;
Initialize_DCB;
end;
end;
// Set the error character.
procedure TSerialPort.SetErrorChar(SEC : byte);
begin
if fErrorChar <> SEC then begin
fErrorChar := SEC;
Initialize_DCB;
end;
end;
// Set the type of flow control desired.
procedure TSerialPort.SetFlowControl(SFC : TFlowControl);
begin
if fFlowControl <> SFC then begin
fFlowControl := SFC;
Initialize_DCB;
end;
end;
// Do we want to strip off the null characters?
procedure TSerialPort.SetStripNullChars(SSNC : Boolean);
begin
if fStripNullChars <> SSNC then begin
fStripNullChars := SSNC;
Initialize_DCB;
end;
end;
// Set the EOF char.
procedure TSerialPort.SetEOFChar(SEOFC : Byte);
begin
if fEOFChar <> SEOFC then begin
fEOFChar := SEOFC;
Initialize_DCB;
end;
end;
// Public function to check if the port is open.
function TSerialPort.PortIsOpen : boolean;
begin
Result := hCommPort <> INVALID_HANDLE_VALUE;
end;
// Public method to cancel and flush the receive buffer.
procedure TSerialPort.FlushRx;
begin
if hCommPort = INVALID_HANDLE_VALUE then exit;
PurgeComm(hCommPort, PURGE_RXABORT or PURGE_RXCLEAR);
ReadBuffer := '';
end;
// Public method to cancel and flush the transmit buffer.
procedure TSerialPort.FlushTx;
begin
if hCommPort = INVALID_HANDLE_VALUE then exit;
PurgeComm(hCommPort, PURGE_TXABORT or PURGE_TXCLEAR);
end;
// Register the component in its own menu selection.
procedure Register;
begin
RegisterComponents('Misc', [TSerialPort]);
end;
end.
以下信息将发送至此Serial.pas:
function TfrmMain.SetCOMPort(Index:Integer;BaudRate:TBaudRate):Boolean;
var
TempPort:TCommPort;
begin
TempPort := cpCOM1;
If Index = 0 then
TempPort:=cpCOM1;
If Index = 1 then
TempPort:=cpCOM2;
If Index = 2 then
TempPort:=cpCOM3;
If Index = 3 then
TempPort:=cpCOM4;
If Index = 4 then
TempPort:=cpCOM5;
If Index = 5 then
TempPort:=cpCOM6;
If Index = 6 then
TempPort:=cpCOM7;
If Index = 7 then
TempPort:=cpCOM8;
If Index = 8 then
TempPort:=cpCOM9;
MySP.CommPort := TempPort;
MySP.BaudRate := BaudRate;
Result := True; <----- don't know if this is correct
end;
答案 0 :(得分:0)
if hCommPort = INVALID_HANDLE_VALUE then exit;
当您尝试读取或写入无效的地址时,会发生访问冲突。在您的代码中,唯一的内存访问是字段hCommPort
。这意味着Self
指针(实例引用)引用了无效的地址。导致此问题的常见原因包括实例引用为nil
或引用已销毁的对象。
根据您提供的信息,我们不能再说了。您必须调试程序以确定Self
无效的原因。