报错:
Access violation at address 006D9963 in module 'bath.exe'. Read of address 00000004.
调用 getBoxIdAndZone()函数前几次不会报错,后面再调用就会报上面的内存错,经过跟踪,错在下面一行(FCommIsWorking 是布尔型变量)
if not FCommIsWorking then
奇怪的是引用 变量 FCommIsWorking  怎么会报错吗?然后我在这句前面加了句
showmessage(booltostr(FCommIsWorking )) 再编译运行,报错后就定位在showmessage() 这句话,说明 是引用变量 FCommIsWorking 时有问题~~ 代码如下(代码太长,完整代码见 http://bbs.2ccc.com/topic.asp?topicid=353134 )://RF卡管理类  提供查询、发牌、注销等功能
unit URFCardMng;interface
uses
  Classes, Controls, SysUtils, Forms, Variants,
  Registry, Windows, Dialogs, StrUtils, UGlobalUnit;

Const
    DLLPath='RF002Reader.dll';
Type
  TPromptMsg = procedure(msg: string) of object;//提示信息 方法指针  TRFCardMng = class(TObject)
  private
    FCommIsWorking: Boolean;  //串口是否已正常工作
    FCommPort: integer;
    FOnPromptMsg: TPromptMsg;  //提示信息事件
    reData:array of Variant;    FHandWareVer: string;//硬件版本
    FProductDate: string;//出厂日期
    FCustomID:Integer;
  private
    procedure sendPromptMsg(msg: string); //发送事件信息
    function setCommPort(commPort: Integer): Integer;//设置串口端口  返回值 0: 成功 -1:失败; 1:串口已打开 ;2;串口端口不存在
    procedure openComm();//如果串口没有打开则打开
  public
    constructor Create;
    destructor  Destory; overload;
  public
    {
      自动打开串口      返回值:0:成功  其它值:失败
    }
     function autoOpenComm(): integer;
    {
      功能:读取手牌号与区域
      boxId:取得的手牌号
      zone:取得的区域名称
      errMsg:错误信息
    }
    function getBoxIdAndZone(var boxId: string;var ZoneIndex: Integer; var errMsg: string): Integer;    procedure enterLock();
    procedure leaveLock();  published
    {
      事件触发方法
      if Assigned(OnPromptMsg) then
         OnPromptMsg(Text);    }
    property OnPromptMsg: TPromptMsg read FOnPromptMsg write FOnPromptMsg;    property HandWareVer: string read FHandWareVer;  //硬件版本
    property ProductDate: string read FProductDate;  //出厂日期
   // property CustomID: Integer read FCustomID ;
  end;implementation
var
  FCriticalSection :TRTLCriticalSection;
  
  function OpenReader(COMMNAME:integer):HWND;  stdcall; external DLLPath name 'OpenReader';
  function CloseReader():HWND;  stdcall; external DLLPath name 'CloseReader';
  function ReadRFID(Var RFIDData:Byte):DWORD;  stdcall; external DLLPath name 'ReadRFID';
  function SetCard(Var RFIDData:Byte):DWORD;  stdcall; external DLLPath name 'SetCard';
  function ClearCard(Var RFIDData:Byte):DWORD;  stdcall; external DLLPath name 'ClearCard';
  function GetReaderVersion(Var ReaderVersion:Byte):DWORD;  stdcall; external DLLPath name 'GetReaderVersion';
  function GetHandId(Var HandId:Byte):DWORD;  stdcall; external DLLPath name 'GetHandId';
  function SetHandId(Var HandId:Byte):DWORD;  stdcall; external DLLPath name 'SetHandId';
  function GetReaderRTC(var RTC:byte):DWORD; stdcall;external DllPath name 'GetRTC';
  function SetReaderRTC(var RTC:byte):DWORD; stdcall;external DllPath name 'SetRTC';
  function GetHandType(Var HandType:Byte):DWORD;  stdcall; external DLLPath name 'GetHandType';
  function SetHandType(Var HandType:Byte):DWORD;  stdcall; external DLLPath name 'SetHandType';{ TRFCardMng }constructor TRFCardMng.Create;
begin
  FCommIsWorking := False;
  openComm;
end;destructor TRFCardMng.Destory;
begin
end;function TRFCardMng.setCommPort(commPort: Integer): Integer;
var
  RetVal:DWORD;
  tmpVersion:array   [0..9]   of   byte;
begin
  try
    if FCommPort = commPort then
    begin
       Result := 0;
       exit;
    end;    FCommPort := commPort;
    Result := 0;
    FCommIsWorking := True;
    RetVal:=OpenReader(CommPort);                 //执行DLL函数,打开读卡器,传入参数为读卡器对应的串口号码
    if (RetVal=0) then
    begin
      FcommPort := 0;
      FCommIsWorking :=False;
      Result:=-1;                               //返回打开异常
      exit;
    end;
    RetVal:=GetReaderVersion(tmpVersion[0]);     //查询读卡器版本信息
    if (RetVal=$00)   then                      //读版本指令返回正常
    Begin
      FHandWareVer:=chr(tmpVersion[1])+chr(tmpVersion[2])+chr(tmpVersion[3])+chr(tmpVersion[4]);
      FProductDate:=IntToHex(tmpVersion[5],2)+IntToHex(tmpVersion[6],2);;
      FCustomID:= tmpVersion[7]*256+ tmpVersion[8];
      if (FCustomID>$0000) then
      begin
        sendPromptMsg('[COM' + IntToStr(commPort) + ']'+'联机成功,硬件版本: '+FHandWareVer+' 出厂日期:'+FProductDate+'  客户代码: '+IntToHex(FCustomID,4));
      end
      else
      begin
        sendPromptMsg('联机成功,硬件版本: '+FHandWareVer+'  内部专用');
      end
    end
    else
    begin
      sendPromptMsg('[COM' + IntToStr(commPort) + ']' + '通讯失败!');
      FCommIsWorking := False;
      Result := -1;
    end;  except
    on e:exception do
    begin
      if UpperCase(e.Message) = 'PORT ALREADY OPEN' then
      begin
         Result := 1;//串口已打开
         sendPromptMsg('[COM' + IntToStr(commPort) + ']' + '串口已打开');
      end
      else if UpperCase(e.Message) = 'INVALID PORT NUMBER' then
      begin
         Result := 2;//串口端口不存在
         sendPromptMsg('[COM' + IntToStr(commPort) + ']' + '串口端口不存在');
      end  
      else
      begin
        sendPromptMsg('[COM' + IntToStr(commPort) + '] 错误:' + e.Message);
      end;    end;
  end;end;
function TRFCardMng.getBoxIdAndZone(var boxId: string;var ZoneIndex: Integer; var errMsg: string): Integer;
var
  RetVal:DWORD;
  tmpHandId:array   [0..5]   of   byte;
begin
//  openComm;
  try
    enterLock();
    if not FCommIsWorking then
    begin
       Result := 98;//串口未打开
       errMsg := '串口未打开';
       sendPromptMsg('串口未打开');
       exit;
    end;
    Result := -1;
    errMsg := '读卡时:未知错误';
    RetVal:=GetHandId(tmpHandId[0]);                  //调用DLL读手牌码指令
    if ((RetVal=0) and ((tmpHandId[0] xor tmpHandId[1] xor tmpHandId[2])=tmpHandId[3])) then
    Begin
      boxId := IntTohex(tmpHandId[0]*$100+tmpHandId[1],4);
      ZoneIndex := tmpHandId[2]; //getZone( (RecData[3]-48) mod 4 ) ;
      sendPromptMsg('读手牌与门禁通道码成功');
      Result := 0;
    end
    else
    begin
     errMsg :=  '读手牌与区域异常';
     sendPromptMsg('读手牌与门禁通道码异常');
     Result := 2;
    end;   finally
    leaveLock();
  end;end;  procedure TRFCardMng.sendPromptMsg(msg: string);
begin
  {
  try
    if Assigned(OnPromptMsg) then
    begin
      OnPromptMsg(msg);
    end;
  except  end;
  }
end;
 function TRFCardMng.autoOpenComm: integer;
var
  reg:TRegistry;
  ts:TStrings;
  commPort: Integer;
  i: integer;
begin
  try
    enterLock();
    try
      Result := -1;
      reg := TRegistry.Create;
      reg.RootKey := HKEY_LOCAL_MACHINE;
      reg.OpenKey('hardware\devicemap\serialcomm',false);
      ts:=TStringList.Create;      
      commPort := UGlobalUnit.ReadIniFile('RFCard','commport',0);
      if commPort <> 0 then
      begin
        if setCommPort(commPort) = 0 then     //设置串口成功
        begin
           Result := 0;
           Exit;
        end;
      end;        reg.GetValueNames(ts);
      if ts.Count = 0 then
      begin
        sendPromptMsg('未找到串行通讯端口');
      end;  
      for i := 0 to ts.Count-1 do
      begin
        commPort := StrToInt( Copy(reg.ReadString(ts.Strings[i]),4,MaxInt) );
        if setCommPort(commPort) = 0 then     //设置串口成功
        begin
           UGlobalUnit.WriteIniFile('RFCard','commport',commPort);
           Result := 0;
           Break;
        end;
      end;
    except
      on e: Exception do
      begin
         sendPromptMsg('[COM' + IntToStr(commPort) + ']错误:' + e.Message);
      end;  
    end;
    
  finally
    ts.Free;
    reg.CloseKey;
    reg.free;
    leaveLock();
  end;
end;procedure TRFCardMng.openComm;
begin
  try
    enterLock();
    if not FCommIsWorking then
    begin
       if  autoOpenComm <> 0 then
       begin
         sendPromptMsg('打开串口失败');
       end;
    end;
  finally
    leaveLock();
  end;end;
function TRFCardMng.getCustomId: string;
begin
  Result :=  IntToHex(FCustomID,4);
end;procedure TRFCardMng.enterLock;
begin
  EnterCriticalSection(FCriticalSection);
end;procedure TRFCardMng.leaveLock;
begin
  LeaveCriticalSection(FCriticalSection);
end;initialization
  InitializeCriticalSection(FCriticalSection); //初始化
finalization
  DeleteCriticalSection(FCriticalSection); //删除
end.