Delphi SCARD_F_内部_错误由SCARDETSTATUSCHANGE导致
我正在开发使用Mifare Classic 1K卡和HID万能钥匙5421(5321的继承者)的应用程序。我使用线程检测卡的移除/插入。 Delphi代码(线程方法):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
函数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;