windows - 如何找到 PCSC 阅读器的设备实例 ID

标签 windows pcsc winscard device-instance-id

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

SCardGetReaderDeviceInstanceId 仅在 Windows 8 上可用,所以不幸的是不适合我。

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

有什么想法吗?

最佳答案

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

只有一个小问题。智能卡服务打开所有智能卡驱动程序而不共享。您首先需要停止智能卡服务,然后才能打开设备驱动程序。

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

这里的问题是,到目前为止我还没有找到一个 IOCTL_xxx 调用,我可以使用它来匹配来自设置 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;
}

关于windows - 如何找到 PCSC 阅读器的设备实例 ID,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14253830/

相关文章:

windows - 有什么方法可以判断 Windows 目录是否可写而无需实际写入它进行测试?

Windows 10 无需配对即可连接到蓝牙经典设备

javascript - Rails Guides : Getting Started 5. 13 删除文章:不会出现确认对话框

smartcard - 使用相同的 T=1 APDU 发送和接收数据

java - WinScard 智能卡 dll 32 位 64 位兼容性

python - 用 py2exe 制作的可执行文件不能在 windows xp 32 位上运行

windows - 如何检测智能卡读卡器接口(interface)特性

c# - 如何从 C# 中的智能卡读取名称和地址等基本数据?

C# WinScard.SCardListReaders 应该只列出已连接的阅读器(但它列出了所有过去安装的现在未连接的阅读器名称)