Mensagem de erro ao inserir um cartão inteligente em um leitor: o software do driver de dispositivo não foi instalado com êxito

Este artigo fornece uma solução para um erro que ocorre quando você insere uma cartão inteligente em um leitor.

Aplica-se a: Windows 7 Service Pack 1, Windows Server 2012 R2
Número de KB original: 976832

Sintomas

Quando você insere um cartão inteligente em um leitor de cartão inteligente, o Windows tenta baixar e instalar os minidrivers cartão inteligentes para o cartão por meio de serviços de Plug and Play. Se o driver do cartão inteligente não estiver disponível em nenhum dos locais pré-configurados, como Windows Update, WSUS ou caminhos de intranet e um provedor de serviços crypto personalizado ainda não estiver instalado no sistema, você receberá a seguinte mensagem de erro na área de notificação:

O software do driver de dispositivo não foi instalado com êxito

Clique aqui para obter detalhes.

Essa mensagem de erro desaparece após vários segundos.

Além disso, em Gerenciador de Dispositivos, em Outros dispositivos, o dispositivo Smart Card tem um status de DNF (Driver não encontrado).

Isso exige frequentemente que o usuário obtenha um dos seguintes itens do emissor de cartão inteligente para resolve esse erro:

  1. Um minidriver de cartão inteligente registrado pelo Windows.
  2. Um CSP (provedor de serviço criptográfico personalizado) para o Smart cartão.
  3. Um minidriver de cartão inteligente sem logotipo do Windows.
  4. Outros middlewares, como um controle ActiveX, software PKCS#11 ou outro software personalizado.

No entanto, se o usuário for fornecido apenas com o item 3 ou 4 desta lista, o cartão inteligente continuará funcionando no sistema. No entanto, o usuário receberá a mensagem de erro mencionada nesta seção sempre que inserir o cartão inteligente.

Esse problema afeta todas as versões do Windows 7, Windows Server 2008 R2 e em versões posteriores de ambos os sistemas operacionais.

Motivo

Todos os cartões inteligentes exigem software adicional para funcionar no Windows, a menos que haja um driver de caixa de entrada que permita que o usuário use o cartão sem instalar software adicional. O Windows Smart Card Framework foi aprimorado no Windows 7 para habilitar o download automático de minidrivers smart cartão de Windows Update ou de outros locais semelhantes, como um servidor WSUS quando o cartão inteligente é inserido no leitor. Todos os cartões inteligentes que passam com êxito os requisitos do logotipo, conforme publicado pelo Programa de Logotipo do Windows, se beneficiam desse recurso.

No entanto, se o software necessário para usar um cartão inteligente no Windows não tiver o logotipo ou for de um tipo que difere de um minidriver, como um driver PKCS#11, um CSP personalizado, um middleware ou um controle ActiveX, a opção de download automático falhará porque a Microsoft certifica apenas minidrivers de cartão inteligentes. Portanto, se o usuário inserir um cartão para o qual um CSP personalizado ainda não está registrado, o usuário receberá uma mensagem de erro que afirma que o software do driver está ausente para o dispositivo de cartão inteligente, embora o usuário possa usar o cartão inteligente por meio de software adicional instalado no computador do usuário a partir de uma instalação personalizada.

Resolução

Embora os cartões inteligentes continuem funcionando apesar da mensagem de erro que o usuário vê, um emissor, fornecedor ou fabricante de cartão inteligente pode usar um dos seguintes métodos para resolve esse erro.

Implementar um minidriver de cartão inteligente

Recomendamos que cartão emissores, fornecedores e fabricantes implementem minidrivers cartão inteligentes e participem do Programa de Logotipo do Windows para se beneficiar das melhorias introduzidas na plataforma, como Smart Card Plug and Play, Estágio de Dispositivo para Cartões Inteligentes e assim por diante.

Implementar um driver NULL para seu cartão inteligente

Se um software personalizado, como um driver PKCS#11, um controle ActiveX ou algum outro middleware for necessário para habilitar o uso de cartão inteligentes no Windows e implementar um minidriver cartão inteligente ou um CSP personalizado não for uma opção prática, recomendamos que cartão emissores, fornecedores ou fabricantes considerem enviar drivers NULL para Windows Update. O processo típico para garantir que um driver NULL esteja disponível no Windows Update requer um envio de dispositivo não classificado bem-sucedido por meio do Winqual. Se no futuro, houver um minidriver disponível para esses cartões, o novo driver poderá ser carregado para Windows Update participando do Programa de Logotipo do Windows. Os drivers NULL podem então ser baixados manualmente pelos usuários finais ou podem ser disponibilizados usando atualizações opcionais.

A seguir está um modelo de exemplo para um driver NULL para um cartão 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 gerar a ID do dispositivo de hardware referenciada pela cadeia de caracteres DEVICE_ID no exemplo, siga as instruções na especificação do minidriver cartão inteligente.

