如何查找PCSC阅读器的设备实例ID

时间:2013-01-10 08:45:20

标签: windows pcsc winscard

在Windows> = XP上使用winscard只有一个PCSC阅读器的句柄和上下文,是否有某种方法可以获取其设备实例ID或可在SetupDi*中使用的其他内容用于找出为所述阅读器加载的驱动程序的API。

SCardGetReaderDeviceInstanceId仅适用于Windows 8,不幸的是不适合我。

作为计划B,可以使用智能卡读卡器类guid在SetupDi中枚举所有智能卡读卡器。但是,我需要一个唯一属性才能在SCard* API和SetupDi* API之间关联阅读器。例如,序列号听起来很合适,但并非所有制造商都使用它。

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

将SCard与安装程序匹配的一种方法是打开驱动程序,然后使用IOCTL_SMARTCARD_GET_ATTRIBUTE查询SCARD_ATTR_DEVICE_SYSTEM_NAME,并通过SCard API将其与一个匹配。

只有一个小问题。智能卡服务无需共享即可打开所有智能卡驱动程序。首先需要停止智能卡服务才能打开设备驱动程序。

另一个解决方案是使用SCardControl函数通过SCard API中的IOCTL_xxx调用来调用驱动程序。

这里的问题是,到目前为止,我还没有找到IOCTL_xxx调用,我可以使用该调用来匹配Setup API中的任何属性。

我尝试使用强力循环来扫描支持的IOCTL_xxx调用,但这样做时SCard api崩溃,并向事件查看器报告每次失败的IOCTL_xxx调用。

- 更新 -

IOCTL支持以下标记:

SCARD_ATTR_VENDOR_NAME SCARD_ATTR_VENDOR_IFD_TYPE SCARD_ATTR_VENDOR_IFD_VERSION SCARD_ATTR_CHANNEL_ID SCARD_ATTR_PROTOCOL_TYPES SCARD_ATTR_DEFAULT_CLK SCARD_ATTR_MAX_CLK SCARD_ATTR_DEFAULT_DATA_RATE SCARD_ATTR_MAX_DATA_RATE SCARD_ATTR_MAX_IFSD SCARD_ATTR_POWER_MGMT_SUPPORT SCARD_ATTR_CHARACTERISTICS SCARD_ATTR_ICC_PRESENCE SCARD_ATTR_ICC_INTERFACE_STATUS SCARD_ATTR_DEVICE_UNIT

以下是从IOCTL生成智能卡设备名称的代码,并通过SCARD来演示两种方法之间的相似性

//------------------------------------------------------------------------------
// PROTOTYPES
//------------------------------------------------------------------------------

/* get the Smartcard DeviceName via IOCTL calls */
BOOL Smc_GetDeviceNameViaIOCTL(HANDLE,TCHAR*,UINT);

/* get the Smartcard DeviceName via SCARD calls */
BOOL Smc_GetDeviceNameViaSCARD(SCARDHANDLE,TCHAR*,UINT);





//------------------------------------------------------------------------------
// IMPLEMENTATIONS
//------------------------------------------------------------------------------




/************************************************/
/* get the Smartcard DeviceName via IOCTL calls */
/************************************************/

BOOL Smc_GetDeviceNameViaIOCTL(HANDLE in_hDev, TCHAR *out_Name, UINT in_MaxLen)
{
    /* locals */
    UINT  lv_Pos;
    DWORD lv_InBuf;
    DWORD lv_ValLen;
    DWORD lv_ChanID;
    CHAR  lv_OutBuf[256];
    BOOL  lv_Result;


  // reserve space for eos
  if (in_MaxLen-- <= 0)
    return FALSE;

  // init the position
  lv_Pos = 0;

  // set the tag
  lv_InBuf = SCARD_ATTR_VENDOR_NAME;

  // get the value
  lv_Result = DeviceIoControl(
    in_hDev, IOCTL_SMARTCARD_GET_ATTRIBUTE,
    &lv_InBuf, sizeof(DWORD), lv_OutBuf, 256, &lv_ValLen, 0);

  // fail?
  if (!lv_Result)
    return FALSE;

  // check the length, including space
  if (lv_Pos + lv_ValLen + 1 > in_MaxLen)
    return FALSE;

  // append to output
  AChar2TCharCL(lv_OutBuf, lv_ValLen, &out_Name[lv_Pos], in_MaxLen-lv_Pos);

  // update position
  lv_Pos += lv_ValLen;

  // append space
  out_Name[lv_Pos++] = ' ';

  // set the tag
  lv_InBuf = SCARD_ATTR_VENDOR_IFD_TYPE;

  // get the value
  lv_Result = DeviceIoControl(
    in_hDev, IOCTL_SMARTCARD_GET_ATTRIBUTE,
    &lv_InBuf, sizeof(DWORD), lv_OutBuf, 256, &lv_ValLen, 0);

  // fail?
  if (!lv_Result)
    return FALSE;

  // check the length, including space
  if (lv_Pos + lv_ValLen + 1 > in_MaxLen)
    return FALSE;

  // append to output
  AChar2TCharCL(lv_OutBuf, lv_ValLen, &out_Name[lv_Pos], in_MaxLen-lv_Pos);

  // update position
  lv_Pos += lv_ValLen;

  // append space
  out_Name[lv_Pos++] = ' ';

  // set the tag
  lv_InBuf = SCARD_ATTR_DEVICE_UNIT; 

  // get the value
  lv_Result = DeviceIoControl(
    in_hDev, IOCTL_SMARTCARD_GET_ATTRIBUTE,
    &lv_InBuf, sizeof(DWORD), &lv_ChanID, sizeof(DWORD), &lv_ValLen, 0);

  // fail?
  if (!lv_Result)
    return FALSE;

  // format as string
  FormatStringA(lv_OutBuf, 256, "%d", lv_ChanID);

  // check the length
  if (lv_Pos + strlenA(lv_OutBuf) > in_MaxLen)
    return FALSE;

  // append to output
  AChar2TCharC(lv_OutBuf, &out_Name[lv_Pos], in_MaxLen-lv_Pos);

  // done
  return TRUE;
}





