Messaggio di errore quando si inserisce una smart card in un lettore: Il software del driver di dispositivo non è stato installato correttamente

Questo articolo fornisce una soluzione a un errore che si verifica quando si inserisce una smart card in un lettore.

Si applica a: Windows Server 7 Service Pack 1, Windows Server 2012 R2
Numero KB originale: 976832

Sintomi

Quando si inserisce una smart card in un lettore di smart card, Windows prova a scaricare e installare i minidriver della smart card per la scheda tramite Plug and Play servizi. Se il driver per la smart card non è disponibile in nessuna delle posizioni preconfigurate, ad esempio i percorsi Windows Update, WSUS o Intranet e un provider di servizi Crypto personalizzato non è già installato nel sistema, viene visualizzato il messaggio di errore seguente nell'area di notifica:

Il software del driver di dispositivo non è stato installato correttamente

Fare clic qui per informazioni dettagliate.

Questo messaggio di errore scompare dopo alcuni secondi.

Inoltre, in Gestione dispositivi, in Altri dispositivi il dispositivo smart card ha lo stato DNF (Driver non trovato).

Questo richiede spesso all'utente di ottenere uno degli elementi seguenti dall'autorità di certificazione smart card per risolvere questo errore:

  1. Minidriver con smart card registrato da Windows.
  2. Provider di servizi di crittografia personalizzato (CSP) per la smart card.
  3. Minidriver per smart card windows non logo.
  4. Altro middleware, ad esempio un controllo ActiveX, un software PKCS#11 o altro software personalizzato.

Tuttavia, se all'utente viene fornito solo l'elemento 3 o 4 di questo elenco, la smart card continua a funzionare nel sistema. Tuttavia, l'utente riceverà il messaggio di errore indicato in questa sezione ogni volta che inserisce la smart card.

Questo problema interessa tutte le versioni di Windows 7, Windows Server 2008 R2 e nelle versioni successive di entrambi i sistemi operativi.

Causa

Tutte le smart card richiedono software aggiuntivo per funzionare in Windows, a meno che non sia presente un driver di posta in arrivo che consente all'utente di usare la scheda senza installare software aggiuntivo. Windows Smart Card Framework è stato migliorato in Windows 7 per consentire il download automatico di minidriver smart card da Windows Update o da altre posizioni simili, ad esempio un server WSUS quando la smart card viene inserita nel lettore. Tutte le smart card che superano correttamente i requisiti del logo, come pubblicato dal programma Windows Logo, traggono vantaggio da questa funzionalità.

Tuttavia, se il software necessario per usare una smart card in Windows non è logo o è di tipo diverso da un minidriver, ad esempio un driver PKCS#11, un CSP personalizzato, un middleware o un controllo ActiveX, l'opzione di download automatico ha esito negativo perché Microsoft certifica solo minidriver smart card. Pertanto, se l'utente inserisce una scheda per la quale non è già registrato un CSP personalizzato, l'utente riceve un messaggio di errore che indica che il software driver è mancante per il dispositivo smart card, anche se l'utente può usare la smart card tramite software aggiuntivo installato nel computer dell'utente da un'installazione personalizzata.

Risoluzione

Anche se le smart card continuano a funzionare nonostante il messaggio di errore visualizzato dall'utente, un emittente, un fornitore o un produttore di smart card può usare uno dei metodi seguenti per risolvere questo errore.

Implementare un minidriver per smart card

È consigliabile che emittenti, fornitori e produttori di schede implementino minidriver smart card e partecipino al programma Logo Windows per trarre vantaggio dai miglioramenti introdotti nella piattaforma, ad esempio smart card Plug and Play, Device Stage for Smart Card e così via.

Implementare un driver NULL per la smart card

Se il software personalizzato come un driver PKCS#11, un controllo ActiveX o un altro middleware è necessario per abilitare l'uso di smart card in Windows e l'implementazione di un minidriver smart card o di un CSP personalizzato non è un'opzione pratica, è consigliabile che emittenti di schede, fornitori o produttori considerino l'invio di driver NULL a Windows Update. Il processo tipico per assicurarsi che un driver NULL sia disponibile in Windows Update richiede un invio di dispositivo non classificato correttamente tramite Winqual. Se in futuro è disponibile un minidriver per queste schede, il nuovo driver può essere caricato in Windows Update partecipando al programma Logo Windows. I driver NULL possono quindi essere scaricati manualmente dagli utenti finali o resi disponibili tramite aggiornamenti facoltativi.

Di seguito è riportato un modello di esempio per un driver NULL per una smart card.

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

Per generare l'ID dispositivo hardware a cui fa riferimento la stringa DEVICE_ID nell'esempio, seguire le istruzioni nella specifica del minidriver della smart card.

Per informazioni dettagliate su come inviare un driver NULL a Microsoft, contattare il Servizio Supporto Tecnico Clienti Microsoft.