Para obter informações detalhadas sobre como enviar um driver NULL para a Microsoft, entre em contato com os Serviços de Suporte ao Cliente da Microsoft.

Desabilitar Plug and Play de Cartão Inteligente por meio de Política de Grupo para computadores gerenciados

Essa opção é recomendada apenas para implantações empresariais em que os computadores são gerenciados pelos administradores e todo o software necessário para trabalhar com os cartões inteligentes que estão sendo usados na empresa é instalado usando ferramentas de gerenciamento de software, como SMS.

Esse procedimento é desencorajado nos seguintes ambientes porque afetará todos os cartões inteligentes em seu ambiente:

  • Implantações comerciais que visam usuários finais, como bancos online.
  • Ambientes que incluem cartões inteligentes Plug and Play e cartões inteligentes não Plug and Play que usam Política de Grupo para desabilitar Plug and Play para cartões inteligentes.

O smart card Plug and Play pode ser desabilitado em empresas em que o computador do usuário final é gerenciado por mecanismos como Política de Grupo.

Se sua implantação usar apenas soluções de cartão inteligentes não Plug and Play, o Smart Card Plug and Play poderá ser desabilitado por um administrador local em um computador cliente. Desabilitar Plug and Play de Cartão Inteligente impede que drivers de cartão inteligentes, também conhecidos como minidrivers de cartão inteligentes, baixem. Ele também impede os prompts de Plug and Play de Cartão Inteligente.

Para desabilitar o Smart Card Plug and Play no Política de Grupo local, siga estas etapas:

  1. Clique em Iniciar, digite gpedit.msc na caixa De pesquisa de programas e arquivos e pressione ENTER.

  2. Na árvore de console em Configuração do Computador, clique em Modelos Administrativos.

  3. No painel de detalhes, clique duas vezes em Componentes do Windows e clique duas vezes em Cartão Inteligente.

  4. Clique com o botão direito do mouse em Ativar o serviço Plug and Play cartão inteligente e clique em Editar.

  5. Clique em Desabilitado e clique em OK.

Alterar o sistema do usuário final e desabilitar Plug and Play de Cartão Inteligente para cartões específicos

Essa é a opção menos recomendada. Você só deve usar essa opção se os cartões forem cartões herdados e não houver planos para implementar minidrivers cartão inteligentes no futuro. Essa opção exige que o software existente que já está instalado no sistema notifique o Windows de que há um CSP personalizado instalado no sistema, embora nenhum CSP exista no sistema de usuário final. Assim que o Windows determina que há um CSP personalizado já instalado no sistema, o Windows não tenta baixar e instalar um driver por meio do Smart Card Plug and Play. Nenhum nó de dispositivo para o dispositivo de cartão inteligente é criado que está visível em Gerenciador de Dispositivos. Essa opção resulta nas seguintes alterações no registro do sistema:

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

Entradas de registro subchave:

  • ATR=Hexadecimal DWORD: ATR delimitado por vírgula do cartão inteligente.

  • ATRMask= Hexadecimal DWORD: máscara delimitada por vírgula para aplicar ao ATR para mascarar bytes insignificantes no ATR.

  • Crypto Provider=String value: alguma cadeia de caracteres relevante para seu cartão inteligente.

Por exemplo:

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

Entradas de registro subchave:

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

Para sistemas x64 bits, alterações idênticas devem ser feitas sob a seguinte subchave: HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Cryptography\Calais\SmartCards

Recomendamos que, em vez de alterar diretamente o registro do sistema, você use APIs WinSCard para introduzir essas alterações no sistema. Aqui está o exemplo de código de exemplo que detecta a inserção de cartão inteligente e desabilita Plug and Play de Cartão Inteligente para o cartão específico criando uma entrada de registro que associe o cartão a um provedor não existente.

A Microsoft oferece exemplos de programação somente para ilustração, sem garantias expressas ou implícitas. Isso inclui, mas não está limitado a, as garantias implícitas de qualidade comercial ou conformidade para uma determinada finalidade. Este artigo supõe que você conhece a linguagem de programação que está sendo demonstrada e as ferramentas usadas nos processos de criação e depuração. Os engenheiros de suporte da Microsoft podem ajudar a explicar a funcionalidade de um determinado procedimento. Entretanto, eles não modificarão esses exemplos para fornecer funcionalidades adicionais ou construir procedimentos que atendam aos seus 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;
}

Referências

Para obter mais informações sobre como solucionar problemas de cartão Plug and Play inteligentes, consulte Guia de solução de problemas de cartão inteligente.

Coleta de dados

Se você precisar de ajuda do suporte da Microsoft, recomendamos coletar as informações seguindo as etapas mencionadas em Coletar informações usando o TSS para problemas relacionados à implantação.