Сообщение об ошибке при вставке смарт-карта в средство чтения: программное обеспечение драйвера устройства не было успешно установлено

В этой статье описывается решение ошибки, возникающей при вставке интеллектуального карта в средство чтения.

Применимо к: Windows Server 7 с пакетом обновления 1, Windows Server 2012 R2
Исходный номер базы знаний: 976832

Симптомы

При вставке смарт-карта в средство чтения смарт-карта Windows пытается скачать и установить мини-накопители smart карта для карта с помощью служб Plug and Play. Если драйвер для интеллектуальной карта недоступен ни в одном из предварительно настроенных расположений, таких как клиентский компонент Центра обновления Windows, WSUS или пути интрасети, а пользовательский поставщик служб шифрования еще не установлен в системе, в области уведомлений появляется следующее сообщение об ошибке:

Не удалось установить программное обеспечение драйвера устройства

Дополнительные сведения см. здесь.

Это сообщение об ошибке исчезает через несколько секунд.

Кроме того, в диспетчер устройств в разделе Другие устройства устройство смарт-карты имеет состояние DNF (драйвер не найден).

Для устранения этой ошибки пользователю часто требуется получить один из следующих элементов от издателя смарт-карта:

  1. Смарт-карта мини-driver в Системе Windows.
  2. Настраиваемый поставщик служб шифрования (CSP) для Smart карта.
  3. Смарт-карта minidriver с windows без логотипа.
  4. Другое ПО промежуточного слоя, например элемент управления ActiveX, программное обеспечение PKCS#11 или другое пользовательское программное обеспечение.

Однако если пользователю предоставлен только элемент 3 или 4 из этого списка, смарт-карта продолжает работать в системе. Однако пользователь будет получать сообщение об ошибке, упомянутое в этом разделе каждый раз при вставке смарт-карта.

Эта проблема затрагивает все выпуски Windows 7, Windows Server 2008 R2 и более поздних версий обеих операционных систем.

Причина

Все смарт-карты требуют дополнительного программного обеспечения для работы в Windows, если нет драйвера папки "Входящие", который позволяет пользователю использовать карта без установки дополнительного программного обеспечения. Платформа Windows Smart Card Framework была улучшена в Windows 7, чтобы включить автоматическую загрузку смарт-карта мини-драйверов из клиентский компонент Центра обновления Windows или из других аналогичных расположений, таких как сервер WSUS, когда смарт-карта вставляется в средство чтения. Все смарт-карты, которые успешно проходят требования к логотипу, опубликованные программой "Логотип Windows", пользуются этой функцией.

Однако если программное обеспечение, необходимое для использования смарт-карта в Windows, не имеет логотипа или имеет тип, отличающийся от мини-driver, например драйвер PKCS#11, настраиваемый CSP, ПО промежуточного слоя или элемент ActiveX, параметр автоматического скачивания завершается ошибкой, так как Корпорация Майкрософт сертифицирует только интеллектуальные карта мини-drivers. Таким образом, если пользователь вставляет карта, для которого пользовательский поставщик служб CSP еще не зарегистрирован, он получает сообщение об ошибке, в котором говорится, что программное обеспечение драйвера отсутствует для интеллектуального карта устройства, даже если пользователь может использовать смарт-карта с помощью дополнительного программного обеспечения, установленного на компьютере пользователя из пользовательской установки.

Разрешение

Хотя смарт-карты продолжают работать, несмотря на сообщение об ошибке, которое видит пользователь, смарт-карта издатель, поставщик или производитель может использовать один из следующих методов для устранения этой ошибки.

Реализация интеллектуального карта мини-driver

Мы рекомендуем карта издателям, поставщикам и производителям внедрять интеллектуальные карта мини-накопители и участвовать в программе логотипа Windows, чтобы воспользоваться преимуществами усовершенствований, представленных в платформе, таких как Plug and Play смарт-карт, этап устройства для смарт-карт и т. д.

Реализация драйвера NULL для интеллектуальной карта

Если для использования интеллектуальной карта в Windows требуется специальное программное обеспечение, например драйвер PKCS#11, элемент ActiveX или другое ПО промежуточного слоя, а реализация интеллектуального карта minidriver или пользовательского CSP не является практическим вариантом, мы рекомендуем карта издателям, поставщикам или производителям отправлять драйверы NULL в клиентский компонент Центра обновления Windows. Типичный процесс проверки доступности драйвера NULL на клиентский компонент Центра обновления Windows требует успешной отправки неклассифицированного устройства через Winqual. Если в будущем для этих карточек будет доступен мини-накопитель, новый драйвер можно загрузить в клиентский компонент Центра обновления Windows, участвуя в программе логотипа Windows. Затем конечные пользователи могут вручную загрузить драйверы NULL или сделать доступными с помощью необязательных обновлений.

Ниже приведен пример шаблона драйвера NULL для интеллектуального карта.

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

