スマート カードをリーダーに挿入するときのエラー メッセージ: デバイス ドライバー ソフトウェアが正常にインストールされませんでした
この記事では、リーダーにスマート カードを挿入するときに発生するエラーの解決策について説明します。
元の KB 番号: 976832
現象
スマート カード リーダーにスマート カードを挿入すると、Windows は、プラグ アンド プレイ サービスを通じてカードのスマート カード ミニドライバーをダウンロードしてインストールしようとします。 Windows Update、WSUS、イントラネット パスなどの構成済みの場所でスマート カードのドライバーを使用できない場合、カスタム暗号化サービス プロバイダーがまだシステムにインストールされていない場合は、通知領域に次のエラー メッセージが表示されます。
デバイス ドライバー ソフトウェアが正常にインストールされませんでした
詳細については、こちらをクリックしてください。
このエラー メッセージは、数秒後に消えます。
さらに、デバイス マネージャーでは、その他のデバイスのスマート カード デバイスの状態は DNF (ドライバーが見つかりません)。
このエラーを解決するには、多くの場合、ユーザーがスマート カード発行者から次のいずれかの項目を取得する必要があります。
- Windows ログに記録されたスマート カード ミニドライバー。
- スマート カード用のカスタム暗号化サービス プロバイダー (CSP)。
- Windows のロゴなしスマート カード ミニドライバー。
- ActiveX コントロール、PKCS#11 ソフトウェア、その他のカスタム ソフトウェアなどのその他のミドルウェア。
ただし、このリストの項目 3 または 4 のみがユーザーに提供されている場合、スマート カードはシステム上で引き続き動作します。 ただし、ユーザーはスマート カードを挿入するたびに、このセクションに記載されているエラー メッセージを受け取ります。
この問題は、Windows 7、Windows Server 2008 R2、および両方のオペレーティング システムの以降のバージョンのすべてのリリースに影響します。
原因
ユーザーが追加のソフトウェアをインストールせずにカードを使用できる受信トレイ ドライバーがない限り、すべてのスマート カードには Windows で動作する追加のソフトウェアが必要です。 Windows スマート カード フレームワークが Windows 7 で改善され、スマート カードがリーダーに挿入されたときに、Windows Update または WSUS サーバーなどの他の同様の場所からスマート カード ミニドライバーを自動的にダウンロードできるようになりました。 Windows ロゴ プログラムによって公開されたロゴ要件を正常に満たすスマート カードはすべて、この機能の恩恵を受けます。
ただし、Windows でスマート カードを使用するために必要なソフトウェアがロゴ付きではない場合や、PKCS#11 ドライバー、カスタム CSP、ミドルウェア、ActiveX コントロールなどのミニドライバーとは異なる種類の場合、Microsoft はスマート カード ミニドライバーのみを認定しているため、自動ダウンロード オプションは失敗します。 そのため、ユーザーがカスタム CSP がまだ登録されていないカードを挿入すると、ユーザーは、カスタム インストールからユーザーのコンピューターにインストールされた追加のソフトウェアを使用してスマート カードを使用できる場合でも、スマート カード デバイスのドライバー ソフトウェアが不足していることを示すエラー メッセージを受け取ります。
解決方法
ユーザーに表示されるエラー メッセージにもかかわらず、スマート カードは引き続き機能しますが、スマート カードの発行者、ベンダー、または製造元は、次のいずれかの方法を使用してこのエラーを解決できます。
スマート カード ミニドライバーを実装する
カード発行者、ベンダー、製造元はスマート カード ミニドライバーを実装し、Windows ロゴ プログラムに参加して、スマート カード プラグ アンド プレイ、スマート カードのデバイス ステージなどのプラットフォームで導入された機能強化の恩恵を受けることをお勧めします。
スマート カードの NULL ドライバーを実装する
Windows でスマート カードの使用を有効にするために PKCS#11 ドライバー、ActiveX コントロール、またはその他のミドルウェアなどのカスタム ソフトウェアが必要であり、スマート カード ミニドライバーまたはカスタム CSP の実装が実用的なオプションでない場合は、カード発行者、ベンダー、または製造元が WINDOWS Update に NULL ドライバーを提出することを検討することをお勧めします。 Windows Update で NULL ドライバーが使用できることを確認する一般的なプロセスでは、Winqual を介して未分類のデバイスの送信が成功する必要があります。 今後、これらのカードに使用できるミニドライバーがある場合は、Windows ロゴ プログラムに参加することで、新しいドライバーを Windows Update にアップロードできます。 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文字列によって参照されるハードウェア デバイス ID を生成するには、スマート カード ミニドライバーの仕様の指示に従います。
NULL ドライバーを Microsoft に送信する方法の詳細については、Microsoft カスタマー サポート サービスにお問い合わせください。
マネージド コンピューターのグループ ポリシーを使用してスマート カードのプラグ アンド プレイを無効にする
このオプションは、コンピューターが管理者によって管理され、企業で使用されているスマート カードを操作するために必要なすべてのソフトウェアが SMS などのソフトウェア管理ツールを使用してインストールされるエンタープライズ展開にのみ推奨されます。
この手順は、環境内のすべてのスマート カードに影響するため、次の環境では推奨されません。
- オンライン バンキングなど、エンド ユーザーを対象とする商用デプロイ。
- プラグ アンド プレイ スマート カードと、グループ ポリシーを使用してスマート カードのプラグ アンド プレイを無効にする非プラグ アンド プレイ スマート カードの両方を含む環境。
スマート カード プラグ アンド プレイは、エンド ユーザーのコンピューターがグループ ポリシーなどのメカニズムによって管理されている企業で無効にすることができます。
展開でプラグ アンド プレイ以外のスマート カード ソリューションのみを使用している場合は、クライアント コンピューターのローカル管理者がスマート カード プラグ アンド プレイを無効にすることができます。 スマート カード プラグ アンド プレイを無効にすると、スマート カード ドライバー (スマート カード ミニドライバーとも呼ばれます) がダウンロードできなくなります。 また、スマート カードのプラグ アンド プレイプロンプトも防止されます。
ローカル グループ ポリシーでスマート カードのプラグ アンド プレイを無効にするには、次の手順に従います。
[ Startをクリックし、[プログラムとファイルの検索 ] ボックスに「gpedit.msc」と入力し Enter キーを押します。
コンソール ツリーの Computer Configuration で、[Administrative Templates をクリック。
詳細ウィンドウで、 Windows コンポーネントをダブルクリックし、 スマート カードをダブルクリックします。
[スマート カード プラグ アンド プレイ サービスで表示] を右クリックし[編集] をクリック。
[ Disabled] をクリックし、[ OK] をクリックします。
エンド ユーザーのシステムを変更し、特定のカードのスマート カード プラグ アンド プレイを無効にする
これは最も推奨されるオプションです。 このオプションは、カードがレガシ カードであり、今後スマート カード ミニドライバーを実装する予定がない場合にのみ使用する必要があります。 このオプションでは、システムに既にインストールされている既存のソフトウェアが、エンド ユーザー システムにこのような CSP が存在しない場合でも、システムにカスタム CSP がインストールされていることを Windows に通知する必要があります。 Windows は、システムにカスタム CSP が既にインストールされていると判断するとすぐに、スマート カード プラグ アンド プレイを使用してドライバーをダウンロードしてインストールしようとしません。 デバイス マネージャーに表示されるスマート カード デバイスのデバイス ノードは作成されません。 このオプションにより、システム レジストリが次のように変更されます。
サブキー: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\<Smart card name>
サブキー レジストリ エントリ:
ATR=16 進数 DWORD: スマート カードのコンマ区切り ATR。
ATRMask= 16 進数 DWORD: ATR 内の重要でないバイトをマスクするために ATR に適用するコンマ区切りマスク。
Crypto Provider=String value: スマート カードに関連するいくつかの文字列。
例えば次が挙げられます。
サブキー: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\Fabrikam ATM card
サブキー レジストリ エントリ:
- ATR=16 進数 DWORD: 3b,dc,13,00,40,3a,49,54,47,5f,4d,53,43,53,50,5f,56,32
- ATRMask= 16 進数 DWORD: 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
x64 ビット システムの場合は、次のサブキーで同じ変更を行う必要があります。 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Cryptography\Calais\SmartCards
システム レジストリを直接変更する代わりに、WinSCard API を使用してこれらの変更をシステムに導入することをお勧めします。 ここでは、スマート カードの挿入を検出し、カードを既存のプロバイダーに関連付けるレジストリ エントリを作成して、特定のカードのスマート カードのプラグ アンド プレイを無効にするサンプル コード例を示します。
Microsoft は、例示のみを目的としてプログラミング例を提供しており、明示または黙示にかかわらず、いかなる責任も負わないものとします。 これには、市販性または特定の目的との適合性についての黙示の保証も含まれますが、これに限定はされません。 この記事は、説明されているプログラミング言語、手順を作成およびデバッグするために使用されているツールに読者が精通していることを前提にしています。 Microsoft サポート エンジニアは、特定の手順の機能を説明するのに役立ちます。 ただし、これらの例を変更して、特定の要件を満たす追加の機能を提供したり、プロシージャを構築したりしません。
//==============================================================;
//
// 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 を使用して情報を収集する」に記載している手順に従って情報を収集することをお勧めします。