Поделиться через


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

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

Исходный номер базы знаний: 976832

Симптомы

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

Программное обеспечение драйвера устройств не было успешно установлено

Щелкните здесь, чтобы узнать больше.

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

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

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

  1. Мини-driver смарт-карты Windows зарегистрировал.
  2. Настраиваемый поставщик служб шифрования (CSP) для смарт-карты.
  3. Мини-driver для смарт-карт 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, автоматический параметр скачивания завершается ошибкой, так как корпорация Майкрософт сертифицирована только мини-накопителями смарт-карт. Таким образом, если пользователь вставляет карточку, для которой пользователь еще не зарегистрирован, пользователь получает сообщение об ошибке, которое указывает, что программное обеспечение драйвера отсутствует для устройства смарт-карты, даже если пользователь может использовать смарт-карту с помощью дополнительного программного обеспечения, установленного на компьютере пользователя из пользовательской установки.

Решение

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

Реализация мини-driver смарт-карты

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

Реализация драйвера NULL для смарт-карты

Если пользовательское программное обеспечение, например драйвер PKCS#11, элемент управления ActiveX или другое по промежуточному слоям, требуется для включения использования смарт-карты в Windows и реализации мини-драйвера смарт-карт или пользовательского CSP не является практическим вариантом, рекомендуется, чтобы издатели карт, поставщики или производители могли отправлять драйверы NULL в Обновл. Windows. Типичный процесс проверки доступности драйвера NULL в Обновл. Windows требует успешной неклассифицированной отправки устройства с помощью Winqual. Если в будущем есть мини-driver, доступный для этих карт, новый драйвер можно отправить в Обновл. 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 в примере, следуйте инструкциям в спецификации мини-накопителя смарт-карт.

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

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

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

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

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

Смарт-карта самонастраивающийся можно отключить в организациях, где компьютер конечного пользователя управляется такими механизмами, как групповая политика.

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

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

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

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

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

  4. Щелкните правой кнопкой мыши параметр "Включить самонастраивающийся смарт-карты" и нажмите кнопку "Изменить".

  5. Нажмите кнопку " Отключено" и нажмите кнопку "ОК".

Изменение системы конечного пользователя и отключение самонастраивающийся смарт-карт для определенных карт

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

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

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

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

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

  • Значение Crypto Provider=String: некоторая строка, соответствующая смарт-карте.

Например:

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

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

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

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

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

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

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

Ссылки

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

Сбор данных

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