Windows 7 기반 또는 Windows Server 2008 R2 기반 컴퓨터에서 판독기에서 스마트 카드를 삽입할 때 오류 메시지: "장치 드라이버 소프트웨어가 성공적으로 설치되지 않은"

기술 자료 번역 기술 자료 번역
기술 자료: 976832 - 이 문서가 적용되는 제품 보기.
모두 확대 | 모두 축소

이 페이지에서

현상

스마트 카드 판독기에 스마트 카드를 삽입하면 Windows 다운로드 및 설치 PnP 서비스를 통해 카드 스마트 카드 minidrivers 시도합니다. Windows 업데이트, WSUS, 또는 인트라넷 경로 같은 미리 구성된 위치를 때 스마트 카드 드라이버를 사용할 수 없는 사용자 지정 암호화 서비스 공급자가 시스템에 이미 설치된 경우, 알림 영역에 다음과 같은 오류 메시지가 나타납니다.
장치 드라이버 소프트웨어가 제대로 설치되지 않았습니다.
자세한 내용은 여기를 클릭하십시오.
이 오류 메시지가 몇 초 후에 사라집니다.

또한 장치 관리자에서 기타 장치 아래에 스마트 카드 장치 상태를 "DNF" 드라이버 찾을 수 있습니다.

다음 항목 중 하나를 이 오류를 해결하려면 스마트 카드 발급자로부터 얻기 위해 사용자가 자주 필요합니다.
  1. Windows 스마트 카드 logoed minidriver
  2. 사용자 지정 암호화 서비스 공급자 (CSP) 스마트 카드.
  3. Windows 스마트 카드 logoed 않은 minidriver
  4. ActiveX 컨트롤, PKCS # 11 소프트웨어 또는 다른 사용자 지정 소프트웨어 같은 다른 미들웨어.
그러나 사용자가 3 또는 4이 이 목록에 있는 항목만 함께 제공되는 경우, 스마트 카드를 시스템에 계속 작동합니다. 그러나 사용자가 스마트 카드를 삽입할 때마다가 이 절에서 설명한 오류 메시지가 나타납니다.

이 문제는 Windows 7, Windows Server 2008 R2 이상에서 두 운영 체제의 릴리스를 모두 영향을 줍니다.

원인

모든 스마트 카드를 경우가 아니라면 사용자가 추가 소프트웨어를 설치하지 않고 카드를 사용할 수 있도록 제공 드라이버를 Windows의 작동하도록 추가 소프트웨어가 필요합니다. Windows 스마트 카드 프레임워크 스마트 카드 판독기에 넣으면 자동 스마트 카드 minidrivers Windows Update 또는 WSUS 서버와 같은 다른 유사한 위치에서 다운로드할 수 있도록 Windows 7 에서 향상된 않았습니다. 성공적으로 Windows 로고 프로그램에 의해 게시된 로고 요구 사항을 전달할 모든 스마트 카드는 이 기능을 활용할 수 있습니다.

그러나 Windows에서 스마트 카드를 사용하는 데 필요한 소프트웨어 logoed 또는 minidriver, PKCS # 11 드라이버, 사용자 지정 CSP, 미들웨어, ActiveX 컨트롤 등의 다른 형식인 경우 유일한 스마트 카드 minidrivers Microsoft 있도록 인증합니다 때문에 자동 다운로드 옵션을 실패합니다. 따라서 사용자는 기본값만 카드에 없는 사용자 지정 CSP 이미 등록되어 있지 않으면, 사용자가 사용자 지정 설치를 통해 사용자 컴퓨터에 설치된 추가 소프트웨어를 통해 스마트 카드를 사용할 수 있지만 드라이버 소프트웨어를 스마트 카드 장치의 누락된 내용의 오류 메시지가 받습니다.

해결 방법

스마트 카드를 불구하고 사용자에게 표시되는 오류 메시지가 계속 사용할 수 있지만, 스마트 카드 발급자, 공급업체 또는 제조업체에 다음 방법 중 하나를 이 오류를 해결할 수 있습니다.

스마트 카드 minidriver 구현

