访问违规!无法访问的价值Serial.pas

时间:2014-05-23 11:43:27

标签: delphi delphi-7

我的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;

1 个答案:

答案 0 :(得分:0)

if hCommPort = INVALID_HANDLE_VALUE then exit;

当您尝试读取或写入无效的地址时,会发生访问冲突。在您的代码中,唯一的内存访问是字段hCommPort。这意味着Self指针(实例引用)引用了无效的地址。导致此问题的常见原因包括实例引用为nil或引用已销毁的对象。

根据您提供的信息,我们不能再说了。您必须调试程序以确定Self无效的原因。