PC/SC-Sharp GetReaders() 抛出 InsufficientBuffer 异常

PC/SC-Sharp GetReaders() throws InsufficientBuffer exception

我正在使用从 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: The data buffer to receive returned data is too small for the returned data.

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

Length of the mszReaders buffer in characters. This parameter receives the actual length of the multi-string structure, including all trailing null characters. If the buffer length is specified as SCARD_AUTOALLOCATE, then mszReaders is converted to a pointer to a byte pointer, and receives the address of a block of memory containing the multi-string structure. This block of memory must be deallocated with 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:

Multi-string that lists the card readers within the supplied reader groups. If this value is NULL, SCardListReaders ignores the buffer length supplied in pcchReaders, writes the length of the buffer that would have been returned if this parameter had not been NULL to pcchReaders, and returns a success code.

所以它应该分配给 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" 解决方案,也许我做错了什么,或者它应该通过瘦客户端以不同的方式工作,这是一个错误或有什么事欢迎大家评论!