스마트 카드 서비스는 Windows 8에서 다르게 작동하며 MSDN은 설명서를 업데이트하지 않았습니다. Windows 8에서 스마트 카드 작업을 모니터링하기 위해 SCardGetStatusChange를 올바르게 호출하는 방법에 대한 코드 스 니펫을 제공 할 수 있습니까? 미리 감사드립니다!Windows 8에서 SCardGetStatusChange를 올바르게 사용하는 방법은 무엇입니까?
2
A
답변
2
다음은 개인 블로그 프로젝트 용으로 작성한 C++ 템플릿 함수입니다. github에서 개발중인 라이브러리를 사용하지만 로직을 자신의 상황에 맞게 다시 작성할 수도 있습니다.
template<typename SetContext, typename ClearContext, typename Wait, typename Report>
unique_winerror monitor_smartcard_readers(
SetContext&& setContext,
ClearContext&& clearContext,
Wait&& wait,
Report&& report
)
{
unique_winerror winerror;
std::vector<wchar_t> readernames;
std::vector<SCARD_READERSTATE> readers;
while (winerror)
{
//
// make sure that the scard service has started
// and that the loop has not been cancelled
//
if (!std::forward<Wait>(wait)())
{
return winerror_cast(SCARD_E_CANCELLED);
}
monitor_error_contract(
[&]()
{
unique_close_scardcontext context;
ON_UNWIND_AUTO(
[&]
{
std::forward<ClearContext>(clearContext)();
}
);
//
// need a fresh context whenever we start over.
// lots of sytem changes could have caused this
// restart including the scard service stopping
// and then restarting.
//
winerror.reset(
SCardEstablishContext(
SCARD_SCOPE_USER,
NULL,
NULL,
context.replace()
)
);
if (!winerror || !context)
{
return;
}
std::forward<SetContext>(setContext)(context.get());
//
// make sure that loop has not been cancelled.
// without this there is a race where the new
// context is not cancelled because the caller
// cancelled at a time when there was no
// context yet.
//
if (!std::forward<Wait>(wait)())
{
winerror = winerror_cast(SCARD_E_CANCELLED);
return;
}
if (readers.empty())
{
//
// add PnP state query
// setting the state to unaware causes SCardGetStatusChange
// to return immediately with the actual pnp state.
//
readers.push_back(make(L"\\\\?PnP?\\Notification"));
}
for(;;)
{
auto readersstaterange = lib::rng::make_range_raw(readers);
winerror.reset(
SCardGetStatusChange(
context.get(),
INFINITE,
readersstaterange.begin(),
lib::rng::size_cast<DWORD>(readersstaterange.size())
)
);
if (!winerror)
{
// exit
return;
}
//
// report changes
//
auto readersrange = lib::rng::make_range_raw(readers, 0, -1);
if (!readersrange.empty())
{
std::forward<Report>(report)(readersrange);
}
//
// record the changes we have reported
//
for (auto& state : readers)
{
state.dwCurrentState = state.dwEventState;
}
if ((readers.back().dwEventState & SCARD_STATE_CHANGED) == SCARD_STATE_CHANGED)
{
// Pnp event - list readers.
break;
}
}
// keep the old allocations for use to build the new list.
std::vector<wchar_t> oldreadernames(std::move(readernames));
std::vector<SCARD_READERSTATE> oldreaders(std::move(readers));
// exclude the pnp reader
auto oldreaderssortedrange = lib::rng::make_range(oldreaders, 0, -1);
LPWSTR concatreaderstrings = nullptr;
ON_UNWIND_AUTO(
[&] { if (concatreaderstrings) {SCardFreeMemory(context.get(), concatreaderstrings);};}
);
DWORD totallength = SCARD_AUTOALLOCATE;
winerror.reset(
SCardListReaders(
context.get(),
nullptr,
reinterpret_cast<LPWSTR>(&concatreaderstrings),
&totallength
)
);
if (winerror == winerror_cast(SCARD_E_NO_READERS_AVAILABLE))
{
// no readers is not an error, loop around to wait
// for a reader to be connected
winerror.suppress().release();
return;
}
else if (!winerror)
{
return;
}
// keep the names around because the state array will have pointers into this
readernames.assign(concatreaderstrings, concatreaderstrings + totallength);
auto readerstateless = [](const SCARD_READERSTATE& lhs, const SCARD_READERSTATE& rhs) -> bool
{
return _wcsicmp(lhs.szReader, rhs.szReader) < 0;
};
//
// all the reader names are concatenated in this array with
// embedded nulls for each and two nulls to mark the end
//
auto cursorreadernames = lib::rng::make_range_raw(readernames);
while(!cursorreadernames.empty() && cursorreadernames.front() != L'\0')
{
// access the current name
auto namerange = lib::rng::make_range(
cursorreadernames,
0,
wcslen(cursorreadernames.begin()) - cursorreadernames.size()
);
// skip to the next name
cursorreadernames = lib::rng::make_range(namerange, namerange.size() + 1, 0);
auto oldreader = std::equal_range(
oldreaderssortedrange.begin(),
oldreaderssortedrange.end(),
make(namerange.begin()),
readerstateless
);
if (oldreader.first != oldreader.second)
{
// keep the old state for this reader
readers.push_back(*oldreader.first);
// must use the new string allocation,
// the old one will be gone soon
readers.back().szReader = namerange.begin();
}
else
{
readers.push_back(make(namerange.begin()));
}
}
// keeping them sorted makes the updates more stable and allows the
// equal_range above instead of a linear find.
std::sort(readers.begin(), readers.end(), readerstateless);
//
// add PnP state query
// keep the existing state, and keep it at the
// end, out of the sorted area.
//
readers.push_back(oldreaders.back());
}
);
}
return winerror;
}
사용법은 다음과 같습니다
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#define NOMINMAX
// Windows Header Files:
#include <windows.h>
#include <Unknwn.h>
#include <winscard.h>
#include <ncrypt.h>
#include <Wincrypt.h>
#include <credentialprovider.h>
// TODO: reference additional headers your program requires here
#include <type_traits>
#include <algorithm>
#include <new>
#include <memory>
#include <utility>
#include <limits>
#include <iterator>
#include <thread>
#include <future>
#include <mutex>
#include <vector>
#include <iostream>
#include <iomanip>
int wmain(int argc, WCHAR* argv[])
{
unique_winerror winerror;
for (;;)
{
SCARDCONTEXT context = NULL;
// if you monitor in a separate thread, then add a cancel or shutdown event
// into the waitfor array and handle it in the Wait lambda
HANDLE waitfor[] = {SCardAccessStartedEvent()};
ON_UNWIND_AUTO([] {SCardReleaseStartedEvent();});
winerror = smart_card::monitor_smartcard_readers(
[&](SCARDCONTEXT context)
{
context = context;
},
[&]()
{
context = NULL;
},
[&]() -> 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;
},
[&](lib::rng::range<SCARD_READERSTATE*> readersrange)
{
for (auto& state : readersrange)
{
auto stateChanges = (state.dwCurrentState^state.dwEventState) & std::numeric_limits<unsigned short>::max();
std::wcout
<< L"nothread - "
<< state.szReader
<< L" changes: " << std::hex << std::showbase << stateChanges
<< L"["
;
printSCardState(std::wcout, stateChanges)
<< L"] state: " << std::hex << std::showbase << state.dwEventState
<< L"["
;
printSCardState(std::wcout, state.dwEventState)
<< L"]"
<< std::endl
;
if (state.dwCurrentState != SCARD_STATE_UNAWARE &&
((state.dwEventState & SCARD_STATE_PRESENT) != SCARD_STATE_PRESENT ||
stateChanges == SCARD_STATE_INUSE ||
stateChanges == SCARD_STATE_UNPOWERED ||
(state.dwEventState & (SCARD_STATE_UNPOWERED | SCARD_STATE_EMPTY | SCARD_STATE_IGNORE | SCARD_STATE_UNKNOWN | SCARD_STATE_UNAVAILABLE | SCARD_STATE_MUTE)) ||
state.cbAtr == 0))
{
// we have seen this reader before and one of:
// no card
// only flipped INUSE
// only flipped UNPOWERED
// UNPOWERED EMPTY UNKNOWN UNAVAILABLE MUTE
// no atr
//
// don't try to read the card
continue;
}
// read the card in the reader and list the certs on the card
}
}
);
winerror.suppress();
}
return 0;
}
2
내가 늦게 이년 이상 해요 알고,하지만 어쩌면 내 대답은 그럼에도 불구하고 다른 사람을 도울 수 있습니다.
추가 개발을위한 출발점으로 간단한 코드가 있습니다. 나는 Windows 7에서 처음 만들었습니다. AFAICS 그것은 윈도우 8에서도 잘 작동합니다. 이것은 하나의 독자만을 사용하지만, 이전의 반복은 독자의 목록을 사용했고 그것은 잘 작동했습니다. 관련 부분은 다음과 같습니다. 독자 상태 구조의
초기화 :
memset(&m_State, 0, sizeof(m_State));
m_State.szReader = _wcsdup(m_ReaderName.c_str());
m_State.dwCurrentState = SCARD_STATE_UNAWARE;
이벤트에 대한 대기 : 지금까지 내가 문서를 이해
bool TSmartCardReader::WaitForEvent(DWORD Timeout, TCardEvent &CardEvent)
{
CardEvent = None;
// Reset reader structure, except the specific fields we need
// (because that's what the docs say: "Important: Each member of each structure
// in this array must be initialized to zero and then set to specific values as
// necessary. If this is not done, the function will fail in situations that
// involve remote card readers.")
const wchar_t *szReader = m_State.szReader;
DWORD dwCurrentState = m_State.dwCurrentState;
memset(&m_State, 0, sizeof(m_State));
m_State.szReader = szReader;
m_State.dwCurrentState = dwCurrentState;
LONG rv = SCardGetStatusChangeW(m_hContext, Timeout, &m_State, 1);
if (rv == SCARD_S_SUCCESS)
{
HandleStatusChange(CardEvent);
// I'm not sure we really need to reset the SCARD_STATE_CHANGED bit
m_State.dwCurrentState = m_State.dwEventState & ~SCARD_STATE_CHANGED;
}
else if (rv == SCARD_E_TIMEOUT)
return false; // No status changes
else if (rv == SCARD_E_NO_READERS_AVAILABLE)
throw ESCNoReaders("No readers available");
else
throw ESCWaitForEvent(GetErrorText(rv));
return CardEvent != None;
}
는 키 것은 당신이 당신이 믿는 것에 dwCurrentState을 설정한다는 것입니다 독자의 현재 상태입니다. SCardGetStatusChange()는 현재 상태를 고려하여 상태 변경을 구성하는 요소를 결정합니다.
관련 문제
- 1. Windows 8에서 화면 해상도를 설정하는 방법은 무엇입니까?
- 2. Windows 8에서 데이터 그리드를 표시하는 방법은 무엇입니까?
- 3. Windows 8에서 시작 메뉴를 활성화하는 방법은 무엇입니까?
- 4. Windows 8에서 연락처에 액세스하여 수정하는 방법은 무엇입니까?
- 5. Windows 8에서 로밍 파일을 저장하는 방법은 무엇입니까?
- 6. Properties.Settings를 올바르게 사용하는 방법은 무엇입니까?
- 7. WebLogic 8에서 스레드 풀을 사용하는 방법은 무엇입니까?
- 8. Windows 8에서 미디어 스트리밍
- 9. Windows 8에서 XmlWriterTraceListener가 누락되었습니다.
- 10. Windows 8에서 GridView 필터링
- 11. UTF-8에서 Windows-1252로 인코딩을 변환하는 방법은 무엇입니까?
- 12. CCSpriteBatchNode를 올바르게 사용하는 방법은 무엇입니까?
- 13. WSAAsyncSelect를 올바르게 사용하는 방법은 무엇입니까?
- 14. parseJSON을 올바르게 사용하는 방법은 무엇입니까?
- 15. radioGroup을 올바르게 사용하는 방법은 무엇입니까?
- 16. dispatch_sync를 올바르게 사용하는 방법은 무엇입니까?
- 17. pjax를 올바르게 사용하는 방법은 무엇입니까?
- 18. STDERR_FILENO를 올바르게 사용하는 방법은 무엇입니까?
- 19. memcpy를 올바르게 사용하는 방법은 무엇입니까?
- 20. VAO를 올바르게 사용하는 방법은 무엇입니까?
- 21. opCall을 올바르게 사용하는 방법은 무엇입니까?
- 22. 블록을 올바르게 사용하는 방법은 무엇입니까?
- 23. Windows 8 : Windows 8에서 외부 이미지를 사용하는 방법 Metro app
- 24. Windows 8에서 Windows 폰 개발
- 25. Windows 8에서 테이블 스토리지 서비스를 사용하는 방법 Javascript를 사용하는 앱
- 26. Windows 8에서 Spy ++ 사용
- 27. Windows 8에서 OnFileActivated 디버깅
- 28. Windows 8에서 WININET.InternetConnect가 실패합니다.
- 29. Windows 8에서 UMTS를 사용하도록합니다.
- 30. Windows 8에서 javascript를로드하는 방법