Чтобы создать идентификатор устройства, на который ссылается строка DEVICE_ID в примере, следуйте инструкциям в спецификации smart карта minidriver.

Для получения подробных сведений о том, как отправить драйвер NULL в корпорацию Майкрософт, обратитесь в службу поддержки майкрософт.

Отключение Plug and Play смарт-карт через групповая политика для управляемых компьютеров

Этот вариант рекомендуется использовать только для корпоративных развертываний, где компьютеры управляются администраторами, а все необходимое программное обеспечение для работы со смарт-картами, используемыми на предприятии, устанавливается с помощью средств управления программным обеспечением, таких как SMS.

Эта процедура не рекомендуется выполнять в следующих средах, так как она повлияет на все смарт-карты в вашей среде:

  • Коммерческие развертывания, предназначенные для конечных пользователей, например онлайн-банкинг.
  • Среды, включающие как Plug and Play смарт-карты, так и не Plug and Play смарт-карты, которые используют групповая политика для отключения Plug and Play для смарт-карт.

Plug and Play смарт-карт можно отключить на предприятиях, где компьютером конечного пользователя управляют такие механизмы, как групповая политика.

Если в развертывании используются только решения, не Plug and Play смарт-карта, Plug and Play смарт-карты может быть отключена локальным администратором на клиентском компьютере. Отключение смарт-карт Plug and Play предотвращает скачивание драйверов смарт-карта, также известных как смарт-карта мини-отвертки. Он также предотвращает запросы смарт-карт Plug and Play.

Чтобы отключить Plug and Play смарт-карт в локальной групповая политика, выполните следующие действия.

  1. Нажмите кнопку Пуск, введите gpedit.msc в поле Поиск программ и файлов и нажмите клавишу ВВОД.

  2. В дереве консоли в разделе Конфигурация компьютера щелкните Административные шаблоны.

  3. В области сведений дважды щелкните Компоненты Windows, а затем дважды щелкните Смарт-карта.

  4. Щелкните правой кнопкой мыши Включить смарт-карту Plug and Play службе и выберите команду Изменить.

  5. Щелкните Отключено, а затем нажмите кнопку ОК.

Изменение системы пользователя и отключение Plug and Play смарт-карт для определенных карт

Это наименее рекомендуемый вариант. Этот параметр следует использовать только в том случае, если карточки являются устаревшими и в будущем не планируется реализовать смарт-карта мини-отвертки. Для этого параметра требуется, чтобы существующее программное обеспечение, которое уже установлено в системе, уведомляло Windows о том, что в системе установлен пользовательский поставщик служб CSP, даже если в системе конечного пользователя такого поставщика служб не существует. Как только Windows определит, что в системе уже установлен пользовательский поставщик служб CSP, Windows не пытается скачать и установить драйвер через смарт-карту Plug and Play. Узел устройства смарт-карта, видимый в диспетчер устройств, не создается. Этот параметр приводит к следующим изменениям системного реестра:

Подраздел: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\<Smart card name>

Записи реестра подразделов:

  • ATR=Шестнадцатеричное DWORD: ATR с разделителями-запятыми смарт-карта.

  • ATRMask= Hexadecimal DWORD: маска с разделителями-запятыми для применения к ATR для маскирования незначительных байтов в ATR.

  • Crypto Provider=String value: некоторые строки, относящиеся к смарт-карта.

Например:

Подраздел: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\Fabrikam ATM card

Записи реестра подразделов:

  • ATR=Шестнадцатеричное DWORD: 3b,dc,13,00,40,3a,49,54,47,5f,4d,53,43,50,5f,56,32
  • ATRMask= Шестнадцатеричное 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

Для 64-разрядных систем идентичные изменения должны быть внесены в следующем подразделе: HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Cryptography\Calais\SmartCards

Вместо непосредственного изменения системного реестра рекомендуется использовать API WinSCard для внесения этих изменений в систему. Ниже приведен пример кода, который обнаруживает вставку смарт-карта, а затем отключает Plug and Play смарт-карт для конкретного карта путем создания записи реестра, которая связывает карта с несуществующим поставщиком.

Корпорация Майкрософт предоставляет примеры программирования только в целях демонстрации без явной или подразумеваемой гарантии. Данное положение включает, но не ограничивается этим, подразумеваемые гарантии товарной пригодности или соответствия отдельной задаче. Эта статья предполагает, что пользователь знаком с представленным языком программирования и средствами, используемыми для создания и отладки процедур. Инженеры службы поддержки Майкрософт могут объяснить функциональность отдельной процедуры. обязаны изменять примеры для реализации дополнительных возможностей или удовлетворения требований конкретных пользователей.

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

Ссылки

Дополнительные сведения об устранении неполадок со смарт-карта Plug and Play см. в руководстве по устранению неполадок со смарт-картами.

Сбор данных

Если вам нужна помощь службы поддержки Microsoft, мы рекомендуем собирать информацию путем выполнения действий, описанных в разделе Сбор информации с помощью TSS для решения проблем, связанных с развертыванием.