Mensaje de error al insertar una tarjeta inteligente en un lector: El software del controlador de dispositivo no se instaló correctamente

En este artículo se proporciona una solución a un error que se produce al insertar una tarjeta inteligente en un lector.

Se aplica a: Windows Server 7 Service Pack 1, Windows Server 2012 R2
Número de KB original: 976832

Síntomas

Al insertar una tarjeta inteligente en un lector de tarjetas inteligentes, Windows intenta descargar e instalar los minidriveres de tarjeta inteligente para la tarjeta a través de Plug and Play servicios. Si el controlador de la tarjeta inteligente no está disponible en ninguna de las ubicaciones preconfiguradas, como Windows Update, WSUS o rutas de acceso de intranet, y un proveedor de servicios crypto personalizado no está instalado en el sistema, recibirá el siguiente mensaje de error en el área de notificación:

El software del controlador de dispositivo no se instaló correctamente

Haga clic aquí para obtener más información.

Este mensaje de error desaparece después de varios segundos.

Además, en Administrador de dispositivos, en Otros dispositivos, el dispositivo de tarjeta inteligente tiene el estado DNF (No se encontró el controlador).

Esto requiere con frecuencia que el usuario obtenga uno de los siguientes elementos del emisor de tarjetas inteligentes para resolver este error:

  1. Un minidriver de tarjeta inteligente registrado en Windows.
  2. Un proveedor de servicios criptográficos (CSP) personalizado para la tarjeta inteligente.
  3. Un minidriver de tarjeta inteligente sin logotipo de Windows.
  4. Otro middleware, como un control ActiveX, un software PKCS#11 u otro software personalizado.

Sin embargo, si al usuario solo se le proporciona el elemento 3 o 4 de esta lista, la tarjeta inteligente sigue funcionando en el sistema. Sin embargo, el usuario recibirá el mensaje de error que se menciona en esta sección cada vez que inserte la tarjeta inteligente.

Este problema afecta a todas las versiones de Windows 7, Windows Server 2008 R2 y en versiones posteriores de ambos sistemas operativos.

Causa

Todas las tarjetas inteligentes requieren software adicional para funcionar en Windows a menos que haya un controlador de bandeja de entrada que permita al usuario usar la tarjeta sin instalar software adicional. Windows Smart Card Framework se ha mejorado en Windows 7 para habilitar la descarga automática de minidriveres de tarjeta inteligente desde Windows Update o desde otras ubicaciones similares, como un servidor WSUS, cuando la tarjeta inteligente se inserta en el lector. Todas las tarjetas inteligentes que superan correctamente los requisitos del logotipo, tal como se publica en el Programa de logotipos de Windows, se benefician de esta característica.

Sin embargo, si el software necesario para usar una tarjeta inteligente en Windows no tiene logotipo o es de un tipo que difiere de un minidriver, como un controlador PKCS#11, un CSP personalizado, middleware o un control ActiveX, se produce un error en la opción de descarga automática porque Microsoft certifica solo minidriveres de tarjeta inteligente. Por lo tanto, si el usuario inserta una tarjeta para la que aún no está registrado un CSP personalizado, el usuario recibe un mensaje de error que indica que falta el software del controlador para el dispositivo de tarjeta inteligente, aunque el usuario pueda usar la tarjeta inteligente a través de software adicional que se instaló en el equipo del usuario desde una instalación personalizada.

Solución

Aunque las tarjetas inteligentes siguen funcionando a pesar del mensaje de error que el usuario ve, un emisor de tarjetas inteligentes, un proveedor o un fabricante pueden usar uno de los métodos siguientes para resolver este error.

Implementación de un minidriver de tarjeta inteligente

Se recomienda que los emisores de tarjetas, proveedores y fabricantes implementen minidriveres de tarjetas inteligentes y participen en el Programa de logotipos de Windows para beneficiarse de las mejoras introducidas en la plataforma, como la tarjeta inteligente Plug and Play, device stage para tarjetas inteligentes, etc.

Implementación de un controlador NULL para la tarjeta inteligente

Si se requiere software personalizado como un controlador PKCS#11, un control ActiveX u otro middleware para habilitar el uso de la tarjeta inteligente en Windows e implementar un minidriver de tarjeta inteligente o un CSP personalizado no es una opción práctica, se recomienda que los emisores de tarjetas, proveedores o fabricantes consideren la posibilidad de enviar controladores NULL a Windows Update. El proceso típico para asegurarse de que un controlador NULL está disponible en Windows Update requiere un envío de dispositivo sin clasificar correcto a través de Winqual. Si en el futuro hay un minidriver disponible para estas tarjetas, el nuevo controlador se puede cargar en Windows Update participando en el Programa de logotipos de Windows. Los controladores NULL se pueden descargar manualmente por los usuarios finales o pueden estar disponibles mediante actualizaciones opcionales.

A continuación se muestra una plantilla de ejemplo para un controlador NULL para una tarjeta inteligente.

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

Para generar el identificador de dispositivo de hardware al que hace referencia la cadena de DEVICE_ID en el ejemplo, siga las instrucciones de la especificación del minidriver de tarjeta inteligente.