카드 발급자, 공급업체 및 제조업체에서 스마트 카드 minidrivers 구현 및 스마트카드 플러그 앤 플레이 스마트 카드 장치 단계 같은 플랫폼이 도입된 향상된 기능을 활용할 수 있는 Windows 로고 프로그램의 참여할 좋습니다 있습니다.

Windows 스마트 카드 minidriver 사양에 대한 자세한 내용은 다음 Microsoft 웹 사이트를 방문하십시오.
http://www.microsoft.com/whdc/device/input/smartcard/sc-minidriver.mspx
스마트 카드 minidrivers 로고 얻는 프로세스를 시작하는 방법에 대한 자세한 내용은 다음 Windows 로고 프로그램 웹 사이트를 방문하십시오.
http://www.microsoft.com/whdc/winlogo/default.mspx

NULL 드라이버를 스마트 카드 구현

사용자 지정 소프트웨어 PKCS # 11 드라이버, ActiveX 컨트롤 또는 기타 미들웨어 Windows, 스마트 카드를 사용할 수 있도록 필요한 스마트 카드 minidriver 또는 사용자 지정 CSP 구현 실용적인 옵션이 아닌 경우 카드 발급자, 공급업체 또는 제조업체는 NULL 드라이버를 Windows Update 제출하는 고려하는 것이 좋습니다. Winqual 통해 성공적인 구분되지 않은 장치 제출을 일반적인 프로세스에 대해 NULL 드라이버를 Windows Update를 사용할 수 있는지 확인해야 합니다. 앞으로 있을 경우, minidriver 이러한 카드를 사용할 수, 새 드라이버가 Windows 로고 프로그램에 참여하는 Windows Update와 업로드할 수 있습니다. 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를 생성하기 위해 스마트 카드 minidriver 사양을 지시를 따릅니다. 이렇게 하려면 다음 Microsoft 웹 사이트를 방문하십시오.
http://www.microsoft.com/whdc/device/input/smartcard/sc-minidriver.mspx


NULL 드라이버를 Microsoft에 제출하는 방법에 대한 자세한 내용은 Microsoft 고객기술지원부에 문의하십시오.

관리되는 컴퓨터에 대한 그룹 정책을 통해 스마트카드 플러그 앤 플레이 사용 안 함

이 옵션은 관리자 및 SMS와 같은 소프트웨어 관리 도구를 사용하여 기업에서 사용되는 스마트 카드와 함께 작동하도록 필요한 소프트웨어가 설치된 모든 컴퓨터는 관리되는 엔터프라이즈 배포를 사용하는 것이 좋습니다.

사용자 환경의 모든 스마트 카드를 영향을 주므로 이 절차를 다음과 같은 환경에서 좋습니다.
  • 온라인 뱅킹 등 최종 사용자를 대상으로 상용 배포
  • 둘 다 포함할 환경에서 플러그 앤 플러그 앤 플레이 스마트 카드 사용 안 함 그룹 정책을 사용하여 비 플러그 앤 플레이 스마트 카드 및 스마트 카드 플레이
최종 사용자의 컴퓨터에 그룹 정책 같은 메커니즘을 통해 관리되는 기업에서 스마트카드 PnP 완전히 비활성화할 수 있습니다.

