Delen via


Foutbericht wanneer u een smartcard invoegt in een lezer: software voor apparaatstuurprogramma's is niet geïnstalleerd

Dit artikel bevat een oplossing voor een fout die optreedt wanneer u een smartcard in een lezer invoegt.

Oorspronkelijk KB-nummer: 976832

Symptomen

Wanneer u een smartcard invoegt in een smartcardlezer, probeert Windows de smartcard minidrivers voor de kaart te downloaden en te installeren via Plug en Play services. Als het stuurprogramma voor de smartcard niet beschikbaar is op een van de vooraf geconfigureerde locaties, zoals Windows Update-, WSUS- of intranetpaden, en een aangepaste Crypto-serviceprovider nog niet op het systeem is geïnstalleerd, ontvangt u het volgende foutbericht in het systeem:

Software voor apparaatstuurprogramma's is niet geïnstalleerd

Klik hier voor meer informatie.

Dit foutbericht verdwijnt na enkele seconden.

Bovendien heeft het smartcardapparaat in Apparaatbeheer onder Andere apparaten de status DNF (Stuurprogramma niet gevonden).

Dit vereist vaak dat de gebruiker een van de volgende items van de uitgever van de smartcard ophaalt om deze fout op te lossen:

  1. Een minidriver van een Windows-smartcard.
  2. Een aangepaste cryptografische serviceprovider (CSP) voor de smartcard.
  3. Een niet-logoed smartcard minidriver van Windows.
  4. Andere middleware, zoals een ActiveX-besturingselement, PKCS#11-software of andere aangepaste software.

Als de gebruiker echter alleen item 3 of 4 uit deze lijst bevat, blijft de smartcard op het systeem werken. De gebruiker ontvangt echter het foutbericht dat in deze sectie wordt vermeld telkens wanneer deze de smartcard invoegt.

Dit probleem is van invloed op alle versies van Windows 7, Windows Server 2008 R2 en in latere versies van beide besturingssystemen.

Oorzaak

Voor alle smartcards is extra software vereist om in Windows te werken, tenzij er een Postvak IN-stuurprogramma is waarmee de gebruiker de kaart kan gebruiken zonder extra software te installeren. Het Windows SmartCard Framework is verbeterd in Windows 7 om het automatisch downloaden van smartcard minidrivers van Windows Update of van andere vergelijkbare locaties zoals een WSUS-server in te schakelen wanneer de smartcard in de lezer wordt ingevoegd. Alle smartcards die voldoen aan de vereisten voor het logo, zoals gepubliceerd door het Windows-logoprogramma, profiteren van deze functie.

Als de software die is vereist voor het gebruik van een smartcard in Windows echter niet is aangemeld of van een type is dat verschilt van een minidriver, zoals een PKCS#11-stuurprogramma, een aangepaste CSP, middleware of een ActiveX-besturingselement, mislukt de optie voor automatisch downloaden omdat Microsoft alleen smartcard minidrivers gecertificeerd. Als de gebruiker daarom een kaart invoegt waarvoor nog geen aangepaste CSP is geregistreerd, ontvangt de gebruiker een foutbericht met de mededeling dat de stuurprogrammasoftware ontbreekt voor het smartcardapparaat, ook al kan de gebruiker de smartcard gebruiken via extra software die op de computer van de gebruiker is geïnstalleerd vanaf een aangepaste installatie.

Oplossing

Hoewel de smartcards blijven werken ondanks het foutbericht dat de gebruiker ziet, kan een uitgever van smartcards, leveranciers of fabrikanten een van de volgende methoden gebruiken om deze fout op te lossen.

Een smartcard minidriver implementeren

We raden u aan kaartverleners, leveranciers en fabrikanten smartcard minidrivers te implementeren en deel te nemen aan het Windows-logoprogramma om te profiteren van de verbeteringen die zijn geïntroduceerd in het platform, zoals smartcards Plug en Play, apparaatfase voor smartcards, enzovoort.

Een NULL-stuurprogramma implementeren voor uw smartcard

Als aangepaste software zoals een PKCS#11-stuurprogramma, een ActiveX-besturingselement of een andere middleware vereist is om het gebruik van smartcard in Windows in te schakelen en een smartcard minidriver of een aangepaste CSP te implementeren, is het raadzaam dat kaartverleners, leveranciers of fabrikanten overwegen NULL-stuurprogramma's in te dienen bij Windows Update. Het gebruikelijke proces om ervoor te zorgen dat een NULL-stuurprogramma beschikbaar is in Windows Update, vereist een geslaagde niet-geclassificeerde apparaatverzending via Winqual. Als er in de toekomst een minidriver beschikbaar is voor deze kaarten, kan het nieuwe stuurprogramma worden geüpload naar Windows Update door deel te nemen aan het Windows-logoprogramma. De NULL-stuurprogramma's kunnen vervolgens handmatig worden gedownload door de eindgebruikers of kunnen beschikbaar worden gesteld met behulp van optionele updates.

Hier volgt een voorbeeldsjabloon voor een NULL-stuurprogramma voor een smartcard.

;  
; 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"

Als u de hardwareapparaat-id wilt genereren waarnaar wordt verwezen door de DEVICE_ID tekenreeks in het voorbeeld, volgt u de instructies in de specificatie van de smartcard minidriver.

Neem contact op met de klantenservice van Microsoft voor gedetailleerde informatie over het indienen van een NULL-stuurprogramma bij Microsoft.

Smartcard-Plug en Play uitschakelen via groepsbeleid voor beheerde computers

