PC/SC-Sharp GetReaders() генерирует исключение InsufficientBuffer
Я использую пакет 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
исключение
Достаточный объем буфера: буфер данных для получения возвращенных данных слишком мал для возвращаемых данных.
1 ответ
Ну, я нашел решение. Я скачал исходный код PC/SC-Sharp со страницы GitHub и начал анализировать, проблема была в методе 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;
}
Так что это работает сейчас, если у вас есть какие-либо идеи и немного менее "хакерское" решение, возможно, я делаю что-то не так, или, возможно, оно должно работать по-разному через тонких клиентов, и это ошибка или что-то подобное, пожалуйста, не стесняйтесь комментировать!