问题
Having only a handle and context to a PCSC reader using winscard
on Windows >= XP, is there some way to get its device instance id or something else that can be used in the SetupDi*
API to find out which driver is loaded for said reader.
SCardGetReaderDeviceInstanceId
is only available on Windows 8, so unfortunately not for me.
As a plan B, all smart card readers could be enumerated in SetupDi
using the smart card reader class guid. But then I would need a unique attribute to be able to correlate a reader between SCard*
API and SetupDi*
API. For example, the serial number sounds like a good candidate, but not all manufacturers use it.
Any ideas?
回答1:
One way to match SCard with Setup is to open the driver, then use IOCTL_SMARTCARD_GET_ATTRIBUTE to query SCARD_ATTR_DEVICE_SYSTEM_NAME and match it with the one via SCard API.
There is only one tiny problem. The Smartcard service opens all smartcard drivers without sharing. You first need to stop the Smartcard service before being able to open the device driver.
Another solution is to use the SCardControl function to call the driver via IOCTL_xxx calls from within the SCard API.
The problem here is that until so far I haven't found a IOCTL_xxx call which I can use to match with any property from the Setup API.
I tried a brute force loop to scan for supported IOCTL_xxx calls but the SCard api crashes when doing so, and reporting every failing IOCTL_xxx call to the event viewer.
-- update --
The IOCTL supports the following tags:
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
Below is the code to generate the smartcard device name from either the IOCTL, and via SCARD also to demonstrate the simularity between two methods
//------------------------------------------------------------------------------
// 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;
}
回答2:
From my tests, it seams that scard service assigns the name in this order:
a) SPDRP_FRIENDLYNAME if present
b) SPDRP_DEVICEDESC
This way, I was able to match the SCardListReaders() names with the rigth Device/Driver.
Hope this helps ...
来源:https://stackoverflow.com/questions/14253830/how-to-find-the-device-instance-id-of-a-pcsc-reader