Deze optie wordt alleen aanbevolen voor bedrijfsimplementaties waarbij de computers worden beheerd door beheerders en alle benodigde software om te werken met de smartcards die in de onderneming worden gebruikt, wordt geïnstalleerd met behulp van softwarebeheerprogramma's zoals SMS.

Deze procedure wordt afgeraden in de volgende omgevingen, omdat deze van invloed is op alle smartcards in uw omgeving:

  • Commerciële implementaties die gericht zijn op eindgebruikers, zoals onlinebankieren.
  • Omgevingen met zowel Plug en Play smartcards als niet-Plug en Play smartcards die groepsbeleid gebruiken om Plug en Play voor smartcards uit te schakelen.

Smartcard Plug en Play kan worden uitgeschakeld in ondernemingen waar de computer van de eindgebruiker wordt beheerd door mechanismen zoals Groepsbeleid.

Als uw implementatie alleen niet-Plug en Play smartcardoplossingen gebruikt, kan smartcard-Plug en Play worden uitgeschakeld door een lokale beheerder op een clientcomputer. Als u SmartCard uitschakelt Plug en Play voorkomt u dat smartcardstuurprogramma's, ook wel smartcard minidrivers genoemd, worden gedownload. Het voorkomt ook Plug en Play prompts voor smartcards.

Volg deze stappen om smartcard-Plug en Play uit te schakelen in het lokale groepsbeleid:

  1. Klik op Start, typ gpedit.msc in het vak Programma's en bestanden zoeken en druk op Enter.

  2. Klik in de consolestructuur onder Computerconfiguratie op Beheersjablonen.

  3. Dubbelklik in het detailvenster op Windows-onderdelen en dubbelklik vervolgens op SmartCard.

  4. Klik met de rechtermuisknop op SmartCard inschakelen Plug en Play service en klik vervolgens op Bewerken.

  5. Klik op Uitgeschakeld en klik vervolgens op OK.

Het systeem van de eindgebruiker wijzigen en smartcard-Plug en Play uitschakelen voor specifieke kaarten

Dit is de minst aanbevolen optie. Gebruik deze optie alleen als de kaarten verouderde kaarten zijn en er geen plannen zijn om in de toekomst smartcard minidrivers te implementeren. Deze optie vereist dat de bestaande software die al op het systeem is geïnstalleerd, Windows op de hoogte stelt dat er een aangepaste CSP op het systeem is geïnstalleerd, ook al bestaat er geen dergelijke CSP op het systeem van de eindgebruiker. Zodra Windows vaststelt dat er al een aangepaste CSP op het systeem is geïnstalleerd, probeert Windows geen stuurprogramma te downloaden en te installeren via smartcard Plug en Play. Er wordt geen apparaatknooppunt voor het smartcardapparaat gemaakt dat zichtbaar is in Apparaatbeheer. Deze optie resulteert in de volgende wijzigingen in het systeemregister:

Subsleutel: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\<Smart card name>

Registervermeldingen van subsleutel:

  • ATR=Hexadecimale DWORD: Door komma's gescheiden ATR van de smartcard.

  • ATRMask= Hexadecimale DWORD: door komma's gescheiden masker dat moet worden toegepast op de ATR om onbelangrijke bytes in de ATR te maskeren.

  • CryptoProvider=Tekenreekswaarde: Een tekenreeks die relevant is voor uw smartcard.

Bijvoorbeeld:

Subsleutel: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\Fabrikam ATM card

Registervermeldingen van subsleutel:

  • ATR=Hexadecimaal DWORD: 3b,dc,13.00,40,3a,49,54,47,5f,4d,53,43,53,50,5f,56,32
  • ATRMask= Hexadecimale DWORD: ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff
  • Crypto-provider=tekenreekswaarde: Fabrikam ATM Dummy-provider

Voor x64-bits systemen moeten identieke wijzigingen worden aangebracht onder de volgende subsleutel: HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Cryptography\Calais\SmartCards

Het is raadzaam om winSCard-API's te gebruiken om deze wijzigingen in het systeem te introduceren in plaats van het systeem rechtstreeks te wijzigen. Hier volgt een voorbeeldcodevoorbeeld dat smartcardinvoeging detecteert en vervolgens smartcard Plug en Play voor de specifieke kaart uitschakelt door een registervermelding te maken die de kaart koppelt aan een niet-bestaande provider.

Microsoft verstrekt programmeervoorbeelden alleen ter illustratie, zonder expliciete of impliciete garantie. daaronder mede begrepen, maar niet beperkt tot impliciete garanties met betrekking tot de verkoopbaarheid en/of geschiktheid voor een bepaald doel. In dit artikel wordt ervan uitgegaan dat u bekend bent met de programmeertaal VBScript, alsmede met de hulpprogramma's waarmee procedures worden gemaakt en waarmee fouten in procedures worden opgespoord. Ondersteuningsmedewerkers van Microsoft kunnen helpen bij de uitleg over de functionaliteit van een bepaalde procedure. Deze medewerkers zullen de voorbeelden echter niet aanpassen om extra functionaliteit toe te voegen of om procedures te maken die aan uw specifieke eisen voldoen.

//==============================================================;
//
// 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;
}

Verwijzingen

Zie de handleiding voor het oplossen van problemen met smartcards voor meer informatie over het oplossen van problemen met smartcards Plug en Play.

Gegevens verzamelen

Als u hulp nodig hebt van Microsoft-ondersteuning, raden we u aan de informatie te verzamelen door de stappen te volgen die worden vermeld in Informatie verzamelen met behulp van TSS voor implementatiegerelateerde problemen.