Delphi SCARD_F_内部_错误由SCARDETSTATUSCHANGE导致

Delphi SCARD_F_内部_错误由SCARDETSTATUSCHANGE导致,delphi,smartcard,pcsc,winscard,Delphi,Smartcard,Pcsc,Winscard,我正在开发使用Mifare Classic 1K卡和HID万能钥匙5421(5321的继承者)的应用程序。我使用线程检测卡的移除/插入。 Delphi代码(线程方法): 函数CardWatcherThread(PContext:Pointer):整数; 变量 雷特瓦:红衣主教; RContext:红衣主教; RStates:SCARD_READERSTATEA的数组[0..0]; 开始 尝试 RContext:=基数(PContext^); FillChar(RStates,SizeOf(RSt

我正在开发使用Mifare Classic 1K卡和HID万能钥匙5421(5321的继承者)的应用程序。我使用线程检测卡的移除/插入。 Delphi代码(线程方法):

函数CardWatcherThread(PContext:Pointer):整数;
变量
雷特瓦:红衣主教;
RContext:红衣主教;
RStates:SCARD_READERSTATEA的数组[0..0];
开始
尝试
RContext:=基数(PContext^);
FillChar(RStates,SizeOf(RStates),#0);
RStates[0]。szReader:=SelectedReader;
RStates[0]。pvUserData:=nil;
RStates[0]。dwCurrentState:=SCARD_STATE_unknown;
当ReaderOpen和(而不是Application.Terminated)开始时
RetVar:=SCardGetStatusChange(RContext,MAX_WAIT_TIME_SCARDSTATUSCHANGE,@RStates,1);
RStates[0]。dwCurrentState:=RStates[0]。dwEventState;
ActReaderState:=RStates[0]。dwEventState;
//如果最大等待时间的状态变化不是无限的,则避免关于时间移动的错误
如果(RetVar SCARD_E_TIMEOUT)或(MAX_WAIT_TIME_SCARDSTATUSCHANGE=-1),则开始
SendMessage(NotifyHandle,WM_CARDSTATE,RetVar,0);
结束;
结束;
最后
结果:=0;
结束;
结束;
我正在使用SendMessage通知我的智能卡类在哪里检测到正确的状态。此外,当我检测到插卡时,我会自动连接并读取智能卡中的数据

我的应用程序在大部分时间都正常工作,但有时,例如,在插入卡的10000次中,我会从
SCardGetStatusChange
中得到SCARD\u F\u INTERNAL\u ERROR。发生这种情况时,SCARDETSTATUSCHANGE始终只会导致内部错误。当我检测到这种情况时,我试图
SCardCancel
SCardReleaseContext
,结束线程并建立新的上下文,并用这个新上下文创建新的观察线程,但这没有帮助,因为SCardGetStatusChange继续返回SCARD\u F\u INTERNAL\u ERROR。只有当我关闭应用程序并再次运行时,问题才会消失。 这对我来说是随机发生的,我不能用一些已知的场景重现它。在PC中可以有更多的读者,但我只建立到Omnikey 5421的连接


有人遇到了这个问题?

很难说是哪里出了问题,但我对您的代码没有什么评论,希望它们能帮助您

  • 您应该首先检查
    SCardGetStatusChange
    的返回值,如果是
    SCARD\u E\u TIMEOUT
    ,则跳过所有处理并开始下一个循环
  • 而不仅仅是
    RStates[0]。dwCurrentState:=RStates[0]。dwEventState
    您还必须清除状态中的
    SCARD\u STATE\u CHANGED
    位(即,如果状态实际更改)
  • 据我所知,资源管理器上下文可能会变得无效,因此在调用
    SCardGetStatusChange
    之前,请确保您仍然拥有良好的上下文(如果没有获取新的上下文)
因此,请尝试类似的方法(这是键入到浏览器中的,因此无法替换,可能无法按原样编译):

函数CardWatcherThread(PContext:Pointer):整数;
变量
雷特瓦:红衣主教;
RContext:红衣主教;
RStates:SCARD_READERSTATEA的数组[0..0];
开始
尝试
RContext:=基数(PContext^);
FillChar(RStates,SizeOf(RStates),#0);
RStates[0]。szReader:=SelectedReader;
RStates[0]。pvUserData:=nil;
RStates[0]。dwCurrentState:=SCARD_STATE_unknown;
当ReaderOpen和(而不是Application.Terminated)开始时
如果(SCardIsValidContext(RContext)SCARD_S_SUCCESS),则开始
RetVal:=骇人听闻的背景(…);
结束;
RetVar:=SCardGetStatusChange(RContext,MAX_WAIT_TIME_SCARDSTATUSCHANGE,@RStates,1);
案例检索
SCARD_E_超时:;
伤痕累累的成功:开始
如果((RStates[0].dwEventState和SCARD_STATE_CHANGED)0),则开始
RStates[0]。dwCurrentState:=RStates[0]。dwEventState xor SCARD_状态_已更改;
//读者的状态改变了,做点什么吧
结束;
结束;
结束;
结束;
最后
结果:=0;
结束;
结束;

我非常怀疑您是否能在这里找到帮助。联系您所用硬件的供应商。@DavidHeffernan我试图联系HID,但没有回应:/1首先感谢您的宝贵意见。我会试试这个,看看是否有帮助。有希望:)
function CardWatcherThread(PContext: Pointer): integer;
var
  RetVar   : cardinal;
  RContext : cardinal;
  RStates  : array[0..0] of SCARD_READERSTATEA;
begin
  try
    RContext := Cardinal(PContext^);
    FillChar(RStates,SizeOf(RStates),#0);
    RStates[0].szReader       := SelectedReader;
    RStates[0].pvUserData     := nil;
    RStates[0].dwCurrentState := SCARD_STATE_UNAWARE;
    while ReaderOpen and (not Application.Terminated) do begin
      RetVar := SCardGetStatusChange(RContext, MAX_WAIT_TIME_SCARDSTATUSCHANGE, @RStates, 1);
      RStates[0].dwCurrentState := RStates[0].dwEventState;
      ActReaderState := RStates[0].dwEventState;

      // Avoid sedning error about timemout if MAX_WAIT_TIME_SCARDSTATUSCHANGE is not infinite
      if (RetVar <> SCARD_E_TIMEOUT) or (MAX_WAIT_TIME_SCARDSTATUSCHANGE = -1) then begin
        SendMessage(NotifyHandle, WM_CARDSTATE, RetVar, 0);
      end;
    end;
  finally
    Result := 0;
  end;
end;
function CardWatcherThread(PContext: Pointer): integer;
var
  RetVar   : cardinal;
  RContext : cardinal;
  RStates  : array[0..0] of SCARD_READERSTATEA;
begin
  try
    RContext := Cardinal(PContext^);
    FillChar(RStates,SizeOf(RStates),#0);
    RStates[0].szReader       := SelectedReader;
    RStates[0].pvUserData     := nil;
    RStates[0].dwCurrentState := SCARD_STATE_UNAWARE;
    while ReaderOpen and (not Application.Terminated) do begin
      if(SCardIsValidContext(RContext) <> SCARD_S_SUCCESS)then begin
         RetVal := SCardEstablishContext(...);
      end;
      RetVar := SCardGetStatusChange(RContext, MAX_WAIT_TIME_SCARDSTATUSCHANGE, @RStates, 1);
      case RetVal of
        SCARD_E_TIMEOUT:;
        SCARD_S_SUCCESS: begin
           if((RStates[0].dwEventState and SCARD_STATE_CHANGED) <> 0)then begin
              RStates[0].dwCurrentState := RStates[0].dwEventState xor SCARD_STATE_CHANGED;
              // reader's state changed, do something
           end;
        end;
      end;
    end;
  finally
    Result := 0;
  end;
end;