Para obtener información detallada sobre cómo enviar un controlador NULL a Microsoft, póngase en contacto con los Servicios de soporte al cliente de Microsoft.

Deshabilitación de Plug and Play de tarjeta inteligente a través de directiva de grupo para equipos administrados

Esta opción solo se recomienda para las implementaciones empresariales en las que los equipos están administrados por administradores y todo el software necesario para trabajar con las tarjetas inteligentes que se usan en la empresa se instala mediante herramientas de administración de software como SMS.

Este procedimiento no se recomienda en los siguientes entornos porque afectará a todas las tarjetas inteligentes del entorno:

  • Implementaciones comerciales destinadas a usuarios finales, como la banca en línea.
  • Entornos que incluyen tarjetas inteligentes Plug and Play y tarjetas inteligentes que no son Plug and Play que usan directiva de grupo para deshabilitar Plug and Play para tarjetas inteligentes.

La Plug and Play de tarjeta inteligente se puede deshabilitar en empresas en las que el equipo del usuario final se administra mediante mecanismos como directiva de grupo.

Si la implementación solo usa soluciones de tarjeta inteligente que no son Plug and Play, un administrador local puede deshabilitar Plug and Play de tarjeta inteligente en un equipo cliente. Deshabilitar la tarjeta inteligente Plug and Play evita que se descarguen los controladores de tarjetas inteligentes, también conocidos como minidriveres de tarjeta inteligente. También evita las solicitudes de Plug and Play de tarjeta inteligente.

Para deshabilitar Plug and Play de tarjeta inteligente en directiva de grupo locales, siga estos pasos:

  1. Haga clic en Inicio, escriba gpedit.msc en el cuadro Buscar programas y archivos y, a continuación, presione ENTRAR.

  2. En el árbol de consola en Configuración del equipo, haga clic en Plantillas administrativas.

  3. En el panel de detalles, haga doble clic en Componentes de Windows y, a continuación, haga doble clic en Tarjeta inteligente.

  4. Haga clic con el botón derecho en Activar tarjeta inteligente Plug and Play servicio y, a continuación, haga clic en Editar.

  5. Haga clic en Deshabilitadoy, a continuación, haga clic en Aceptar.

Cambiar el sistema del usuario final y deshabilitar la tarjeta inteligente Plug and Play para tarjetas específicas

Esta es la opción menos recomendada. Debe usar esta opción solo si las tarjetas son tarjetas heredadas y no hay planes para implementar minidriveres de tarjeta inteligente en el futuro. Esta opción requiere que el software existente que ya está instalado en el sistema notifique a Windows que hay un CSP personalizado instalado en el sistema aunque no exista dicho CSP en el sistema del usuario final. En cuanto Windows determina que ya hay un CSP personalizado instalado en el sistema, Windows no intenta descargar e instalar un controlador a través de la tarjeta inteligente Plug and Play. No se crea ningún nodo de dispositivo para el dispositivo de tarjeta inteligente que esté visible en Administrador de dispositivos. Esta opción da como resultado los siguientes cambios en el registro del sistema:

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

Entradas del Registro de subclave:

  • ATR=Hexadecimal DWORD: ATR delimitado por comas de la tarjeta inteligente.

  • ATRMask= DWORD hexadecimal: máscara delimitada por comas que se va a aplicar al ATR para enmascarar bytes insignificantes en el ATR.

  • Crypto Provider=Valor de cadena: alguna cadena relevante para la tarjeta inteligente.

Por ejemplo:

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

Entradas del Registro de subclave:

  • ATR=Hexadecimal DWORD: 3b,dc,13,00,40,3a,49,54,47,5f,4d,53,43,53,50,5f,56,32
  • ATRMask= DWORD hexadecimal: ff,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

En el caso de los sistemas de x64 bits, se deben realizar cambios idénticos en la subclave siguiente: HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Cryptography\Calais\SmartCards

Se recomienda que, en lugar de cambiar directamente el registro del sistema, use las API de WinSCard para introducir estos cambios en el sistema. Este es un ejemplo de código de ejemplo que detecta la inserción de tarjeta inteligente y, a continuación, deshabilita la tarjeta inteligente Plug and Play para la tarjeta determinada mediante la creación de una entrada del Registro que asocia la tarjeta a un proveedor no existente.

Microsoft proporciona ejemplos de programación con fines ilustrativos únicamente, sin ninguna garantía, ya sea expresa o implícita. Esto incluye, entre otras, las garantías implícitas de comerciabilidad e idoneidad para un fin determinado. Se considera que está familiarizado con el lenguaje de programación que se muestra y con las herramientas para crear y depurar procedimientos. Los ingenieros de soporte técnico de Microsoft pueden explicarle la funcionalidad de un determinado procedimiento. Sin embargo, no modificarán estos ejemplos para proporcionar una funcionalidad adicional o procesos de construcción para que se cumplan sus requisitos específicos.

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

Referencias

Para obtener más información sobre cómo solucionar problemas de tarjeta inteligente Plug and Play, consulte la Guía de solución de problemas de tarjetas inteligentes.

Recolección de datos

Si necesita ayuda del soporte técnico de Microsoft, le recomendamos que recopile la información siguiendo los pasos mencionados en Recopilación de información mediante TSS para problemas relacionados con la implementación.