您在基于 Windows 7 的或基于 Windows Server 2008 R2 的计算机上读取器中插入智能卡时出现错误消息:"设备驱动程序软件未能成功安装"

http://support.microsoft.com/kb/976832/zh-cn

http://support.microsoft.com/kb/976832/zh-tw

症状

当智能卡插入智能卡阅读器后时,Windows 尝试下载并安装智能卡 minidrivers 通过插服务卡。如果自定义的加密服务提供程序未在系统上安装智能卡的驱动程序在任一预配置位置,如 Windows 更新、 WSUS 或 intranet 路径不可用,在通知区域中将收到以下错误消息:

未能成功安装设备驱动程序软件
有关详细信息,请单击此处。

此错误消息在几秒钟后就会消失。

另外,设备管理器中,在其他设备下的智能卡设备的"DNF"(没有找到驱动程序) 的状态。

这通常需要用户从智能卡颁发者若要解决此错误获得以下各项之一:

  1. Windows logoed 智能卡微型驱动程序
  2. 智能卡自定义的加密服务提供程序 (CSP)。
  3. Windows 非 logoed 智能卡微型驱动程序
  4. 其他如 ActiveX 控件、 PKCS #11 软件或其他自定义软件的中间件。

但是,如果用户提供唯一 3 或 4,从该列表中的项,智能卡会继续在系统正常工作。但是,该用户将收到错误消息中提到这一节每次它们插入智能卡。

此问题影响到所有版本的 Windows 7 中,Windows Server 2008 R2,和更高版本的这两个操作系统。

原因

所有智能卡都需要附加软件才能在 Windows 中工作,除非有一个收件箱驱动程序,允许用户无需安装其他软件使用的卡。在 Windows 7 中以启用自动下载智能卡 minidrivers 从 Windows Update 或其他类似的位置,如一个 WSUS 服务器,智能卡插入到阅读器时,Windows 智能卡框架已经过改进。所有成功通过徽标要求,通过 Windows 徽标计划,发布的智能卡从该功能中受益。

但是,如果在 Windows 中使用智能卡所需的软件不是 logoed 或者是微型驱动程序,例如 PKCS #11 驱动程序、 自定义的 CSP、 中间件或一个 ActiveX 控件,与不同类型的自动下载选项失败因为 Microsoft 认证只智能卡 minidrivers。因此,如果在用户插入的卡为其自定义 CSP 没有注册,用户会收到一条错误消息,指出尽管用户可以使用智能卡上通过自定义安装从用户的计算机已安装的其他软件是丢失的智能卡设备的驱动程序软件。

解决方案

尽管智能卡继续忽略用户可以看到此错误消息的工作,智能卡颁发者、 供应商或制造商可以使用以下方法之一来纠正此错误。

实施智能卡的微型驱动程序

