Building a loop to monitor smart cards on windows turns out to be tricky. I have written a function to do this and allow code to be inserted in the necessary places.


template<
typename SetContext,
typename ClearContext,
typename Wait,
typename Report
>
unique_winerror monitor_smartcard_readers(
SetContext && setContext,
ClearContext && clearContext,
Wait && wait,
Report && report
);

By itself the data produced by this function isn't too interesting, but I have a project in mind that I hope will use it to advantage.

To use monitor_smartcard_readers you call the function passing in lambdas for the code to insert.

  • setContext when the function establishes a context it calls this lambda to allow the caller to store the context and use it later to call SCardCancel
  • clearContext when the function closes the context it calls this function to inform the caller that it is no longer valid.
  • wait when the function needs to wait for the service to become available or check to see if it should exit it calls this lambda. this lambda must return a bool, true for continue and false for exit.
  • report when the function has an update to the status it calls this lambda with a range of reader states.

A quick example should show how this all stitches together.


void monitor()
{

First need to get the win32 event handle that is set when the smart card service is running.


HANDLE waitfor[1] = {SCardAccessStartedEvent()};
ON_UNWIND_AUTO([] {SCardReleaseStartedEvent();});

unique_winerror winerror;
SCARDCONTEXT context = NULL;

while (!winerror) {
winerror = monitor_smartcard_readers(

when setContext is called, store the context in the local stack variable.


[&](SCARDCONTEXT context) {
context = context;
},

when clearContext is called, set the local stack variable to NULL


[&]() {
context = NULL;
},

when wait is called, wait for the smart card service to start. If additional threads were in play this might include other events to signal that monitor_smartcard_readers should exit.


[&]() -> bool {
if (WAIT_OBJECT_0 != WaitForMultipleObjects(
lib::rng::size(waitfor),
waitfor,
FALSE,
INFINITE
)
) {
// monitor_smardcard_readers will
// return SCARD_E_CANCELLED
return false;
}
return true;
},

when report is called, print out the state changes.


[&](
lib::rng::range<SCARD_READERSTATE*> readersrange
) {
std::wcout << L"---status update---" << std::endl;
for (auto & state : readersrange) {
auto stateChanges = (
state.dwCurrentState ^ state.dwEventState
) & std::numeric_limits<unsigned short>::max();

std::wcout << L"reader: " << state.szReader
<< L" changes: " <<
std::hex << std::showbase << stateChanges
<< L" state: "
<< ((state.dwEventState == SCARD_STATE_UNAWARE) ?
L" SCARD_STATE_UNAWARE" : L"")
<< ((state.dwEventState & SCARD_STATE_PRESENT) ?
L" SCARD_STATE_PRESENT" : L"")
<< ((state.dwEventState & SCARD_STATE_ATRMATCH) ?
L" SCARD_STATE_ATRMATCH" : L"")
<< ((state.dwEventState & SCARD_STATE_CHANGED) ?
L" SCARD_STATE_CHANGED" : L"")
<< ((state.dwEventState & SCARD_STATE_EMPTY) ?
L" SCARD_STATE_EMPTY" : L"")
<< ((state.dwEventState & SCARD_STATE_EXCLUSIVE) ?
L" SCARD_STATE_EXCLUSIVE" : L"")
<< ((state.dwEventState & SCARD_STATE_IGNORE) ?
L" SCARD_STATE_IGNORE" : L"")
<< ((state.dwEventState & SCARD_STATE_INUSE) ?
L" SCARD_STATE_INUSE" : L"")
<< ((state.dwEventState & SCARD_STATE_MUTE) ?
L" SCARD_STATE_MUTE" : L"")
<< ((state.dwEventState & SCARD_STATE_UNAVAILABLE) ?
L" SCARD_STATE_UNAVAILABLE" : L"")
<< ((state.dwEventState & SCARD_STATE_UNKNOWN) ?
L" SCARD_STATE_UNKNOWN" : L"")
<< ((state.dwEventState & SCARD_STATE_UNPOWERED) ?
L" SCARD_STATE_UNPOWERED" : L"")
<< std::endl;
}
std::wcout << L"--status update end--" << std::endl;
}
);
}
}

Next post will explore the implementation of monitor_smartcard_readers..