リーダーにスマート カードを挿入するとエラー メッセージ:デバイス ドライバー ソフトウェアが正常にインストールされませんでした

この記事では、リーダーにスマート カードを挿入するときに発生するエラーに対する解決策を提供します。

適用対象:  Windows 7 Service Pack 1, Windows Server 2012 R2
元の KB 番号:   976832

現象

スマート カード リーダーにスマート カードを挿入すると、Windowsプラグ アンド プレイ サービスを通じて、カードのスマート カード ミニドライバーをダウンロードしてインストールします。 スマート カードのドライバーが、Windows Update、WSUS、イントラネット パスなどの構成済みの場所で使用できない場合、カスタムの Crypto サービス プロバイダーがシステムにまだインストールされていない場合は、通知領域に次のエラー メッセージが表示されます。

デバイス ドライバー ソフトウェアが正常にインストールされませんでした

詳細については、ここをクリックしてください。

このエラー メッセージは数秒後に表示されなくなります。

さらに、デバイス マネージャーの [その他のデバイス] で、スマート カード デバイスの状態が DNF (ドライバーが見つかりません)。

多くの場合、このエラーを解決するには、スマート カード発行者から次のいずれかの項目を取得する必要があります。

  1. ログWindowsスマート カード ミニドライバー。
  2. スマート カード用のカスタム暗号化サービス プロバイダー (CSP)。
  3. ロゴWindowsスマート カード ミニドライバーの 1 つ。
  4. その他のミドルウェア (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 でスマート カードの使用を有効にし、スマート カード ミニドライバーまたはカスタム CSP を実装するために、このような PKCS#11 ドライバー、ActiveX コントロール、または他のミドルウェアなどのカスタム ソフトウェアが必要な場合は、カード発行者、ベンダー、または製造元が NULL ドライバーを Windows Update に提出することを検討することをお勧めします。 更新プログラムで NULL ドライバーを確実に使用するには、winqual Windows未分類デバイスの送信が成功する必要があります。 将来、これらのカードに使用できるミニドライバーがある場合は、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 などのソフトウェア管理ツールを使用してインストールされるエンタープライズ展開にのみ推奨されます。

この手順は、環境内のすべてのスマート カードに影響を与えるので、次の環境では推奨されません。

  • オンライン バンキングなど、エンドユーザーを対象とする商用展開。
  • プラグ アンド プレイ スマート カードと、スマート カードのプラグ アンド プレイを無効にするグループ ポリシーを使用するプラグ アンド プレイ以外のスマート カードの両方を含む環境。

スマート カード プラグ アンド プレイは、エンド ユーザーのコンピューターがグループ ポリシーなどのメカニズムによって管理されている企業では無効にできます。

展開でプラグ アンド プレイ以外のスマート カード ソリューションのみを使用している場合は、クライアント コンピューター上のローカル管理者がスマート カード プラグ アンド プレイを無効にすることができます。 スマート カード プラグ アンド プレイを無効にすると、スマート カード ドライバー (スマート カード ミニドライバーとも呼ばれる) がダウンロードされなくる。 また、スマート カードのプラグ アンド プレイのプロンプトも表示されます。

ローカル グループ ポリシーでスマート カード プラグ アンド プレイを無効にするには、次の手順を実行します。

  1. [ スタート] ボタンをクリックし、[プログラムとファイルの検索] ボックスに「gpedit.msc」と 入力 し、Enter キーを押します。

  2. [コンピューターの構成] の下 のコンソール ツリーで、[ 管理 用テンプレート] をクリックします

  3. 詳細ウィンドウで、[コンポーネント] をWindows 、[スマート カード] を ダブルクリックします

  4. [スマート カード プラグ アンド プレイ サービスを有効にする] を右クリックし、[編集] を クリックします

  5. [無効 ] を クリックし 、[OK] をクリックします

エンド ユーザーのシステムを変更し、特定のカードのスマート カード プラグ アンド プレイを無効にする

これは、推奨される最も少ないオプションです。 このオプションは、カードが従来のカードであり、将来スマート カード ミニドライバーを実装する予定がない場合にのみ使用する必要があります。 このオプションでは、システムに既にインストールされている既存のソフトウェアが、エンド ユーザー システムにそのような CSP が存在しない場合でも、システムにカスタム CSP がインストールされていることを Windows に通知する必要があります。 カスタム CSP Windowsがシステムに既にインストールされていることを確認すると、Windows はスマート カード プラグ アンド プレイを通じてドライバーをダウンロードしてインストールしようとはしない。 デバイス マネージャーに表示されるスマート カード デバイスのデバイス ノードは作成されません。 このオプションを選択すると、システム レジストリに次の変更が加わります。

サブキー: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\<Smart card name>

サブキー レジストリ エントリ:

  • ATR=16 進 DWORD: スマート カードのコンマ区切り ATR。

  • ATRMask= 16 進 DWORD: ATR に適用するコンマ区切りマスクを使用して、ATR 内の重要ではないバイトをマスクします。

  • Crypto Provider=String 値: スマート カードに関連する文字列。

以下に例を示します。

サブキー: 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
  • Crypto Provider=String 値: Fabrikam ATM ダミー プロバイダー

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

関連情報

スマート カードプラグ アンド プレイの問題のトラブルシューティングの詳細については 、「Smart Card Troubleshooting Guide」を参照してください