Disabilitare Plug and Play smart card tramite Criteri di gruppo per i computer gestiti

Questa opzione è consigliata solo per le distribuzioni aziendali in cui i computer sono gestiti dagli amministratori e tutto il software necessario per lavorare con le smart card usate nell'organizzazione viene installato tramite strumenti di gestione software come SMS.

Questa procedura è sconsigliata negli ambienti seguenti perché influirà su tutte le smart card nell'ambiente:

  • Distribuzioni commerciali destinate agli utenti finali, ad esempio online banking.
  • Ambienti che includono smart card Plug and Play e smart card non Plug and Play che usano Criteri di gruppo per disabilitare Plug and Play per le smart card.

Le Plug and Play smart card possono essere disabilitate nelle aziende in cui il computer dell'utente finale è gestito da meccanismi come Criteri di gruppo.

Se la distribuzione usa solo soluzioni di smart card non Plug and Play, Plug and Play smart card possono essere disabilitate da un amministratore locale in un computer client. La disabilitazione della smart card Plug and Play impedisce il download dei driver delle smart card, noti anche come minidriver delle smart card. Impedisce inoltre le richieste di Plug and Play smart card.

Per disabilitare Plug and Play smart card nelle Criteri di gruppo locali, seguire questa procedura:

  1. Fare clic su Start, digitare gpedit.msc nella casella Cerca programmi e file e quindi premere INVIO.

  2. Nell'albero della console in Configurazione computer fare clic su Modelli amministrativi.

  3. Nel riquadro dei dettagli fare doppio clic su Componenti di Windows e quindi fare doppio clic su Smart Card.

  4. Fare clic con il pulsante destro del mouse su Attiva servizio Plug and Play smart card e quindi scegliere Modifica.

  5. Fare clic su Disabilitato e quindi su OK.

Modificare il sistema dell'utente finale e disabilitare Plug and Play smart card per schede specifiche

Questa è l'opzione meno consigliata. È consigliabile usare questa opzione solo se le schede sono schede legacy e non è previsto l'implementazione di minidriver smart card in futuro. Questa opzione richiede che il software esistente già installato nel sistema informi Windows che nel sistema è installato un CSP personalizzato, anche se tale CSP non esiste nel sistema dell'utente finale. Non appena Windows determina che nel sistema è già installato un provider di servizi di configurazione personalizzato, Windows non prova a scaricare e installare un driver tramite smart card Plug and Play. Non viene creato alcun nodo del dispositivo smart card visibile in Gestione dispositivi. Questa opzione comporta le modifiche seguenti al Registro di sistema:

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

Voci del Registro di sistema delle sottochiavi:

  • ATR=DWORD esadecimale: ATR delimitato da virgole della smart card.

  • ATRMask= DWORD esadecimale: maschera delimitata da virgole da applicare all'ATR per mascherare byte non significativi nell'ATR.

  • Crypto Provider=Valore stringa: stringa rilevante per la smart card.

Ad esempio:

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

Voci del Registro di sistema delle sottochiavi:

  • ATR=DWORD esadecimale: 3b,dc,13,00,40,3a,49,54,47,5f,4d,53,43,53,50,5f,56,32
  • ATRMask= DWORD esadecimale: ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff
  • Crypto Provider=String value: Fabrikam ATM Dummy Provider

Per i sistemi a 64 bit, è necessario apportare modifiche identiche nella sottochiave seguente: HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Cryptography\Calais\SmartCards

È consigliabile, invece di modificare direttamente il Registro di sistema, usare le API WinSCard per introdurre queste modifiche al sistema. Di seguito è riportato un esempio di codice di esempio che rileva l'inserimento di smart card e quindi disabilita Plug and Play smart card per la scheda specifica creando una voce del Registro di sistema che associa la scheda a un provider non esistente.

Microsoft fornisce esempi di programmazione a scopo puramente illustrativo, senza alcuna garanzia di qualsiasi tipo, sia espressa che implicita, ivi incluse, senza limitazioni, le garanzie implicite di commerciabilità o idoneità per uno scopo particolare. In questo articolo si presuppone che l'utente conosca il linguaggio di programmazione in questione e gli strumenti utilizzati per creare ed eseguire il debug delle procedure. I tecnici di supporto tecnico Microsoft sono autorizzati a fornire spiegazioni in merito alla funzionalità di una particolare routine, ma in nessuno caso a modificare questi esempi per fornire funzionalità aggiuntive o a creare routine atte a soddisfare specifiche esigenze.

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

Riferimenti

Per altre informazioni sulla risoluzione dei problemi di Plug and Play delle smart card, vedere Guida alla risoluzione dei problemi delle smart card.

Raccolta dei dati

Se è necessaria l'assistenza del supporto tecnico Microsoft, si consiglia di raccogliere le informazioni seguendo i passaggi indicati in Raccogliere informazioni utilizzando TSS per le questioni relative alla distribuzione.