将 SCard 与 Setup 匹配的一种方法是打开驱动程序,然后使用 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;
}