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
..
No comments:
Post a Comment