/************************************************/
/* get the Smartcard DeviceName via SCARD calls */
/************************************************/

BOOL Smc_GetDeviceNameViaSCARD(SCARDHANDLE in_hCard, TCHAR *out_Name, UINT in_MaxLen)
{
    /* locals */
    UINT  lv_Pos;
    DWORD lv_InBuf;
    DWORD lv_ValLen;
    DWORD lv_ChanID;
    CHAR  lv_OutBuf[256];
    UINT  lv_hResult;


  // reserve space for eos
  if (in_MaxLen-- <= 0)
    return FALSE;

  // init the position
  lv_Pos = 0;

  // set the tag
  lv_InBuf  = SCARD_ATTR_VENDOR_NAME;
  lv_ValLen = 256;

  // get the value
  lv_hResult = lib_SCardGetAttrib(in_hCard, lv_InBuf, (BYTE*)lv_OutBuf, &lv_ValLen);

  // fail?
  if (FAILED(lv_hResult))
    return FALSE;

  // check the length, including space
  if (lv_Pos + lv_ValLen + 1 > in_MaxLen)
    return FALSE;

  // append to output
  AChar2TCharCL(lv_OutBuf, lv_ValLen, &out_Name[lv_Pos], in_MaxLen-lv_Pos);

  // update position
  lv_Pos += lv_ValLen;

  // append space
  out_Name[lv_Pos++] = ' ';

  // set the tag
  lv_InBuf  = SCARD_ATTR_VENDOR_IFD_TYPE;
  lv_ValLen = 256;

  // get the value
  lv_hResult = lib_SCardGetAttrib(in_hCard, lv_InBuf, (BYTE*)lv_OutBuf, &lv_ValLen);

  // fail?
  if (FAILED(lv_hResult))
    return FALSE;

  // check the length, including space
  if (lv_Pos + lv_ValLen + 1 > in_MaxLen)
    return FALSE;

  // append to output
  AChar2TCharCL(lv_OutBuf, lv_ValLen, &out_Name[lv_Pos], in_MaxLen-lv_Pos);

  // update position
  lv_Pos += lv_ValLen;

  // append space
  out_Name[lv_Pos++] = ' ';

  // set the tag
  lv_InBuf  = SCARD_ATTR_DEVICE_UNIT;
  lv_ValLen = sizeof(DWORD);

  // get the value
  lv_hResult = lib_SCardGetAttrib(in_hCard, lv_InBuf, (BYTE*)&lv_ChanID, &lv_ValLen);

  // fail?
  if (FAILED(lv_hResult))
    return FALSE;

  // format as string
  FormatStringA(lv_OutBuf, 256, "%d", lv_ChanID);

  // check the length
  if (lv_Pos + strlenA(lv_OutBuf) > in_MaxLen)
    return FALSE;

  // append to output
  AChar2TCharC(lv_OutBuf, &out_Name[lv_Pos], in_MaxLen-lv_Pos);

  // done
  return TRUE;
}

答案 1 :(得分:0)

从我的测试中,scard服务按以下顺序分配名称的接缝:
a)SPDRP_FRIENDLYNAME(如果存在)
b)SPDRP_DEVICEDESC

这样,我就可以将SCardListReaders()名称与rigth设备/驱动程序匹配。

希望这会有所帮助......