It looks like Windows introduced a new behavior when the last smart card
reader is disconnected. The PC/SC layer (WinSCard library) will return the
error SCARD_E_SERVICE_STOPPED
.
According to MSDN "Smart Card Return Values":
SCARD_E_SERVICE_STOPPED
0x8010001E
The smart card resource manager has shut down.
Demonstration
The idea is to wait for a smart card reader if none is already present.
Then wait for the card reader to be disconnected.
Once disconnected SCardListReaders()
will return SCARD_E_SERVICE_STOPPED
(0x8010001E
) instead of the expected SCARD_E_NO_READERS_AVAILABLE
(0x8010002E
).
Source code
#! /usr/bin/env python3 from smartcard.scard import * from smartcard.pcsc.PCSCExceptions import * import time hresult, hcontext = SCardEstablishContext(SCARD_SCOPE_USER) if hresult != SCARD_S_SUCCESS: raise EstablishContextException(hresult) hresult, readers = SCardListReaders(hcontext, []) if not hresult in [SCARD_S_SUCCESS, SCARD_E_NO_READERS_AVAILABLE]: raise ListReadersException(hresult) print('PC/SC Readers:', readers) if not len(readers): print("Wait for the first reader") while not len(readers): hresult, readers = SCardListReaders(hcontext, []) if not hresult in [SCARD_S_SUCCESS, SCARD_E_NO_READERS_AVAILABLE]: raise ListReadersException(hresult) time.sleep(1) print('PC/SC Readers:', readers) print("wait for the last reader removal") while len(readers): hresult, readers = SCardListReaders(hcontext, []) if not hresult in [SCARD_S_SUCCESS, SCARD_E_NO_READERS_AVAILABLE]: raise ListReadersException(hresult) time.sleep(1) print('PC/SC Readers:', readers) hresult = SCardReleaseContext(hcontext) if hresult != SCARD_S_SUCCESS: raise ReleaseContextException(hresult)
GNU/Linux result
rousseau@debian:~ $ ./SCardListReaders.py PC/SC Readers: [] Wait for the first reader PC/SC Readers: ['Alcor Micro AU9540 00 00'] wait for the last reader removal PC/SC Readers: []
Windows result
(base) C:\Users\ludovic\Documents>python SCardListReaders.py PC/SC Readers: [] Wait for the first reader PC/SC Readers: ['Generic EMV Smartcard Reader 0'] wait for the last reader removal Traceback (most recent call last): File "C:\Users\ludovic\Documents\SCardListReaders.py", line 29, in <module> raise ListReadersException(hresult) smartcard.pcsc.PCSCExceptions.ListReadersException: Failed to list readers:
Le gestionnaire de ressources des cartes ŕ puce s’est arręté. (0x8010001E)
Sorry for the error message in French. I don't know an equivalent of "LANG=C program
" to have program run and use the default language (English).
You can also note the strange display of accented letters. Windows is not yet Unicode ready? :-)
Problems
The problem is that this new behavior broke code in PySCard, my PC/SC Python wrapper.
For example see
- " CardRequest waitforcard ATR can't see reconnected readers on Windows (regression) #123 "
- " Windows smartcard service is started only once #114 "
- " fix #74: plugout the last device will raise an smartcard.Exceptions #93 "
- " Plugout an PCSC device will raise ListReadersException(hresult) on windows #74 "
- " Exception ListReadersException raised after disconnecting PCSC reader #13 "
Yes, it is an old issue. I tried to fix it many times but the fixes has some other side effects and the problem is still present somewhere.
Windows is NOT my preferred platform (far from it) so fixing Windows issue is a P.I.T.A. for me. Help is really welcome here.
But Why?
What problem Microsoft is trying to solve with this behavior?
Why killing the resource manager and returning an error while there is still PC/SC clients connected to the resource manager?
If you have an idea of the answers please tell me.
If you know a way to change the behavior please tell me.
Use the pcsclite-muscle mailing list to discuss this issue.