#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <winscard.h>
#define CHECK(f, rv, panic) \
printf(f "(): 0x%08lX, %s\n", rv, pcsc_stringify_error(rv)); \
if ((SCARD_S_SUCCESS != rv) && panic) \
{ \
return -1; \
}
#define PANIC true
#define DONT_PANIC false
#define MAX_READERS 16
int main(void)
{
LONG rv;
SCARDCONTEXT hContext;
LPTSTR mszReaders;
DWORD dwReaders = 0;
char *ptr, *readers[MAX_READERS] = {};
int nb_readers;
SCARD_READERSTATE rgReaderStates[MAX_READERS];
rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
CHECK("SCardEstablishContext", rv, PANIC)
rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);
CHECK("SCardListReaders", rv, DONT_PANIC)
mszReaders = calloc(dwReaders, sizeof(char));
rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
CHECK("SCardListReaders", rv, DONT_PANIC)
printf("Found readers:\n");
nb_readers = 0;
for (ptr=mszReaders; *ptr; ptr += strlen(ptr) +1)
{
printf(" %s\n", ptr);
readers[nb_readers++] = ptr;
}
printf("Found %d readers\n", nb_readers);
/* add the special reader */
readers[nb_readers++] = "\\\\?PnP?\\Notification";
/* get the initial states */
for (int i=0; i<nb_readers; i++)
{
rgReaderStates[i].szReader = readers[i];
rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE;
}
rv = SCardGetStatusChange(hContext, 0, rgReaderStates, nb_readers);
CHECK("SCardGetStatusChange", rv, DONT_PANIC)
/* set the current state */
for (int i=0; i<nb_readers; i++)
{
rgReaderStates[i].dwCurrentState = rgReaderStates[i].dwEventState;
printf("reader: %s, events #: %d\n",
readers[i], rgReaderStates[i].dwEventState >> 16);
printf("reader: %s, events state 0x%04X\n",
readers[i], rgReaderStates[i].dwEventState & 0xFFFF);
}
/* wait for a change */
rv = SCardGetStatusChange(hContext, INFINITE, rgReaderStates, nb_readers);
CHECK("SCardGetStatusChange", rv, PANIC)
/* new state */
for (int i=0; i<nb_readers; i++)
{
printf("reader: %s, events #: %d\n",
readers[i], rgReaderStates[i].dwEventState >> 16);
printf("reader: %s, events state 0x%04X\n",
readers[i], rgReaderStates[i].dwEventState & 0xFFFF);
}
free(mszReaders);
rv = SCardReleaseContext(hContext);
CHECK("SCardReleaseContext", rv, PANIC)
return 0;
}
Connect a reader
We start the sample code with no reader connected:
SCardEstablishContext(): 0x00000000, Command successful.
SCardListReaders(): 0x8010002E, Cannot find a smart card reader.
SCardListReaders(): 0x8010002E, Cannot find a smart card reader.
Found readers:
Found 0 readers
SCardGetStatusChange(): 0x8010000A, Command timeout.
reader: \\?PnP?\Notification, events #: 33
reader: \\?PnP?\Notification, events state 0x0000
>>> connection of a new reader here
SCardGetStatusChange(): 0x00000000, Command successful.
reader: \\?PnP?\Notification, events #: 34
reader: \\?PnP?\Notification, events state 0x0002
SCardReleaseContext(): 0x00000000, Command successful.
State value 0x0002 is SCARD_STATE_CHANGED
.
The first SCardGetStatusChange()
returns a reader events of 33.
After I connect a reader the number goes to 34.
Disconnect a reader
We restart the sample code with the reader connected:
SCardEstablishContext(): 0x00000000, Command successful.
SCardListReaders(): 0x00000000, Command successful.
SCardListReaders(): 0x00000000, Command successful.
Found readers:
Gemalto PC Twin Reader 00 00
Found 1 readers
SCardGetStatusChange(): 0x00000000, Command successful.
reader: Gemalto PC Twin Reader 00 00, events #: 0
reader: Gemalto PC Twin Reader 00 00, events state 0x0012
reader: \\?PnP?\Notification, events #: 34
reader: \\?PnP?\Notification, events state 0x0000
>>> removal of the reader here
SCardGetStatusChange(): 0x00000000, Command successful.
reader: Gemalto PC Twin Reader 00 00, events #: 0
reader: Gemalto PC Twin Reader 00 00, events state 0x000E
reader: \\?PnP?\Notification, events #: 35
reader: \\?PnP?\Notification, events state 0x0002
SCardReleaseContext(): 0x00000000, Command successful.
The reader "Gemalto PC Twin Reader 00 00" has been removed.
Its state value 0x000E contains the bits:
SCARD_STATE_UNKNOWN
SCARD_STATE_UNAVAILABLE
SCARD_STATE_CHANGED
Connect a second reader
We restart the sample code with the reader connected:
SCardEstablishContext(): 0x00000000, Command successful.
SCardListReaders(): 0x00000000, Command successful.
SCardListReaders(): 0x00000000, Command successful.
Found readers:
Gemalto PC Twin Reader 00 00
Found 1 readers
SCardGetStatusChange(): 0x00000000, Command successful.
reader: Gemalto PC Twin Reader 00 00, events #: 0
reader: Gemalto PC Twin Reader 00 00, events state 0x0012
reader: \\?PnP?\Notification, events #: 36
reader: \\?PnP?\Notification, events state 0x0000
>>> connection of a second reader
SCardGetStatusChange(): 0x00000000, Command successful.
reader: Gemalto PC Twin Reader 00 00, events #: 0
reader: Gemalto PC Twin Reader 00 00, events state 0x0010
reader: \\?PnP?\Notification, events #: 37
reader: \\?PnP?\Notification, events state 0x0002
SCardReleaseContext(): 0x00000000, Command successful.
The Gemalto reader event state is 0x0010 = SCARD_STATE_EMPTY
because
it does not contains a smart card. It does not have the bit
SCARD_STATE_CHANGED
set because it's state has not changed.
The PnP reader state is 0x0002 = SCARD_STATE_CHANGED
because a new
reader was connected.