Foutbericht wanneer u een smartcard in een lezer invoegt: De software van het apparaatstuurprogramma is niet geïnstalleerd

Dit artikel biedt een oplossing voor een fout die optreedt wanneer u een smartcard in een lezer plaatst.

Van toepassing op: Windows 7 Service Pack 1, Windows Server 2012 R2
Origineel KB-nummer: 976832

Symptomen

Wanneer u een smartcard in een smartcardlezer plaatst, 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 er nog geen aangepaste Crypto-serviceprovider op het systeem is geïnstalleerd, ontvangt u het volgende foutbericht in het systeemvak:

De software van het apparaatstuurprogramma 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).

Hiervoor moet de gebruiker vaak een van de volgende items ophalen bij de verlener van smartcards om deze fout op te lossen:

  1. Een door Windows geregistreerde smartcard minidriver.
  2. Een aangepaste cryptografische serviceprovider (CSP) voor de smartcard.
  3. Een minidriver met niet-aangemelde Windows-smartcard.
  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 krijgt, blijft de smartcard op het systeem werken. De gebruiker ontvangt echter het foutbericht dat in deze sectie wordt vermeld telkens wanneer hij of zij 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 Smart Card 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, mogelijk te maken wanneer de smartcard in de lezer wordt geplaatst. Alle smartcards die voldoen aan de logovereisten, 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 certificeert. Als de gebruiker dus een kaart invoegt waarvoor nog geen aangepaste CSP is geregistreerd, ontvangt de gebruiker een foutbericht waarin wordt aangegeven dat de stuurprogrammasoftware ontbreekt voor het smartcardapparaat, hoewel de gebruiker de smartcard kan gebruiken via aanvullende 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 verlener van smartcards, leverancier of fabrikant van smartcards een van de volgende methoden gebruiken om deze fout op te lossen.

Een smartcard minidriver implementeren

We raden kaartverleners, leveranciers en fabrikanten aan 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 smartcards in Windows mogelijk te maken en het implementeren van een smartcard minidriver of een aangepaste CSP geen praktische optie is, raden we u aan kaartverleners, leveranciers of fabrikanten null-stuurprogramma's in te dienen bij Windows Update. Het gebruikelijke proces om ervoor te zorgen dat een NULL-stuurprogramma beschikbaar is op 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 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 voor het 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 gebruikmaken van groepsbeleid om Plug en Play voor smartcards uit te schakelen.

SmartCard-Plug en Play kunnen 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-Plug en Play uitschakelt, voorkomt u dat smartcardstuurprogramma's, ook wel smartcard minidrivers genoemd, worden gedownload. Het voorkomt ook dat smartcard-Plug en Play prompts.

Voer de volgende stappen uit om smartcard-Plug en Play uit te schakelen in 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-Plug en Play-service inschakelen en klik vervolgens op Bewerken.

  5. Klik op Uitgeschakeld en klik vervolgens op OK.

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

Dit is de minst aanbevolen optie. U moet deze optie alleen gebruiken als de kaarten verouderde kaarten zijn en er geen plannen zijn om smartcard minidrivers in de toekomst te implementeren. Voor deze optie is vereist dat de bestaande software die al op het systeem is geïnstalleerd Windows informeren 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 subsleutel:

  • ATR=Hexadecimaal DWORD: door komma's gescheiden ATR van de smartcard.

  • ATRMask= Hexadecimaal 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 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

We raden u aan om in plaats van het systeemregister rechtstreeks te wijzigen, WinSCard-API's te gebruiken om deze wijzigingen in het systeem te introduceren. Hier volgt een voorbeeldcodevoorbeeld dat het invoegen van smartcards 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 Handleiding voor het oplossen van problemen met smartcards voor meer informatie over het oplossen van problemen met smartcards Plug en Play.

Gegevensverzameling

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.