2

我正在使用从 NuGet 下载的PC/SC Sharp包,并且有一种方法GetReaders()可以返回连接到机器的活动阅读器。

var contextFactory = ContextFactory.Instance;
using (var context = contextFactory.Establish(SCardScope.System)) {
    Console.WriteLine("Currently connected readers: ");
    var readerNames = context.GetReaders();
    foreach (var readerName in readerNames) {
        Console.WriteLine("\t" + readerName);
    }
}

当我从本地机器(Windows 10 Pro x64)调用它时,它工作正常并返回可用的读者名称。无论如何,当通过瘦客户端连接到 Windows Server 2008 R2 时,它会抛出InsufficientBuffer异常

InsufficientBuffer:接收返回数据的数据缓冲区对于返回的数据来说太小了。

4

1 回答 1

1

好吧,我找到了解决方案。我已经从他们的 GitHub 页面下载了 PC/SC-Sharp 的源代码并开始分析,问题出在方法SCardListReaders中,该方法具有参数pcchReaders并且该参数太小并导致异常,来自 MSDN:

mszReaders 缓冲区的长度(以字符为单位)。此参数接收多字符串结构的实际长度,包括所有尾随空字符。如果缓冲区长度指定为 SCARD_AUTOALLOCATE,则 mszReaders 将转换为指向字节指针的指针,并接收包含多字符串结构的内存块的地址。必须使用 SCardFreeMemory 释放此内存块。

在 pcsc-sharp 的ListReaders方法(WinSCardAPI)中这样调用:

public SCardError ListReaders(IntPtr hContext, string[] groups, out string[] readers) {
    var dwReaders = 0;

    // initialize groups array
    byte[] mszGroups = null;
    if (groups != null)
    mszGroups = SCardHelper.ConvertToByteArray(groups, TextEncoding);

    // determine the needed buffer size
    var rc = SCardHelper.ToSCardError(
        SCardListReaders(hContext,
        mszGroups,
        null,
        ref dwReaders));

    if (rc != SCardError.Success) {
        readers = null;
        return rc;
    }

    // initialize array
    var mszReaders = new byte[dwReaders * sizeof(char)];


    rc = SCardHelper.ToSCardError(
        SCardListReaders(hContext,
        mszGroups,
        mszReaders,
        ref dwReaders));

    readers = (rc == SCardError.Success)
              ? SCardHelper.ConvertToStringArray(mszReaders, TextEncoding)
              : null;

    return rc;
}

第一次,它是调用SCardListReaders方法来确定所需的缓冲区大小,mszReaders参数设置为null,所以根据 MSDN:

列出提供的读卡器组中的读卡器的多字符串。如果此值为 NULL,SCardListReaders 将忽略 pcchReaders 中提供的缓冲区长度,将如果此参数不是 NULL 则将返回的缓冲区长度写入 pcchReaders,并返回成功代码

所以它应该分配给dwReaders正确的缓冲区大小,用于获取连接的读者列表。好吧,它在我的 Windows 10 pro 机器上正常工作,阅读器直接连接,但通过瘦客户端连接到 Windows 2008 r2 服务器,它返回相同的值(它是37),但该值导致InsufficientBuffer异常。

因此,我开始调整该值并手动设置(在 Windows 2008 r2 服务器内调试),我发现如果将该值设置为48(或更高)它将起作用。我不知道是什么原因导致该SCardListReaders方法返回的参数值不足,但我设法在第二次通过之前手动将该值加倍,所以新版本ListReaders()看起来像这样:

public SCardError ListReaders(IntPtr hContext, string[] groups, out string[] readers) {
    var dwReaders = 0;

    // initialize groups array
    byte[] mszGroups = null;
    if (groups != null)
    mszGroups = SCardHelper.ConvertToByteArray(groups, TextEncoding);            

    // determine the needed buffer size
    var rc = SCardHelper.ToSCardError(
        SCardListReaders(hContext,
        mszGroups,
        null,
        ref dwReaders));

    if (rc != SCardError.Success) {
        readers = null;
        return rc;
    }

    //doubling buffer size to work through thin clients
    dwReaders *= 2; // <------------------ New line

    // initialize array
    var mszReaders = new byte[dwReaders * sizeof(char)];

    rc = SCardHelper.ToSCardError(
        SCardListReaders(hContext,
        mszGroups,
        mszReaders,
        ref dwReaders));

    readers = (rc == SCardError.Success)
              ? SCardHelper.ConvertToStringArray(mszReaders, TextEncoding)
              : null;

    return rc;
}

所以它现在正在工作,如果你有任何想法和少一点“hacky”的解决方案,也许我做错了什么,或者它应该通过瘦客户端以不同的方式工作,这是一个错误或什么,请随时发表评论!

于 2018-07-04T10:17:02.313 回答