비 플러그 앤 플레이 스마트 카드 솔루션 배포를 사용하는 경우 클라이언트 컴퓨터에서 로컬 관리자에 의해 스마트카드 PnP 해제할 수 있습니다. 플러그 앤 플레이 스마트 카드 사용 안 함 (스마트 카드 minidrivers 스마트 카드 드라이버를 다운로드할 수 없습니다. 또한 스마트 카드 PnP 프롬프트를 방지할 수 있습니다.

로컬 그룹 정책에서 플러그 앤 플레이 스마트 카드 사용하지 않도록 설정하려면 다음 이 단계를 수행하십시오.
  1. 시작 을 누르고, gpedit.msc검색 프로그램 및 파일 상자에 입력한 다음 Enter 키를 누릅니다.
  2. 콘솔 트리의 컴퓨터 구성에서관리 템플릿 을 클릭하십시오.
  3. 세부 정보 창에서 Windows 구성 요소, 두 번 클릭한 다음 스마트 카드 두 번 클릭하십시오.
  4. 스마트 카드 플러그 앤 플레이 서비스 사용 을 마우스 오른쪽 단추로 클릭한 다음 편집 을 클릭하십시오.
  5. 사용 안 함 을 클릭한 다음 확인 을 클릭하십시오.

최종 사용자의 시스템 변경하고 특정 카드에 대한 플러그 앤 플레이 스마트 카드 사용 안 함

이 옵션은 최소 권장 옵션입니다. 레거시 카드를 카드입니다 향후 스마트 카드 minidrivers 구현할 계획이 없습니다 경우 이 옵션을 사용해야 합니다. 이 옵션은 시스템에 이미 설치된 기존 소프트웨어 최종 사용자 시스템에 이러한 CSP 존재하는 경우에도 시스템에 설치된 사용자 지정 CSP가 Windows에서 알려 필요합니다. Windows 시스템에 이미 설치된 사용자 지정 CSP 결정합니다 즉시 다운로드 및 스마트카드 PnP 통해 드라이버를 설치할 Windows 시도하지 않습니다. 스마트 카드 장치의 장치 노드가 장치 관리자에 표시되는 만들어집니다. 이 옵션은 시스템 레지스트리에 다음 변경 내용을 결과:

하위 키:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\<Smart card name>
레지스트리 항목을 하위 키:
  • ATR 16진수 DWORD =: 스마트 카드 ATR 쉼표로 구분됩니다.
  • ATRMask 16진수 DWORD =: 해당 ATR 의미 없는 바이트 out 마스크와 ATR 적용하려면 마스크 쉼표로 구분된.
  • 암호화 공급자 = 문자열 값: 스마트 카드의 관련 일부 문자열입니다.
예를 들면:
하위 키:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\Fabrikam ATM card
레지스트리 항목을 하위 키:
  • ATR 16진수 DWORD =: 3b, dc, 13, 00, 40, 3a, 49, 54, 47, 32, 4 d, 53, 43 53, 50, 5f, 56, 5f
  • ATRMask 16진수 DWORD =: ff, ff, ff, ff, ff, ff, ff, ff, ff, ff, ff, ff, ff, ff, ff, ff, ff, ff
  • 암호화 공급자 = 문자열 값: "Fabrikam ATM 더미 공급자"
x 64 비트 시스템 동일한 다음 하위 키 아래에 변경해야 합니다.
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;
}

참조

스마트 카드 PnP 문제 해결에 대한 자세한 내용은 다음 TechNet 문서를 참조하십시오.
플러그 앤 플레이 스마트 카드 문제 해결 가이드
http://technet.microsoft.com/en-us/library/dd979536(WS.10).aspx

속성

기술 자료: 976832 - 마지막 검토: 2009년 10월 23일 금요일 - 수정: 2.0
본 문서의 정보는 다음의 제품에 적용됩니다.
  • Windows Server 2008 R2 Datacenter
  • Windows Server 2008 R2 Enterprise
  • Windows Server 2008 R2 Standard
  • Windows 7 Enterprise
  • Windows 7 Home Basic
  • Windows 7 Home Premium
  • Windows 7 Professional
  • Windows 7 Starter
  • Windows 7 Ultimate
키워드:?
kbmt kbsmartcard kbcodesnippet kbtshoot kbexpertiseinter kbsurveynew kbprb KB976832 KbMtko
기계 번역된 문서
중요: 본 문서는 전문 번역가가 번역한 것이 아니라 Microsoft 기계 번역 소프트웨어로 번역한 것입니다. Microsoft는 번역가가 번역한 문서 및 기계 번역된 문서를 모두 제공하므로 Microsoft 기술 자료에 있는 모든 문서를 한글로 접할 수 있습니다. 그러나 기계 번역 문서가 항상 완벽한 것은 아닙니다. 따라서 기계 번역 문서에는 마치 외국인이 한국어로 말할 때 실수를 하는 것처럼 어휘, 구문 또는 문법에 오류가 있을 수 있습니다. Microsoft는 내용상의 오역 또는 Microsoft 고객이 이러한 오역을 사용함으로써 발생하는 부 정확성, 오류 또는 손해에 대해 책임을 지지 않습니다. Microsoft는 이러한 문제를 해결하기 위해 기계 번역 소프트웨어를 자주 업데이트하고 있습니다.

피드백 보내기

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com