Message d’erreur lorsque vous insérez un carte intelligent dans un lecteur : Le logiciel du pilote de périphérique n’a pas été correctement installé

Cet article fournit une solution à une erreur qui se produit lorsque vous insérez un carte intelligent dans un lecteur.

Produits concernés : Windows 7 Service Pack 1, Windows Server 2012 R2
Numéro de la base de connaissances d’origine : 976832

Symptômes

Lorsque vous insérez un carte intelligent dans un lecteur carte intelligent, Windows tente de télécharger et d’installer les mini-lecteurs smart carte pour le carte via Plug-and-Play services. Si le pilote de la carte intelligente n’est disponible à aucun des emplacements préconfigurés, tels que les chemins d’accès Windows Update, WSUS ou intranet, et qu’un fournisseur de services de chiffrement personnalisé n’est pas déjà installé sur le système, le message d’erreur suivant s’affiche dans la zone de notification :

Le logiciel du pilote de périphérique n’a pas été correctement installé

Cliquez ici pour plus d’informations.

Ce message d’erreur disparaît après plusieurs secondes.

En outre, dans Gestionnaire de périphériques, sous Autres appareils, le périphérique de carte à puce a une status de DNF (Pilote introuvable).

Cela nécessite souvent que l’utilisateur obtienne l’un des éléments suivants à partir de l’émetteur smart carte pour résoudre cette erreur :

  1. Minidriver smart carte windows.
  2. Un fournisseur de services de chiffrement (CSP) personnalisé pour le smart carte.
  3. Minidriver smart carte Windows sans logo.
  4. Autres intergiciels tels qu’un contrôle ActiveX, un logiciel PKCS#11 ou d’autres logiciels personnalisés.

Toutefois, si l’utilisateur ne dispose que de l’élément 3 ou 4 de cette liste, le carte intelligent continue de fonctionner sur le système. Toutefois, l’utilisateur reçoit le message d’erreur mentionné dans cette section chaque fois qu’il insère le carte intelligent.

Ce problème affecte toutes les versions de Windows 7, Windows Server 2008 R2 et dans les versions ultérieures des deux systèmes d’exploitation.

Cause

Toutes les cartes à puce nécessitent un logiciel supplémentaire pour fonctionner dans Windows, sauf s’il existe un pilote de boîte de réception qui permet à l’utilisateur d’utiliser le carte sans installer de logiciels supplémentaires. L’infrastructure de carte à puce Windows a été améliorée dans Windows 7 pour permettre le téléchargement automatique de mini-lecteurs smart carte à partir de Windows Update ou d’autres emplacements similaires tels qu’un serveur WSUS lorsque le carte intelligent est inséré dans le lecteur. Toutes les cartes à puce qui répondent correctement aux exigences de logo, telles que publiées par le programme de logo Windows, bénéficient de cette fonctionnalité.

Toutefois, si le logiciel requis pour utiliser un carte intelligent dans Windows n’est pas logoné ou est d’un type différent d’un minidriver, tel qu’un pilote PKCS#11, un fournisseur de solutions cloud personnalisé, un intergiciel (middleware) ou un contrôle ActiveX, l’option de téléchargement automatique échoue, car Microsoft certifie uniquement les minidrivers smart carte. Par conséquent, si l’utilisateur insère un carte pour lequel un fournisseur de solutions Cloud personnalisé n’est pas déjà inscrit, l’utilisateur reçoit un message d’erreur indiquant que le logiciel pilote est manquant pour l’appareil smart carte même si l’utilisateur peut utiliser le carte intelligent via un logiciel supplémentaire qui a été installé sur l’ordinateur de l’utilisateur à partir d’une installation personnalisée.

Résolution

Bien que les cartes à puce continuent de fonctionner malgré le message d’erreur que l’utilisateur voit, un émetteur de carte intelligent, un fournisseur ou un fabricant peut utiliser l’une des méthodes suivantes pour résoudre cette erreur.

Implémenter un minidriver intelligent carte

Nous recommandons que carte émetteurs, fournisseurs et fabricants implémentent des mini-disques carte intelligents et participent au programme de logo Windows pour bénéficier des améliorations introduites dans la plateforme, telles que la Plug-and-Play de carte à puce, l’étape d’appareil pour les cartes à puce, etc.

Implémenter un pilote NULL pour votre carte intelligente

Si un logiciel personnalisé tel qu’un pilote PKCS#11, un contrôle ActiveX ou un autre intergiciel (middleware) est nécessaire pour permettre l’utilisation d’une carte intelligente sur Windows, et que l’implémentation d’un mini-carte intelligent ou d’un fournisseur de solutions cloud personnalisé n’est pas une option pratique, nous vous recommandons que carte émetteurs, fournisseurs ou fabricants envisagent d’envoyer des pilotes NULL à Windows Update. Le processus classique permettant de s’assurer qu’un pilote NULL est disponible sur Windows Update nécessite une soumission d’appareil non classifiée réussie via Winqual. Si, à l’avenir, un mini-lecteur est disponible pour ces cartes, le nouveau pilote peut être chargé sur Windows Update en participant au programme de logo Windows. Les pilotes NULL peuvent ensuite être téléchargés manuellement par les utilisateurs finaux ou mis à disposition à l’aide de mises à jour facultatives.

Voici un exemple de modèle pour un pilote NULL pour une carte intelligente.

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

