Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Ten artykuł zawiera rozwiązanie błędu występującego podczas wstawiania karty inteligentnej do czytnika.
Oryginalny numer KB: 976832
Symptomy
Po wstawieniu karty inteligentnej do czytnika kart inteligentnych system Windows próbuje pobrać i zainstalować minidrivery kart inteligentnych dla karty za pośrednictwem usług Plug and Play. Jeśli sterownik karty inteligentnej nie jest dostępny w żadnej ze wstępnie skonfigurowanych lokalizacji, takich jak Windows Update, WSUS lub ścieżki intranetowe, a niestandardowy dostawca usług kryptograficznych nie jest jeszcze zainstalowany w systemie, w obszarze powiadomień zostanie wyświetlony następujący komunikat o błędzie:
Oprogramowanie sterownika urządzenia nie zostało pomyślnie zainstalowane
Kliknij tutaj, aby uzyskać szczegółowe informacje.
Ten komunikat o błędzie zniknie po kilku sekundach.
Ponadto w Menedżer urządzeń w obszarze Inne urządzenia urządzenie karty inteligentnej ma stan DNF (nie znaleziono sterownika).
Często wymaga to od użytkownika uzyskania jednego z następujących elementów od wystawcy karty inteligentnej w celu rozwiązania tego błędu:
- Zarejestrowany minidriver karty inteligentnej w systemie Windows.
- Niestandardowy dostawca usług kryptograficznych (CSP) dla karty inteligentnej.
- Minidriver karty inteligentnej z systemem Windows bez logo.
- Inne oprogramowanie pośredniczące, takie jak kontrolka ActiveX, oprogramowanie PKCS#11 lub inne oprogramowanie niestandardowe.
Jeśli jednak użytkownik jest dostarczany tylko z elementem 3 lub 4 z tej listy, karta inteligentna będzie nadal działać w systemie. Jednak użytkownik otrzyma komunikat o błędzie wymieniony w tej sekcji za każdym razem, gdy wstawi kartę inteligentną.
Ten problem dotyczy wszystkich wersji systemu Windows 7, Windows Server 2008 R2 i nowszych wersji obu systemów operacyjnych.
Przyczyna
Wszystkie karty inteligentne wymagają dodatkowego oprogramowania do pracy w systemie Windows, chyba że istnieje sterownik skrzynki odbiorczej, który umożliwia użytkownikowi korzystanie z karty bez instalowania dodatkowego oprogramowania. Ulepszono strukturę kart inteligentnych systemu Windows w systemie Windows 7, aby umożliwić automatyczne pobieranie minidriverów kart inteligentnych z usługi Windows Update lub z innych podobnych lokalizacji, takich jak serwer WSUS, gdy karta inteligentna zostanie wstawiona do czytnika. Wszystkie karty inteligentne, które pomyślnie spełniają wymagania dotyczące logo, opublikowane przez program logo systemu Windows, korzystają z tej funkcji.
Jeśli jednak oprogramowanie wymagane do korzystania z karty inteligentnej w systemie Windows nie jest logo lub jest typem, który różni się od minidrivera, takiego jak sterownik PKCS#11, niestandardowy dostawca CSP, oprogramowanie pośredniczące lub kontrolka ActiveX, opcja automatycznego pobierania kończy się niepowodzeniem, ponieważ firma Microsoft potwierdza tylko minidrivery kart inteligentnych. W związku z tym, jeśli użytkownik wstawia kartę, dla której niestandardowy dostawca CSP nie jest jeszcze zarejestrowany, użytkownik otrzymuje komunikat o błędzie informujący, że brakuje oprogramowania sterownika dla urządzenia karty inteligentnej, mimo że użytkownik może używać karty inteligentnej za pośrednictwem dodatkowego oprogramowania zainstalowanego na komputerze użytkownika z instalacji niestandardowej.
Rozwiązanie
Mimo że karty inteligentne nadal działają pomimo komunikatu o błędzie widocznego przez użytkownika, wystawca karty inteligentnej, dostawca lub producent mogą użyć jednej z następujących metod w celu rozwiązania tego błędu.
Implementowanie minidrivera karty inteligentnej
Zalecamy, aby wystawcy kart, dostawcy i producenci wdrażali minidrivery kart inteligentnych i uczestniczyli w programie logo systemu Windows, aby skorzystać z ulepszeń wprowadzonych na platformie, takiej jak Plug and Play karty inteligentnej, etap urządzenia dla kart inteligentnych itd.
Implementowanie sterownika o wartości NULL dla karty inteligentnej
Jeśli oprogramowanie niestandardowe, takie jak sterownik PKCS#11, kontrolka ActiveX lub inne oprogramowanie pośredniczące jest wymagane do włączenia korzystania z karty inteligentnej w systemie Windows, a implementacja minidrivera karty inteligentnej lub niestandardowego dostawcy CSP nie jest praktyczną opcją, zalecamy, aby wystawcy kart, dostawcy lub producenci rozważyli przesłanie sterowników NULL do usługi Windows Update. Typowy proces zapewniania dostępności sterownika NULL w usłudze Windows Update wymaga pomyślnego przesłania niesklasyfikowanego urządzenia za pośrednictwem platformy Winqual. Jeśli w przyszłości jest dostępny minidriver dla tych kart, nowy sterownik można przekazać do usługi Windows Update, uczestnicząc w programie logo systemu Windows. Sterowniki null można następnie ręcznie pobrać przez użytkowników końcowych lub udostępnić za pomocą opcjonalnych aktualizacji.
Poniżej przedstawiono przykładowy szablon sterownika o wartości NULL dla karty inteligentnej.
;
; Null Driver for Fabrikam Smartcard installation x86 and x64 package.
;
[Version]
Signature="$Windows NT$"
Class=SmartCard
ClassGuid={990A2BD7-E738-46c7-B26F-1CF8FB9F1391}
Provider=%ProviderName%
CatalogFile=delta.cat
DriverVer=4/21/2006,1.0.0.0
[Manufacturer]
%ProviderName%=Minidriver,NTamd64,NTamd64.6.1,NTx86,NTx86.6.1
[Minidriver.NTamd64]
;This driver has no applicability on OS versions earlier than Windows 7
[Minidriver.NTx86]
;This driver has no applicability on OS versions earlier than Windows 7
[Minidriver.NTamd64.6.1]
%CardDeviceName%=Minidriver64_Install,<DEVICE_ID>
;%CardDeviceName%=Minidriver64_Install,<DEVICE_ID2>
;%CardDeviceName%=Minidriver64_Install,<DEVICE_ID3>
;...
[Minidriver.NTx86.6.1]
%CardDeviceName%=Minidriver32_Install,<DEVICE_ID>
;%CardDeviceName%=Minidriver32_Install,<DEVICE_ID2>
;%CardDeviceName%=Minidriver32_Install,<DEVICE_ID3>
;...
;Leave the following sections blank
[DefaultInstall]
[DefaultInstall.ntamd64]
[DefaultInstall.NTx86]
[DefaultInstall.ntamd64.6.1]
[DefaultInstall.NTx86.6.1]
[Minidriver64_Install.NT]
[Minidriver64_61_Install.NT]
[Minidriver32_Install.NT]
[Minidriver32_61_Install.NT]
[Minidriver64_61_Install.NT.Services]
AddService = ,2
[Minidriver32_61_Install.NT.Services]
AddService = ,2
; =================== Generic ==================================
[Strings]
ProviderName ="Microsoft"
CardDeviceName="Fabrikam Generic Smart card"
Aby wygenerować identyfikator urządzenia sprzętowego, do którego odwołuje się ciąg DEVICE_ID w przykładzie, postępuj zgodnie ze specyfikacją minidrivera karty inteligentnej.
Aby uzyskać szczegółowe informacje na temat przesyłania sterownika o wartości NULL do firmy Microsoft, skontaktuj się z pomocą techniczną firmy Microsoft.
Wyłączanie funkcji Plug and Play karty inteligentnej za pomocą zasad grupy dla zarządzanych komputerów
Ta opcja jest zalecana tylko w przypadku wdrożeń w przedsiębiorstwie, w których komputery są zarządzane przez administratorów i wszystkie niezbędne oprogramowanie do pracy z kartami inteligentnymi używanymi w przedsiębiorstwie jest instalowane przy użyciu narzędzi do zarządzania oprogramowaniem, takich jak sms.
Ta procedura jest odradzana w następujących środowiskach, ponieważ będzie ona mieć wpływ na wszystkie karty inteligentne w środowisku:
- Wdrożenia komercyjne, które są przeznaczone dla użytkowników końcowych, takich jak bankowość online.
- Środowiska, które obejmują zarówno karty inteligentne Plug and Play, jak i karty inteligentne, które używają zasad grupy do wyłączania Plug and Play dla kart inteligentnych.
Wtyczka i odtwarzanie kart inteligentnych mogą być wyłączone w przedsiębiorstwach, w których komputer użytkownika końcowego jest zarządzany przez mechanizmy, takie jak zasady grupy.
Jeśli wdrożenie korzysta tylko z rozwiązań kart inteligentnych innych niż Plug and Play, wtyczka i odtwarzanie kart inteligentnych mogą być wyłączone przez administratora lokalnego na komputerze klienckim. Wyłączenie funkcji Plug and Play karty inteligentnej uniemożliwia pobieranie sterowników kart inteligentnych, nazywanych również minidriverami kart inteligentnych. Zapobiega również monitom o wtyczkę i odtwarzanie karty inteligentnej.
Aby wyłączyć wtyczkę i odtwarzanie karty inteligentnej w lokalnych zasadach grupy, wykonaj następujące kroki:
Kliknij przycisk Start, wpisz gpedit.msc w polu Wyszukaj programy i pliki , a następnie naciśnij ENTER.
W drzewie konsoli w obszarze Konfiguracja komputera kliknij pozycję Szablony administracyjne.
W okienku szczegółów kliknij dwukrotnie pozycję Składniki systemu Windows, a następnie kliknij dwukrotnie kartę inteligentną.
Kliknij prawym przyciskiem myszy pozycję Włącz usługę Plug and Play karty inteligentnej, a następnie kliknij polecenie Edytuj.
Kliknij pozycję Wyłączone, a następnie kliknij przycisk OK.
Zmienianie systemu użytkownika końcowego i wyłączanie funkcji Plug and Play karty inteligentnej dla określonych kart
Jest to najmniej zalecana opcja. Tej opcji należy używać tylko wtedy, gdy karty są starszymi kartami i nie ma planów wdrożenia minidriverów kart inteligentnych w przyszłości. Ta opcja wymaga, aby istniejące oprogramowanie, które jest już zainstalowane w systemie, powiadamia system Windows o tym, że w systemie jest zainstalowany niestandardowy dostawca CSP, mimo że taki dostawca CSP nie istnieje w systemie użytkownika końcowego. Gdy tylko system Windows ustali, że w systemie jest już zainstalowany niestandardowy dostawca CSP, system Windows nie próbuje pobrać i zainstalować sterownika za pomocą funkcji Plug and Play karty inteligentnej. Nie utworzono węzła urządzenia karty inteligentnej, który jest widoczny w Menedżer urządzeń. Ta opcja powoduje następujące zmiany w rejestrze systemowym:
Podklucz: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\<Smart card name>
Wpisy rejestru podklucza:
ATR=szesnastkowy DWORD: rozdzielany przecinkami ATR karty inteligentnej.
ATRMask = szesnastkowy DWORD: Maska rozdzielana przecinkami, aby zamaskować nieistotne bajty w ATR.
Crypto Provider=String value: Jakiś ciąg jest odpowiedni dla karty inteligentnej.
Na przykład:
Podklucz: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\Fabrikam ATM card
Wpisy rejestru podklucza:
- ATR=Hexadecimal DWORD: 3b,dc,13,00,40,3a,49,54,47,5f,4d,53,43,53,50,5f,56,32
- ATRMask = Hexadecimal DWORD: ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff
- Dostawca kryptograficzny=wartość ciągu: Dostawca fikcyjnego dostawcy Fabrikam ATM
W przypadku systemów x64-bitowych należy wprowadzić identyczne zmiany w następującym podkluczu: HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Cryptography\Calais\SmartCards
Zalecamy, aby zamiast bezpośrednio zmieniać rejestr systemowy, należy użyć interfejsów API winSCard, aby wprowadzić te zmiany w systemie. Oto przykładowy przykładowy kod, który wykrywa wstawienie karty inteligentnej, a następnie wyłącza wtyczkę i odtwarzanie karty inteligentnej dla określonej karty, tworząc wpis rejestru, który kojarzy kartę z nieistniejącą dostawcą.
Firma Microsoft podaje przykłady programowania tylko dla celów ilustracyjnych, nie udzielając żadnej rękojmi, wyrażonej wprost ani dorozumianej, w tym także, ale nie tylko, dorozumianej rękojmi co do przydatności handlowej lub do określonych celów. W tym artykule zakłada się, że czytelnik zna demonstrowany język programowania oraz narzędzia używane do tworzenia i debugowania procedur. Wykwalifikowani pracownicy Pomocy technicznej firmy Microsoft mogą pomóc w wyjaśnieniu działania określonej procedury. Nie będą oni jednak modyfikować tych przykładów w celu dodania funkcji ani konstruować nowych procedur celem dostosowania ich do potrzeb użytkownika.
//==============================================================;
//
// Disable Smart card Plug and Play for specific cards
//
// Abstract:
// This is an example of how to create a new
// Smart Card Database entry when a smart card is inserted
// into the computer.
//
// This source code is only intended as a supplement to existing Microsoft
// documentation.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED. THIS INCLUDES BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (C) Microsoft Corporation. All Rights Reserved.
//==============================================================;
// This code must be compiled with UNICODE support to work correctly
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <winscard.h>
#include <stdio.h>
#include <strsafe.h>
#include <rpc.h>
// Change this prefix to specify what the beginning of the
// introduced card name in the registry will be. This is
// be prepended to a GUID value.
#define CARD_NAME_PREFIX L"MyCustomCard"
// This is the name that will be provided as the CSP for
// the card when introduced to the system. This is provided
// in order to disable Smart Card Plug and Play for this
// card.
#define CARD_CSP L"$DisableSCPnP$"
// This special reader name is used to be notified when
// a reader is added to or removed from the system through
// SCardGetStatusChange.
#define PNP_READER_NAME L"\\\\?PnP?\\Notification"
// Maximum ATR length plus alignment bytes. This value is
// used in the SCARD_READERSTATE structure
#define MAX_ATR_LEN 36
LONG GenerateCardName(
__deref_out LPWSTR *ppwszCardName)
{
LONG lReturn = NO_ERROR;
HRESULT hr = S_OK;
DWORD cchFinalString = 0;
WCHAR wszCardNamePrefix[] = CARD_NAME_PREFIX;
LPWSTR pwszFinalString = NULL;
UUID uuidCardGuid = {0};
RPC_WSTR pwszCardGuid = NULL;
RPC_STATUS rpcStatus = RPC_S_OK;
// Parameter check
if (NULL == ppwszCardName)
{
wprintf(L"Invalid parameter in GenerateCardName.\n");
return ERROR_INVALID_PARAMETER;
}
// Generate GUID
rpcStatus = UuidCreate(&uuidCardGuid);
if (RPC_S_OK != rpcStatus)
{
wprintf(L"Failed to create new GUID with error 0x%x.\n");
lReturn = (DWORD)rpcStatus;
}
else
{
// Convert GUID to string
rpcStatus = UuidToString(&uuidCardGuid, &pwszCardGuid);
if (RPC_S_OK != rpcStatus)
{
wprintf(L"Failed to convert new GUID to string with error 0x%x.\n", rpcStatus);
lReturn = (DWORD)rpcStatus;
}
else
{
// Allocate memory for final string
// Template is <prefix>-<guid>
cchFinalString = (DWORD)(wcslen(wszCardNamePrefix) + 1 + wcslen((LPWSTR)pwszCardGuid) + 1);
pwszFinalString = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, cchFinalString * sizeof(WCHAR));
if (NULL == pwszFinalString)
{
wprintf(L"Out of memory.\n");
lReturn = ERROR_OUTOFMEMORY;
}
else
{
// Create final string
hr = StringCchPrintf(
pwszFinalString,
cchFinalString,
L"%s-%s",
wszCardNamePrefix,
pwszCardGuid);
if (FAILED(hr))
{
wprintf(L"Failed to create card name with error 0x%x.\n", hr);
lReturn = (DWORD)hr;
}
else
{
// Set output params
*ppwszCardName = pwszFinalString;
pwszFinalString = NULL;
}
}
}
}
if (NULL != pwszCardGuid)
{
RpcStringFree(&pwszCardGuid);
}
if (NULL != pwszFinalString)
{
HeapFree(GetProcessHeap(), 0, pwszFinalString);
}
return lReturn;
}
LONG IntroduceCardATR(
__in SCARDCONTEXT hSC,
__in LPBYTE pbAtr,
__in DWORD cbAtr)
{
LONG lReturn = NO_ERROR;
LPWSTR pwszCardName = NULL;
// Parameter checks
if (NULL == hSC || NULL == pbAtr || 0 == cbAtr)
{
wprintf(L"Invalid parameter in IntroduceCardATR.\n");
return ERROR_INVALID_PARAMETER;
}
// Generate a name for the card
lReturn = GenerateCardName(&pwszCardName);
if (NO_ERROR != lReturn)
{
wprintf(L"Failed to generate card name with error 0x%x.\n", lReturn);
}
else
{
// Introduce the card to the system
lReturn = SCardIntroduceCardType(
hSC,
pwszCardName,
NULL,
NULL,
0,
pbAtr,
NULL,
cbAtr);
if (SCARD_S_SUCCESS != lReturn)
{
wprintf(L"Failed to introduce card '%s' to system with error 0x%x.\n", pwszCardName, lReturn);
}
else
{
// Set the provider name
lReturn = SCardSetCardTypeProviderName(
hSC,
pwszCardName,
SCARD_PROVIDER_CSP,
CARD_CSP);
if (SCARD_S_SUCCESS != lReturn)
{
wprintf(L"Failed to set CSP for card '%s' with error 0x%x.\n", pwszCardName, lReturn);
}
else
{
wprintf(L"Card '%s' has been successfully introduced to the system and has had Plug and Play disabled.\n", pwszCardName);
}
}
}
if (NULL != pwszCardName)
{
HeapFree(GetProcessHeap(), 0, pwszCardName);
}
return lReturn;
}
LONG ProcessCard(
__in SCARDCONTEXT hSC,
__in LPSCARD_READERSTATE pRdr)
{
LONG lReturn = NO_ERROR;
DWORD dwActiveProtocol = 0;
DWORD cbAtr = MAX_ATR_LEN;
DWORD dwIndex = 0;
DWORD cchCards = SCARD_AUTOALLOCATE;
LPWSTR pmszCards = NULL;
BYTE rgbAtr[MAX_ATR_LEN] = {0};
SCARDHANDLE hSCard = NULL;
// Parameter checks
if (NULL == hSC || NULL == pRdr)
{
wprintf(L"Invalid parameter in ProcessCard.\n");
return ERROR_INVALID_PARAMETER;
}
// Connect to the card in the provided reader in shared mode
lReturn = SCardConnect(
hSC,
pRdr->szReader,
SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
&hSCard,
&dwActiveProtocol);
if (SCARD_S_SUCCESS != lReturn)
{
wprintf(L"Failed to connect to card in reader '%s' with error 0x%x.\n", pRdr->szReader, lReturn);
}
else
{
wprintf(L"Connected to card in reader '%s'.\n", pRdr->szReader);
/*
* In this spot, put any necessary calls needed to identify that this
* is the type of card you are looking for. Usually this is done via
* SCardTransmit calls. For this example, we will grab the ATR of every
* inserted card.
*/
// Obtain the ATR of the inserted card
lReturn = SCardGetAttrib(
hSCard,
SCARD_ATTR_ATR_STRING,
rgbAtr,
&cbAtr);
if (SCARD_S_SUCCESS != lReturn)
{
wprintf(L"Failed to obtain ATR of card in reader '%s' with error 0x%x.\n", pRdr->szReader, lReturn);
}
else
{
// Output the ATR
wprintf(L"ATR of card in reader '%s':", pRdr->szReader);
for (dwIndex = 0; dwIndex < cbAtr; dwIndex++)
{
wprintf(L" %02x", rgbAtr[dwIndex]);
}
wprintf(L"\n");
// Determine if the ATR is already in the Smart Card Database
lReturn = SCardListCards(
hSC,
rgbAtr,
NULL,
0,
(LPWSTR)&pmszCards,
&cchCards);
if (SCARD_S_SUCCESS != lReturn)
{
wprintf(L"Failed to determine if card in reader '%s' is currently recognized by the system with error 0x%x. Skipping.\n", pRdr->szReader, lReturn);
}
else if (NULL == pmszCards || 0 == *pmszCards)
{
// Card not found. We need to add it.
wprintf(L"Card in reader '%s' is not currently recognized by the system. Adding ATR.\n", pRdr->szReader);
lReturn = IntroduceCardATR(
hSC,
rgbAtr,
cbAtr);
// If an error occurs here, we will continue so we can try the next time
// the card is inserted as well as examine other readers.
}
else
{
wprintf(L"Card in reader '%s' is already known by the system. Not adding ATR.\n", pRdr->szReader);
}
}
}
// Disconnect from the card. We do not need to reset it.
if (NULL != hSCard)
{
SCardDisconnect(hSCard, SCARD_LEAVE_CARD);
}
// Free resources
if (NULL != pmszCards)
{
SCardFreeMemory(hSC, pmszCards);
}
return lReturn;
}
LONG MonitorReaders(
__in SCARDCONTEXT hSC)
{
LPWSTR pwszReaders = NULL;
LPWSTR pwszOldReaders = NULL;
LPWSTR pwszRdr = NULL;
DWORD dwRet = ERROR_SUCCESS;
DWORD cchReaders = SCARD_AUTOALLOCATE;
DWORD dwRdrCount = 0;
DWORD dwOldRdrCount = 0;
DWORD dwIndex = 0;
LONG lReturn = NO_ERROR;
BOOL fDone = FALSE;
SCARD_READERSTATE rgscState[MAXIMUM_SMARTCARD_READERS+1] = {0};
SCARD_READERSTATE rgscOldState[MAXIMUM_SMARTCARD_READERS+1] = {0};
LPSCARD_READERSTATE pRdr = NULL;
// Parameter check
if (NULL == hSC)
{
wprintf(L"Invalid parameter in MonitorReaders.\n");
return ERROR_INVALID_PARAMETER;
}
// One of the entries for monitoring will be to detect new readers
// The first time through the loop will be to detect whether
// the system has any readers.
rgscState[0].szReader = PNP_READER_NAME;
rgscState[0].dwCurrentState = SCARD_STATE_UNAWARE;
dwRdrCount = 1;
while (!fDone)
{
while (!fDone)
{
// Wait for status changes to occur
wprintf(L"Monitoring for changes.\n");
lReturn = SCardGetStatusChange(
hSC,
INFINITE,
rgscState,
dwRdrCount);
switch (lReturn)
{
case SCARD_S_SUCCESS:
// Success
break;
case SCARD_E_CANCELLED:
// Monitoring is being cancelled
wprintf(L"Monitoring cancelled. Exiting.\n");
fDone = TRUE;
break;
default:
// Error occurred
wprintf(L"Error 0x%x occurred while monitoring reader states.\n", lReturn);
fDone = TRUE;
break;
}
if (!fDone)
{
// Examine the status change for each reader, skipping the PnP notification reader
for (dwIndex = 1; dwIndex < dwRdrCount; dwIndex++)
{
pRdr = &rgscState[dwIndex];
// Determine if a card is now present in the reader and
// it can be communicated with.
if ((pRdr->dwCurrentState & SCARD_STATE_EMPTY ||
SCARD_STATE_UNAWARE == pRdr->dwCurrentState) &&
pRdr->dwEventState & SCARD_STATE_PRESENT &&
!(pRdr->dwEventState & SCARD_STATE_MUTE))
{
// A card has been inserted and is available.
// Grab its ATR for addition to the database.
wprintf(L"A card has been inserted into reader '%s'. Grabbing its ATR.\n", pRdr->szReader);
lReturn = ProcessCard(hSC, pRdr);
// If an error occurs here, we will continue so we can try the next time
// the card is inserted as well as examine other readers.
}
// Save off the new state of the reader
pRdr->dwCurrentState = pRdr->dwEventState;
}
// Now see if the number of readers in the system has changed.
// Save its new state as the current state for the next loop.
pRdr = &rgscState[0];
pRdr->dwCurrentState = pRdr->dwEventState;
if (pRdr->dwEventState & SCARD_STATE_CHANGED)
{
wprintf(L"Reader change detected.\n");
break;
}
}
}
if (!fDone)
{
// Clean up previous loop
if (NULL != pwszOldReaders)
{
SCardFreeMemory(hSC, pwszOldReaders);
pwszOldReaders = NULL;
}
pwszReaders = NULL;
cchReaders = SCARD_AUTOALLOCATE;
// Save off PnP notification reader state and and list of readers previously found in the system
memcpy_s(&rgscOldState[0], sizeof(SCARD_READERSTATE), &rgscState[0], sizeof(SCARD_READERSTATE));
memset(rgscState, 0, sizeof(rgscState));
dwOldRdrCount = dwRdrCount;
pwszOldReaders = pwszReaders;
// Obtain a list of all readers in the system
wprintf(L"Building reader list.\n");
lReturn = SCardListReaders(
hSC,
NULL,
(LPWSTR)&pwszReaders,
&cchReaders);
switch (lReturn)
{
case SCARD_S_SUCCESS:
// Success
break;
case SCARD_E_NO_READERS_AVAILABLE:
// No readers in the system. This is OK.
lReturn = SCARD_S_SUCCESS;
break;
default:
// Error occurred
wprintf(L"Failed to obtain list of readers with error 0x%x.\n", lReturn);
fDone = TRUE;
break;
}
// Build the reader list for monitoring - NULL indicates end-of-list
// First entry is the PnP Notification entry.
pRdr = rgscState;
memcpy_s(&rgscState[0], sizeof(SCARD_READERSTATE), &rgscOldState[0], sizeof(SCARD_READERSTATE));
pRdr++;
pwszRdr = pwszReaders;
while ((NULL != pwszRdr) && (0 != *pwszRdr))
{
BOOL fFound = FALSE;
dwRdrCount++;
// Look for an existing reader state from a previous loop
for (dwIndex = 1; dwIndex < dwOldRdrCount; dwIndex++)
{
if ((lstrlen(pwszRdr) == lstrlen(rgscOldState[dwIndex].szReader)) &&
(0 == lstrcmpi(pwszRdr, rgscOldState[dwIndex].szReader)))
{
// Found a match. Copy it.
memcpy_s(pRdr, sizeof(SCARD_READERSTATE), &rgscOldState[dwIndex], sizeof(SCARD_READERSTATE));
fFound = TRUE;
break;
}
}
if (!fFound)
{
// New reader
pRdr->szReader = pwszRdr;
pRdr->dwCurrentState = SCARD_STATE_UNAWARE;
}
// Increment reader indices
pRdr++;
pwszRdr += lstrlen(pwszRdr)+1;
}
}
}
// Clean up resources
if (NULL != pwszReaders)
{
SCardFreeMemory(hSC, pwszReaders);
}
if (NULL != pwszOldReaders)
{
SCardFreeMemory(hSC, pwszOldReaders);
}
return lReturn;
}
LONG __cdecl main(
VOID)
{
DWORD dwRet = ERROR_SUCCESS;
SCARDCONTEXT hSC = NULL;
LONG lReturn = NO_ERROR;
HANDLE hStartedEvent = NULL;
// Get handle to event that will be signaled when the Smart Card Service is available
hStartedEvent = SCardAccessStartedEvent();
// Wait for the Smart Card Service to become available
dwRet = WaitForSingleObject(hStartedEvent, INFINITE);
if (WAIT_OBJECT_0 != dwRet)
{
wprintf(L"Wait for Smart Card Service failed with error 0x%x.\n", dwRet);
lReturn = dwRet;
}
else
{
// Establish a system-level context with the Smart Card Service
lReturn = SCardEstablishContext(
SCARD_SCOPE_SYSTEM,
NULL,
NULL,
&hSC);
if (SCARD_S_SUCCESS != lReturn)
{
wprintf(L"Failed to establish context with the Smart Card Service with error 0x%x.\n", lReturn);
}
else
{
// Begin monitoring the readers in the system
// This routine could be done in a separate thread so it can be cancelled via SCardCancel().
lReturn = MonitorReaders(hSC);
}
}
// Cleanup resources
if (NULL != hSC)
{
SCardReleaseContext(hSC);
}
if (NULL != hStartedEvent)
{
SCardReleaseStartedEvent();
}
wprintf(L"Done.\n");
return lReturn;
}
Informacje
Aby uzyskać więcej informacji na temat rozwiązywania problemów z wtyczką i odtwarzaniem kart inteligentnych, zobacz Przewodnik rozwiązywania problemów z kartami inteligentnymi.
Zbieranie danych
Jeśli potrzebujesz pomocy ze strony pomocy technicznej firmy Microsoft, zalecamy zebranie informacji, wykonując kroki wymienione w artykule Zbieranie informacji przy użyciu zestawu narzędzi TSS w przypadku problemów związanych z wdrożeniem.