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

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

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

現象

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

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

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

このエラー メッセージは数秒後に消えます。

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

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

  1. Windows ログに記録されたスマート カード ミニドライバー。
  2. スマート カード用のカスタム暗号化サービス プロバイダー (CSP)。
  3. Windows のロゴなしスマート カード ミニドライバー。
  4. ActiveX コントロール、PKCS#11 ソフトウェア、またはその他のカスタム ソフトウェアなどのその他のミドルウェア。

ただし、このリストの項目 3 または 4 のみがユーザーに提供されている場合、スマート カードは引き続きシステムで動作します。 ただし、ユーザーはスマート カードを挿入するたびに、このセクションで説明されているエラー メッセージを受け取ります。

この問題は、Windows 7、Windows Server 2008 R2、および両方のオペレーティング システムのそれ以降のバージョンのすべてのリリースに影響します。

原因

すべてのスマート カードでは、ユーザーが追加のソフトウェアをインストールせずにカードを使用できる受信トレイ ドライバーがない限り、Windows で動作するために追加のソフトウェアが必要です。 Windows 7 の Windows スマート カード フレームワークは、スマート カードがリーダーに挿入されたときに、Windows Updateまたは WSUS サーバーなどの他の同様の場所からスマート カード ミニドライバーを自動的にダウンロードできるように改善されました。 Windows ロゴ プログラムによって発行されたロゴ要件を正常に満たすスマート カードはすべて、この機能の恩恵を受けます。

ただし、Windows でスマート カードを使用するために必要なソフトウェアがロゴ化されていないか、PKCS#11 ドライバー、カスタム CSP、ミドルウェア、ActiveX コントロールなどのミニドライバーとは異なる種類の場合、Microsoft はスマート カード ミニドライバーのみを認定しているため、自動ダウンロード オプションは失敗します。 そのため、ユーザーがカスタム CSP がまだ登録されていないカードを挿入した場合、ユーザーは、カスタム インストールからユーザーのコンピューターにインストールされた追加のソフトウェアを使用してスマート カードを使用できる場合でも、スマート カード デバイスのドライバー ソフトウェアが見つからないことを示すエラー メッセージを受け取ります。

解決方法

スマート カードは、ユーザーに表示されるエラー メッセージにもかかわらず引き続き機能しますが、スマート カード発行者、ベンダー、または製造元は、次のいずれかの方法を使用してこのエラーを解決できます。

スマート カード ミニドライバーを実装する

カード発行者、ベンダー、製造元がスマート カード ミニドライバーを実装し、Windows ロゴ プログラムに参加して、スマート カード プラグ アンド プレイ、スマート カード用デバイス ステージなどのプラットフォームで導入された機能強化の恩恵を受けるようお勧めします。

スマート カードの NULL ドライバーを実装する

カスタム ソフトウェア (PKCS#11 ドライバー、ActiveX コントロール、またはその他のミドルウェア) が Windows でスマート カードの使用を有効にする必要があり、スマート カード ミニドライバーまたはカスタム CSP の実装が実用的でない場合は、発行者、ベンダー、または製造元カード、NULL ドライバーをWindows Updateに提出することを検討することをお勧めします。 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 などのソフトウェア管理ツールを使用してインストールされているエンタープライズ展開にのみ推奨されます。

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

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

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

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

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

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

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

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

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

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

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

これは最も推奨されるオプションです。 このオプションは、カードがレガシ カードであり、今後スマート カード ミニドライバーを実装する予定がない場合にのみ使用する必要があります。 このオプションでは、システムに既にインストールされている既存のソフトウェアが、エンド ユーザー システムにこのような CSP が存在しない場合でも、システムにカスタム CSP がインストールされていることを Windows に通知する必要があります。 Windows がカスタム CSP が既にシステムにインストールされていると判断するとすぐに、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,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;
}

関連情報

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

データ収集

Microsoft サポートの支援が必要な場合は、「展開関連の問題について TSS を使用して情報を収集する」に記載している手順に従って情報を収集することをお勧めします。