@Mingun

Как отследить появление смарт-карты в кард-ридере по протоколу PC/SC?

Пытаюсь ожидать изменения, но функция почему-то сразу возвращается, причем на одной машине с одним и тем же ридером две разных программы ведут себя по разному: у одной почти постоянно возвращается ошибка SCARD_W_CARD_REMOVED, у другого -- SCARD_S_SUCCESS. Код программ практически идентичный, только вторая линкуется еще и с библиотекой CEN/XFS и User32.

Собственно, пытаюсь отслеживать изменения таким кодом:
// Тут открыто соединение, все, как полагается
SCARDCONTEXT hContext;
LONG rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
...
SCARD_READERSTATE reader = {0};
// Считыватель со специальным именем, означающем, что необходимо мониторить
// появление/пропажу считывателей.
reader.szReader = "\\\\?PnP?\\Notification";
reader.dwCurrentState = SCARD_STATE_UNAWARE;
// Мониторим появление считывателей, останавливаемся, пока их не подключат.
// Если считыватель уже подключен на момент вызова, вернется сразу.
LONG st = SCardGetStatusChange(hContext, INFINITE, &reader, 1);
...
SCARD_READERSTATE reader = {0};
reader.szReader = <тут он получен от PC/SC подсистемы>;
// Пытался записывать сюда и SCARD_STATE_UNAWARE, и SCARD_STATE_EMPTY,
// и получать его предыдущим вызовом SCardGetStatusChange, но тогда карточка
// не замечается, если на момент выполнения функции она уже в считывателе.
// Как видно из комментариев выше, считыватель в таком случае прекрасно ловится.
// reader.dwCurrentState = SCARD_STATE_UNAWARE;
LONG st = SCardGetStatusChange(hContext, INFINITE, &reader, 1);
// Здесь st == SCARD_W_CARD_REMOVED в первой программе и SCARD_S_SUCCESS во второй.

Очень редко бывает, что первая программа останавливается и ждет ввода карты, но это скорее случайность.

Вот хотел спросить, правильно ли я пытаюсь реализовать отслеживание появления карт в считывателе? Как это делать правильно? В тестах к библиотеке PCSC-lite просто выставляют reader.dwCurrentState=SCARD_STATE_EMPTY, кто-то советует сначала получить текущее состояние:
DWORD getState(SCARDCONTEXT  hContext, const char* name) {
    SCARD_READERSTATE reader = {0};
    reader.szReader = name;
    reader.dwCurrentState = SCARD_STATE_UNAWARE;
    // Предсказуемо возвращается сразу с результатом SCARD_S_SUCCESS
    // (тестировал только во второй программе, но там всегда SCARD_S_SUCCESS)
    LONG st = SCardGetStatusChange(hContext, INFINITE, &reader, 1);
    return reader.dwEventState;
}
...
SCARD_READERSTATE reader = {0};
reader.szReader = <тут он получен от PC/SC подсистемы>;
reader.dwCurrentState = getState(hContext, reader.szReader);
LONG st = SCardGetStatusChange(hContext, INFINITE, &reader, 1);
...


Также первая программа -- это код примера, дополненный вышеуказанным кодом ожидания подключения считывателя и появления в нем карточки.
Считыватель -- Omnikey 3121.
  • Вопрос задан
  • 3860 просмотров
Решения вопроса 1
@Mingun Автор вопроса
Разобрался. Необходимо с каждым витком ожидания заносить в dwCurrentState значение из dwEventState. Правда, понять, из-за чего были глюки с возвращаемым значением, не удалось. Короче, такой код работает:
// Начальное состояние dwCurrentState будет SCARD_STATE_UNAWARE, т.к. числом это значение 0.
SCARD_READERSTATE reader = {0};
reader.szName = ...;
do {
    LONG st = SCardGetStatusChange(hContext, INFINITE, &reader, 1);
    // Делаем новое состояние текущим.
    reader.dwCurrentState = reader.dwEventState;
    // прочие дела.
    ...
} while (true);

Цикл лучше сделать даже для одиночного ожидания, т.к. первый раз он наверняка провернется вхолостую -- т.к. первый вызов сразу заполнит текущее состояние, а второй уже будет ждать изменений.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы