SCardGetStatusChange() and number of card events
SCardGetStatusChange() does not return the number of card events in the upper word ofdwEventState
.This is not a bug since I don't think this feature was every present in the PC/SC from Apple. It is a feature request and not a bug report.
From the Doxygen documentation of pcsc-lite:
This behaviour is also present in PC/SC on Windows.dwEventState
also contains a number of events in the upper 16 bits (dwEventState
& 0xFFFF0000). This number of events is incremented for each card insertion or removal in the specified reader. This can be used to detect a card removal/insertion between two calls toSCardGetStatusChange()
.
It is the only way to know that the card has been removed from a reader and inserted again while no call to
SCardGetStatusChange()
was running. Potentially the inserted card is not the same as the removed card so the PC/SC application may have to build a new applicative context for the new card.See also
Apple bug report #23937633 "PC/SC SCardGetStatusChange() and number of card events"Sample code
Using the Python PC/SC wrapper PySCard to have a shorter code.#! /usr/bin/env python from smartcard.scard import * from smartcard.pcsc.PCSCExceptions import * def parseEventState(eventstate): stateList = list() states = {SCARD_STATE_IGNORE: "Ignore", SCARD_STATE_CHANGED: "Changed", SCARD_STATE_UNKNOWN: "Unknown", SCARD_STATE_UNAVAILABLE: "Unavailable", SCARD_STATE_EMPTY: "Empty", SCARD_STATE_PRESENT: "Present", SCARD_STATE_ATRMATCH: "ATR match", SCARD_STATE_EXCLUSIVE: "Exclusive", SCARD_STATE_INUSE: "In use", SCARD_STATE_MUTE: "Mute"} for state in states: if eventstate & state: stateList.append(states[state]) return stateList hresult, hcontext = SCardEstablishContext(SCARD_SCOPE_USER) if hresult != SCARD_S_SUCCESS: raise EstablishContextException(hresult) hresult, readers = SCardListReaders(hcontext, []) if hresult != SCARD_S_SUCCESS: raise ListReadersException(hresult) print 'PC/SC Readers:', readers readerstates = {} for reader in readers: readerstates[reader] = (reader, SCARD_STATE_UNAWARE) hresult, newstates = SCardGetStatusChange(hcontext, 0, readerstates.values()) if hresult != SCARD_S_SUCCESS: raise BaseSCardException(hresult) print newstates for readerState in newstates: readername, eventstate, atr = readerState readerstates[readername] = (readername, eventstate) print "Move the smart card" ok = True while ok: try: hresult, newstates = SCardGetStatusChange(hcontext, INFINITE, newstates) if hresult != SCARD_S_SUCCESS and hresult != SCARD_E_TIMEOUT: raise BaseSCardException(hresult) except KeyboardInterrupt: ok = False for readerState in newstates: readername, eventstate, atr = readerState states = parseEventState(eventstate) print states, hex(eventstate) hresult = SCardReleaseContext(hcontext) print "SCardReleaseContext()", SCardGetErrorMessage(hresult) if hresult != SCARD_S_SUCCESS: raise ReleaseContextException(hresult)
Result (on El Capitan)
$ ./SCardGetStatusChange.py PC/SC Readers: ['Gemalto PC Twin Reader'] [('Gemalto PC Twin Reader', 18, [])] Move the smart card ['Changed', 'Present'] 0x22 ['Empty', 'Changed'] 0x12 ['Changed', 'Present'] 0x22 ['Empty', 'Changed'] 0x12 ^C['Empty', 'Changed'] 0x12 SCardReleaseContext() Command successful.
For the tests I insert and remove the card 2 times.
Then press Control-C and insert the card to quit the program.
Expected result (on Debian)
$ ./SCardGetStatusChange.py PC/SC Readers: ['Gemalto PC Twin Reader 00 00'] [('Gemalto PC Twin Reader 00 00', 18, [])] Move the smart card ['Changed', 'Present'] 0x10022 ['Empty', 'Changed'] 0x20012 ['Changed', 'Present'] 0x30022 ['Empty', 'Changed'] 0x40012 ^C['Empty', 'Changed'] 0x40012 SCardReleaseContext() Command successful.
The change is the value
eventstate
displayed (in hexadecimal).On Debian the high word (upper 16 bits) takes the values 1, 2, 3 and 4.
If the value change from 0x10022 to 0x30022, the reader state is the same (
SCARD_STATE_CHANGED
and SCARD_STATE_PRESENT
) but you know that the card has been removed and inserted.