PC / SC-Sharp GetReaders () генерирует исключение InsufficientBuffer - PullRequest
0 голосов
/ 03 июля 2018

Я использую PC / SC Sharp пакет, загруженный из NuGet, и есть один метод 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: буфер данных для получения возвращенных данных слишком мал для возвращаемых данных.

1 Ответ

0 голосов
/ 04 июля 2018

Ну, я нашел решение. Я загрузил исходный код PC / SC-Sharp со страницы GitHub и приступил к анализу, проблема заключалась в методе SCardListReaders , который имеет параметр pcchReaders, этот параметр был маленьким и вызывал исключение от MSDN:

Длина буфера mszReaders в символах. Этот параметр получает фактическую длину многострочной структуры, включая все завершающие нулевые символы. Если длина буфера указана как SCARD_AUTOALLOCATE, то mszReaders преобразуется в указатель на указатель байта и получает адрес блока памяти, содержащего многострочную структуру. Этот блок памяти должен быть освобожден с помощью SCardFreeMemory.

был вызван вот так внутри метода ListReaders pcsc-sharp (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;
}

Так что это работает сейчас, если у вас есть какие-то идеи и немного менее «хакерское» решение, возможно, я делаю что-то не так, или, возможно, оно должно работать по-другому на тонких клиентах, и это ошибка или что-то в этом роде, пожалуйста свободно комментировать!

...