Сообщение об ошибке при вставке смарт-карта в средство чтения: программное обеспечение драйвера устройства не было успешно установлено
В этой статье описывается решение ошибки, возникающей при вставке интеллектуального карта в средство чтения.
Применимо к: Windows Server 7 с пакетом обновления 1, Windows Server 2012 R2
Исходный номер базы знаний: 976832
Симптомы
При вставке смарт-карта в средство чтения смарт-карта Windows пытается скачать и установить мини-накопители smart карта для карта с помощью служб Plug and Play. Если драйвер для интеллектуальной карта недоступен ни в одном из предварительно настроенных расположений, таких как клиентский компонент Центра обновления Windows, WSUS или пути интрасети, а пользовательский поставщик служб шифрования еще не установлен в системе, в области уведомлений появляется следующее сообщение об ошибке:
Не удалось установить программное обеспечение драйвера устройства
Дополнительные сведения см. здесь.
Это сообщение об ошибке исчезает через несколько секунд.
Кроме того, в диспетчер устройств в разделе Другие устройства устройство смарт-карты имеет состояние DNF (драйвер не найден).
Для устранения этой ошибки пользователю часто требуется получить один из следующих элементов от издателя смарт-карта:
- Смарт-карта мини-driver в Системе Windows.
- Настраиваемый поставщик служб шифрования (CSP) для Smart карта.
- Смарт-карта minidriver с windows без логотипа.
- Другое ПО промежуточного слоя, например элемент управления 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 смарт-карт в локальной групповая политика, выполните следующие действия.
Нажмите кнопку Пуск, введите gpedit.msc в поле Поиск программ и файлов и нажмите клавишу ВВОД.
В дереве консоли в разделе Конфигурация компьютера щелкните Административные шаблоны.
В области сведений дважды щелкните Компоненты Windows, а затем дважды щелкните Смарт-карта.
Щелкните правой кнопкой мыши Включить смарт-карту Plug and Play службе и выберите команду Изменить.
Щелкните Отключено, а затем нажмите кнопку ОК.
Изменение системы пользователя и отключение 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 для решения проблем, связанных с развертыванием.
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по