Pour générer l’ID de périphérique matériel référencé par la chaîne DEVICE_ID dans l’exemple, suivez les instructions de la spécification du minidriver smart carte.

Pour plus d’informations sur la façon d’envoyer un pilote NULL à Microsoft, contactez les services de support technique Microsoft.

Désactiver la Plug-and-Play de carte à puce via stratégie de groupe pour les ordinateurs gérés

Cette option est recommandée uniquement pour les déploiements d’entreprise où les ordinateurs sont gérés par des administrateurs et où tous les logiciels nécessaires pour travailler avec les cartes à puce utilisées dans l’entreprise sont installés à l’aide d’outils de gestion logicielle tels que SMS.

Cette procédure est déconseillée dans les environnements suivants, car elle affecte toutes les cartes à puce de votre environnement :

  • Déploiements commerciaux qui ciblent les utilisateurs finaux, tels que les services bancaires en ligne.
  • Environnements qui incluent à la fois des cartes à puce Plug-and-Play et des cartes à puce non Plug-and-Play qui utilisent stratégie de groupe pour désactiver les Plug-and-Play pour les cartes à puce.

Les Plug-and-Play de carte à puce peuvent être désactivées dans les entreprises où l’ordinateur de l’utilisateur final est géré par des mécanismes tels que stratégie de groupe.

Si votre déploiement utilise uniquement des solutions de carte intelligente non Plug-and-Play, les Plug-and-Play de carte à puce peuvent être désactivées par un administrateur local sur un ordinateur client. La désactivation des Plug-and-Play de carte à puce empêche le téléchargement des pilotes de carte intelligents, également appelés mini-carte intelligents. Il empêche également les invites de Plug-and-Play de carte à puce.

Pour désactiver les Plug-and-Play de carte à puce dans les stratégie de groupe locales, procédez comme suit :

  1. Cliquez sur Démarrer, tapez gpedit.msc dans la zone Rechercher des programmes et des fichiers , puis appuyez sur Entrée.

  2. Dans l’arborescence de la console, sous Configuration de l’ordinateur, cliquez sur Modèles d’administration.

  3. Dans le volet d’informations, double-cliquez sur Composants Windows, puis double-cliquez sur Carte à puce.

  4. Cliquez avec le bouton droit sur Activer le service Plug-and-Play carte à puce, puis cliquez sur Modifier.

  5. Cliquez sur Désactivé, puis sur OK.

Modifier le système de l’utilisateur final et désactiver les Plug-and-Play de carte à puce pour des cartes spécifiques

Il s’agit de l’option la moins recommandée. Vous devez utiliser cette option uniquement si les cartes sont des cartes héritées et qu’il n’est pas prévu d’implémenter des mini-drivers smart carte à l’avenir. Cette option nécessite que le logiciel existant déjà installé sur le système notifie Windows qu’un fournisseur de services de configuration personnalisé est installé sur le système, même s’il n’existe pas de fournisseur de services de configuration de ce type sur le système de l’utilisateur final. Dès que Windows détermine qu’un fournisseur de services de configuration personnalisé est déjà installé sur le système, Windows n’essaie pas de télécharger et d’installer un pilote via la carte à puce Plug-and-Play. Aucun nœud d’appareil pour l’appareil de carte intelligent visible dans Gestionnaire de périphériques n’est créé. Cette option entraîne les modifications suivantes apportées au registre système :

Sous-clé : HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\<Smart card name>

Entrées de Registre de sous-clés :

  • ATR=DWORD hexadécimal : ATR délimité par des virgules du carte intelligent.

  • ATRMask= DWORD hexadécimal : masque délimité par des virgules à appliquer à l’ATR pour masquer les octets non significatifs dans l’ATR.

  • Crypto Provider=Valeur de chaîne : chaîne pertinente pour votre carte intelligente.

Par exemple :

Sous-clé : HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\Fabrikam ATM card

Entrées de Registre de sous-clés :

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

Pour les systèmes x64 bits, des modifications identiques doivent être effectuées sous la sous-clé suivante : HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Cryptography\Calais\SmartCards

Nous vous recommandons, au lieu de modifier directement le registre système, d’utiliser les API WinSCard pour introduire ces modifications dans le système. Voici un exemple de code qui détecte l’insertion de carte intelligente, puis désactive les Plug-and-Play de carte à puce pour le carte particulier en créant une entrée de Registre qui associe le carte à un fournisseur non existant.

Microsoft fournit des exemples de programmation à titre d’illustration uniquement, sans garantie expresse ou implicite. Cela inclut, sans y être limité, les garanties implicites de commercialisation et d’adaptation à un but en particulier. Cet article considère que vous connaissez le langage de programmation présenté et les outils utilisés pour créer et déboguer des procédures. Les ingénieurs du support Microsoft peuvent expliquer la fonctionnalité d’une procédure en particulier. Toutefois, ils ne modifieront pas ces exemples pour fournir des fonctionnalités supplémentaires ou créer des procédures répondant à vos besoins spécifiques.

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

References

Pour plus d’informations sur la résolution des problèmes liés aux carte Plug-and-Play intelligentes, consultez Guide de résolution des problèmes liés aux cartes à puce.

Collecte de données

Si vous avez besoin de l’aide du support Microsoft, nous vous recommandons de collecter les informations en suivant les étapes mentionnées dans Collecter des informations à l’aide de TSS pour les problèmes liés au déploiement.