Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этой статье приводится решение об ошибке, возникающей при вставке смарт-карты в средство чтения.
Исходный номер базы знаний: 976832
Симптомы
При вставке смарт-карты в средство чтения смарт-карт Windows пытается скачать и установить мини-накопители смарт-карт для карточки через службы самонастраивающийся. Если драйвер смарт-карты недоступен в любом из предварительно настроенных расположений, таких как Обновл. Windows, WSUS или пути интрасети, а настраиваемый поставщик служб шифрования еще не установлен в системе, вы получите следующее сообщение об ошибке в области уведомлений:
Программное обеспечение драйвера устройств не было успешно установлено
Щелкните здесь, чтобы узнать больше.
Это сообщение об ошибке исчезает через несколько секунд.
Кроме того, в диспетчер устройств в разделе "Другие устройства" устройство Смарт-карты имеет состояние DNF (драйвер не найден).
Это часто требует, чтобы пользователь получил один из следующих элементов из издателя смарт-карт, чтобы устранить эту ошибку:
- Мини-driver смарт-карты Windows зарегистрировал.
- Настраиваемый поставщик служб шифрования (CSP) для смарт-карты.
- Мини-driver для смарт-карт 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, автоматический параметр скачивания завершается ошибкой, так как корпорация Майкрософт сертифицирована только мини-накопителями смарт-карт. Таким образом, если пользователь вставляет карточку, для которой пользователь еще не зарегистрирован, пользователь получает сообщение об ошибке, которое указывает, что программное обеспечение драйвера отсутствует для устройства смарт-карты, даже если пользователь может использовать смарт-карту с помощью дополнительного программного обеспечения, установленного на компьютере пользователя из пользовательской установки.
Решение
Хотя смарт-карты продолжают работать, несмотря на сообщение об ошибке, которое видит пользователь, издатель смарт-карт, поставщик или производитель могут использовать один из следующих методов для устранения этой ошибки.
Реализация мини-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.
Эта процедура не рекомендуется в следующих средах, так как она влияет на все смарт-карты в вашей среде:
- Коммерческие развертывания, предназначенные для конечных пользователей, таких как интернет-банк.
- Среды, включающие как самонастраивающийся смарт-карты, так и смарт-карты без самонастраивающийся, использующие групповую политику для отключения самонастраивающийся смарт-карт.
Смарт-карта самонастраивающийся можно отключить в организациях, где компьютер конечного пользователя управляется такими механизмами, как групповая политика.
Если развертывание использует только решения смарт-карты, отличные от самонастраивающийся, самонастраивающийся смарт-карты можно отключить локальным администратором на клиентском компьютере. Отключение смарт-карты самонастраивающийся предотвращает загрузку драйверов смарт-карт, также известных как мини-накопители смарт-карт. Он также предотвращает запросы смарт-карты самонастраивающийся.
Чтобы отключить самонастраивающийся смарт-карты в локальной групповой политике, выполните следующие действия.
Нажмите кнопку "Пуск", введите gpedit.msc в поле "Поиск программ и файлов " и нажмите клавишу ВВОД.
В дереве консоли в разделе "Конфигурация компьютера" щелкните "Административные шаблоны".
В области сведений дважды щелкните компоненты Windows и дважды щелкните смарт-карту.
Щелкните правой кнопкой мыши параметр "Включить самонастраивающийся смарт-карты" и нажмите кнопку "Изменить".
Нажмите кнопку " Отключено" и нажмите кнопку "ОК".
Изменение системы конечного пользователя и отключение самонастраивающийся смарт-карт для определенных карт
Это наименее рекомендуемый вариант. Этот параметр следует использовать только в том случае, если карты являются устаревшими и в будущем не планируется реализовать мини-накопители смарт-карт. Для этого параметра требуется, чтобы существующее программное обеспечение, уже установленное в системе, уведомляло 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 для решения проблем, связанных с развертыванием.