C# WinScard.SCardListReaders 应该只列出已连接的 reader s(但它列出了所有过去安装的 reader 现在未连接的名称)

C# WinScard.SCardListReaders should list only the connected readers (but it is listing all the past installed reader names which is now not connected)

请检查我下面的 C# 代码。我正在尝试获取现在连接到我的计算机的智能卡 reader 的列表。但是这个函数返回所有过去连接的智能卡 reader 名称(我的意思是现在没有连接)。我只想要 reader 的活动(当前)连接名称列表。我无法理解问题出在哪里。

我尝试了这个 website 中的一个 exe,它是用 C 编写和编译的。它只显示连接的 reader。我比较了代码,但我发现没有区别。请帮助找到修复程序。

public static int GetPCSCReaders(out List<string> smartCardReaders, out string errMsg)
{
    errMsg = string.Empty;
    byte[] readersList = null;
    smartCardReaders = new List<string>();

    try
    {
        int hContext = 0;
        int ret = SCardEstablishContext(WinSCard.SCARD_SCOPE_USER, 0, 0, ref hContext);
        if (ret != 0)
        {
            errMsg = "WinSCard GetPCSCReader: EstablishContext Error: " + ret.ToString();
            return ret;
        }

        int byteCnt = 0;
        ret = WinSCard.SCardListReaders(hContext, null, null, ref byteCnt);
        if (ret != SCARD_S_SUCCESS)
        {
            errMsg = "WinSCard GetPCSCReader: ListReaders Error: " + ret.ToString();
            return ret;
        }

        readersList = new byte[byteCnt];
        ret = WinSCard.SCardListReaders(hContext, null, readersList, ref byteCnt);
        if (ret != SCARD_S_SUCCESS)
        {
            errMsg = "WinSCard GetPCSCReader: ListReaders Error: " + ret.ToString();
            return ret;
        }

        int indx = 0;
        string readerName = string.Empty;
        int i = 0;

        while (readersList[indx] != 0)
        {
            while (readersList[indx] != 0)
            {
                readerName = readerName + (char)readersList[indx++];
            }

            smartCardReaders.Add(readerName);
            i++;

            readerName = "";
            indx++;
        }

    }
    catch (Exception ex)
    {
        errMsg = ex.Message;
    }
    finally
    {
        readersList = null;
    }
    return 0;
}

手头没有智能卡 reader 很难回答这个问题,尽管我是在 3 个月前才开发这些代码的。

我之前的代码是基于这个: https://github.com/nicbedford/CardBrowser/blob/master/PCSC/PCSCReader.cs

它不是很完美,你必须自己检测错误。但这确实有帮助。

不同的windows平台有不同的解决方案。

  1. Window 8.1+:

https://code.msdn.microsoft.com/windowsapps/Smart-card-sample-c7d342e0#content

  1. Window 10:

https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/SmartCard

https://docs.microsoft.com/en-us/uwp/api/windows.devices.smartcards

  1. Windows 7+:

https://github.com/nicbedford/CardBrowser/tree/master/PCSC

https://github.com/orouit/SmartcardFramework

https://github.com/danm-de/pcsc-sharp/tree/master/src/PCSC

如果您在将 C++ 转换为 C# 时遇到问题,您可以在此处找到所有函数: https://www.pinvoke.net/default.aspx/winscard/SCardTransmit.html 只需搜索左上角的函数即可。

我浏览了这个 link,在该页面中,有一个提示和技巧提到 "if you invoke SCardListReaders with the hContext parameter set to null, you'll get the list of the installed readers (not the plugged ones !)"。按照这个,在我的代码中,我将 hContext 变量设置为 int,我将其更改为 IntPtr,这让我只列出已连接的读者。它已解决,现在我的代码更改为

public static int GetPCSCReaders(out List<string> smartCardReaders, out string errMsg)
{
    errMsg = string.Empty;
    smartCardReaders = new List<string>();
    IntPtr hContext;

    try
    {
        int ret = SCardEstablishContext(SCARD_SCOPE_USER, IntPtr.Zero, IntPtr.Zero, out hContext);
        if (ret != SCARD_S_SUCCESS)
        {
            errMsg = "WinSCard GetPCSCReader: EstablishContext Error: " + ret.ToString();
            return ret;
        }

        byte[] readersList = null;
        uint byteCnt = 0;
        ret = SCardListReaders(hContext, null, null, ref byteCnt);
        if (ret != SCARD_S_SUCCESS)
        {
            errMsg = "WinSCard GetPCSCReader: ListReaders Error: " + ret.ToString();
            return ret;
        }

        readersList = new byte[byteCnt];
        ret = SCardListReaders(hContext, null, readersList, ref byteCnt);
        if (ret != SCARD_S_SUCCESS)
        {
            errMsg = "WinSCard GetPCSCReader: ListReaders Error: " + ret.ToString();
            return ret;
        }

        int indx = 0;
        string readerName = string.Empty;
        int i = 0;

        while (readersList[indx] != 0)
        {
            while (readersList[indx] != 0)
            {
                readerName = readerName + (char)readersList[indx++];
            }

            smartCardReaders.Add(readerName);
            i++;

            readerName = "";
            indx++;
        }

    }
    catch (Exception ex)
    {
        errMsg = ex.Message;
    }
    finally
    {

    }
    return 0;
}