我们建议卡颁发者、 供应商和制造商实施智能卡 minidrivers,并加入 Windows 徽标计划从中受益 (如智能卡插,智能卡设备贴图层平台中引入了改进,等等。

有关智能卡用于 Windows 的微型驱动程序规范的详细信息,请访问下面的 Microsoft Web 站点:

http://www.microsoft.com/whdc/device/input/smartcard/sc-minidriver.mspx

有关如何开始使用获取您的智能卡 minidrivers 的徽标的过程的详细信息,请访问下面的 Windows 徽标计划 Web 站点:

http://www.microsoft.com/whdc/winlogo/default.mspx

实现您的智能卡的空驱动程序

如果自定义软件 (这些 PKCS #11 驱动程序、 ActiveX 控件或一些其他中间件是需要能够在 Windows 中,智能卡的使用和实施智能卡的微型驱动程序或自定义的 CSP 不是可行的办法,我们建议卡颁发者、 供应商或制造商应考虑提交空到 Windows 更新的驱动程序。确保空驱动程序在 Windows Update 上可用的典型过程需要通过 Winqual 的成功未分类的设备提交。如果将来,没有可供这些卡的微型驱动程序,可以通过 Windows 徽标计划加入到 Windows Update 上载新的驱动程序。空的驱动程序之后可以由最终用户手动下载,或可通过使用可选更新可用。

下面是空的智能卡的驱动程序的一个示例模板。

;
; 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,请按照中微型驱动程序智能卡的技术指标的说明进行操作。若要执行此操作,请访问下面的 Microsoft 网站:

http://www.microsoft.com/whdc/device/input/smartcard/sc-minidriver.mspx

有关如何提交到 Microsoft 的空驱动程序的详细信息,请与 Microsoft 客户支持服务联系。

禁用智能卡通过组策略的插被管理的计算机

此选项仅对管理员和所有必要的软件以使用企业中正在使用智能卡使用安装的软件管理工具 (如 SMS),管理计算机的企业部署建议。

因为这将影响您的环境中的所有智能卡,此过程是强烈建议您不要在以下环境中:

  • 面向最终用户,如网上银行的商业部署
  • 包含这两个环境插智能卡和使用组策略来禁用智能卡插的非即插智能卡

可以完全禁用智能卡插在最终用户的计算机由组策略等机制的企业。

如果您的部署使用仅非即插智能卡解决方案,客户端计算机上的本地管理员可以禁用智能卡插。禁用智能卡插可以阻止智能卡的驱动程序,也称为智能卡 minidrivers,下载。它还可以防止智能卡插提示。

要禁用智能卡插在本地组策略,请执行以下步骤:

  1. 单击开始,在搜索程序和文件框中,键入gpedit.msc ,然后按 enter 键。
  2. 在控制台树中在计算机配置下,单击管理模板
  3. 在详细信息窗格中,双击Windows 组件,然后双击智能卡
  4. 请用鼠标右键单击启用智能卡插服务,然后单击编辑
  5. 单击被禁用,然后单击确定

更改的最终用户的系统和禁用智能卡插,为特定的卡

这是最推荐的选项。只有卡的旧卡并没有计划在将来实现智能卡 minidrivers,您应使用此选项。此选项要求在系统已安装的现有软件通知 Windows 没有自定义安装到系统上,即使在最终用户系统中存在任何此类 CSP CSP。只要 Windows 在确定存在一个自定义系统上已安装的 CSP,Windows 不会尝试下载并安装智能卡插到驱动程序。智能卡设备没有设备节点创建在设备管理器中可见。此选项导致对系统注册表的以下更改:

子项:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\ < 智能卡名称 >
子项的注册表项:

  • ATR = 十六进制的 dword 值: ATR 的智能卡,以逗号分隔。
  • ATRMask = 十六进制的 dword 值: 要到 ATR 在无意义的字节以遮盖 ATR 应用蒙板,以逗号分隔。
  • 加密提供程序 = 字符串值: 某些与智能卡相关的字符串。

例如:
子项:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\Fabrikam ATM 卡
子项的注册表项:

  • ATR = 十六进制的 dword 值: 3b,dc,13 00、 40,3a,49、 54、 47,5f,4d,53、 43、 53、 50,5f,56、 32
  • ATRMask = 十六进制的 dword 值: ff、 ff、 ff、 ff、 ff、 ff、 ff、 ff、 ff、 ff、 ff、 ff、 ff、 ff、 ff、 ff、 ff、 ff
  • 加密提供程序 = 字符串值:"Fabrikam ATM Dummy 提供程序"

对于 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;
}
时间: 02-09

您在基于 Windows 7 的或基于 Windows Server 2008 R2 的计算机上读取器中插入智能卡时出现错误消息:"设备驱动程序软件未能成功安装"的相关文章

Windows Server 2008 R2遗忘管理员密码后的解决方案

本文转载自:http://liulike.blog.51cto.com/1355103/295340 在日常的工作中,对于一个网络管理员来讲最悲哀的事情莫过于在没有备用管理员账户和密码恢复盘的情况下遗忘了本地管理员账户密码.在早期的系统中,遇到这种事情可以使用目前国内的很多Windows PE光盘来解决.但是,对于Windows Server 2008 R2来讲,只靠简单的这些操作是暂时无法解决密码问题的.但是,可以通过替换文件,使用变通的方法,可以在绕过登录的情况下,使用命令提示行方式,添加本

[转]无网络环境,在Windows Server 2008 R2和SQL Server 2008R2环境安装SharePoint2013 RT

无网络环境,在Windows Server 2008 R2和SQL Server 2008R2环境安装SharePoint2013 RT,这个还有点麻烦,所以记录一下,下次遇到省得绕弯路.进入正题: 首先准备好Windows Server 2008 R2,SQL Server 2008 R2,SharePoint Server 2013安装介质.密钥和补丁,补丁情况可参照下表: Product Number Description Download Address Windows Server

通过Windows Server 2008 R2建立iSCSI存储

通过Windows Server 2008 R2建立iSCSI存储 名词解释:iSCSI技术是一种由IBM公司研究开发的,是一个供硬件设备使用的可以在IP协议的上层运行的SCSI指令集,这种指令集合可以实现在IP网络上运行 SCSI协议,使其能够在诸如高速千兆以太网上进行路由选择.iSCSI技术是一种新储存技术,该技术是将现有SCSI接口与以太网络 (Ethernet)技术结合,使服务器可与使用IP网络的储存装置互相交换资料.iSCSI:Internet 小型计算机系统接口 (iSCSI:Int

Windows Server 2008 R2入门之FTP

如约奉上Windows Server 2008 R2入门之FTP.本博文目的是为了让大家更改的了解FTP:访问FTP服务:会添加.启动FTP服务. FTP服务器(FileTransfer Protocol Server)是在互联网上提供文件存储和访问服务的计算机,它们依照FTP协议提供服务. FTP是File Transfer Protocol(文件传输协议).顾名思义,就是专门用来传输文件的协议.简单地说,支持FTP协议的服务器就是FTP服务器. FTP是一种应用层协议:采用C/S结构设计,结

Windows server 2008 R2 AD DS搭建(额外DNS)

使用额外的DNS服务器搭建AD DS服务器,AD DS服务器本身不是DNS服务器. 先决条件: 1台DNS服务器,1台AD DS服务器: DNS服务器开启动态更新: 部署参考步骤如下: 1.DNS服务器信息检查 2.AD DS服务器信息检查 3.在DNS服务器上面运行dnsmgmt.msc,确定 4.右击"正向查找区域",选择"新建区域" 5.选择下一步 6.选择"主要区域" 7.输入域名"contoso.local",下一步

Windows Server 2008 R2域控组策略设置禁用USB

问题: Windows Server 2008 R2域控服务器如何禁用客户端使用USB移动存储(客户端操作系统需要 Windows Vista以上的操作系统,XP以下的操作系统不能禁用USB移动存储). 标注:对于Windows Server 2008 R2域控组策略禁用USB移动存储设备要求是客户端操作系统要求Windows Vista以上,针对 XP以下的操作系统则只能使用Windows Server 2003操作系统作为域控服务器才可以进行限制(操作方法跟windows server 20

Windows Server 2008 R2: 创建任务计划

task Scheduler 在业务复杂的应用程序中,有时候会要求一个或者多个任务在一定的时间或者一定的时间间隔内计划进行,比如定时备份或同步数据库,定时发送电子邮件等. 创建一个任务计划: 开始Start菜单,在Search programs and files中键入Task Scheduler 在Task Scheduler中,点击Task Scheduler Library,在中间窗口中可以看到所有已创建的Scheduled Tasks. 在Actions Pane中,选择Create T

Windows Server 2008 R2入门之用户管理

今天为大家带来的是Windows Server 2008 R2入门之用户管理,以便大家更快的熟悉2008r2工作组中用户.组的创建.删除.日常管理等,接下来我们直接进入正文. 一.用户账户概述: "用户"是计算机的使用者在计算机系统中的身份映射,不同的用户身份拥有不同的权限,每个用户包含一个名称和一个密码: 在Windows中,每个用户帐户有一个唯一的安全标识符(Security Identifier,SID),用户的权限是通过用户的SID记录的.SID的格式如下所示:S-1-5-21

在Windows Server 2008 R2 Server中,上传视频遇到的问题(二)

上一篇  在Windows Server 2008 R2 Server中,上传视频遇到的问题(一)中遇到上传40M视频报404,然后修改配置文件节点: <httpRuntime targetFramework="4.5.2" maxRequestLength="1073741824" executionTimeout="3600"/> 和 <security> <requestFiltering> <!-