Я пытаюсь просто проверить наличие смарт-карты в Windows. Цель состоит в том, чтобы запустить «демон», который будет выполнять действие всякий раз (и на время), когда карта вставлена.
У меня нет опыта работы с вещами такого рода. Я прочитал документацию по SCardStatus и тому подобное, но я не понимаю, как работает весь API, поэтому я немного растерялся.
Для меня было бы очень полезно, если бы у кого-то был очень простой пример полной программы, которая просто проверяет наличие карты (желательно на C ++, но я возьму то, что смогу получить!). Я был бы очень признателен. Мне не нужен какой-либо статус карты, кроме того, который существует. Спасибо!
Если вы работаете в Windows, вам нужно использовать WinSCard API, если вы используете Unix, то используйте PCSC. Эти два API очень похожи из-за стандартов, но WinSCard API намного больше и дает гораздо больше функций для использования. Эти два API реализованы на языке C, но вы можете легко обернуть их в C ++. Я просто хочу указать, что если вы собираетесь обернуть эти два API в C ++, чтобы использовать их когда-либо в Windows И в Unix, взгляните на числовые значения протоколов смарт-карт, они отличаются на этих платформах.
Основы:
Вам необходимо установить контекст (это все равно, что создать менеджер смарт-карт)
SCardEstablishContext
Он принимает 4 параметра, но для базового использования вам нужны только 2, область действия и указатель на контекстный дескриптор.
LPSCARDCONTEXT hSCardContext = NULL;
int ret = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &hSCardContext);
if (ret != ERROR_SUCCES) ... // handle error
Смарт-карты сгруппированы в разные группы. Так что есть функции для работы с группами, для ее создания и так далее.
Чтобы получить список читателей (для базовых приложений вам действительно не нужны группы)
SCardListReaders
Требуется 4 параметра, контекст, указатель на группу, указатель на читателей и указатель на количество читателей
Вы можете использовать это Lise это
char *szGroups = NULL;
long readers = 0;
int res = SCardListReaders(hSCardContext, szGroups, NULL, &readers);
// handle errors
вы читаете счет в первую очередь. Теперь вы можете выделить память для реальных читателей.
szReaders = (char *) malloc(sizeof(char) * readers);
int res = SCardListReaders(hSCardContext, szGroups, szReaders , &readers);
Теперь у вас есть список подключенных читателей.
Вы можете подключиться к читателю так
LPSCARDHANDLE hSCard = NULL;
long activeProtocols = 0;
int ret = SCardConnect(hSCardContext, myReader, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_TX, &hSCard, &activeProtocols);
// .. handle errors
укажите протоколы, режим совместного использования, используйте SCARD_SHARE_EXCLUSIVE для режима совместного использования, если вы работаете с конфиденциальными данными, которые нуждаются в защите, чтобы ОС не взаимодействовала с транзакциями.
Еще раз, если вы переносите для окон и Unix (Unix не имеет протокола SCARD_PROTOCOL_TX), но это представление этих двух SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1.
myReader — это имя подключенного читателя. подобно (LPCTSTR)"Dermalog LF10"
эти имена читателей вы получаете из функции SCardListReaders.
Теперь вы связаны с картой. при совместном использовании SCARD_SHARE_EXCLUSIVE не забудьте освободить контекст смарт-карты, потому что он заблокируется.
использование SCardDisconnect
для отключения требуется 2 параметра, дескриптор SmartCard и расположение, для базового приложения расположение SCARD_LEAVE_CARD должно быть в порядке. Он указывает, что вы не хотите делать что-то особенное с картой, не хотите извлекать или что-то еще.
Транзакции являются более сложными, потому что вам нужно знать стандарты SCard, а что нет. Но я охватил основы.
Имейте в виду, что этот код может не компилироваться, вам нужно улучшать типы, для окон вам нужно преобразовывать эти типы в типы WinAPI, такие как LPCTSTR, чтобы он не жаловался, а в Unix таких типов нет, поэтому вам нужно также обойти эти проблемы ,
В этом примере кода предполагается, что устройства для чтения карт памяти подключены с самого начала, он не поддерживает изменение количества устройств для чтения карт.
Помимо этого, он просто спамит консоль со вставленным / не вставленным статусом карточек.
Пожалуйста, не используйте это как есть в производственном коде, большая часть проверки ошибок опущена, и некоторые сокращения используются для того, чтобы код был коротким (ish).
#pragma comment(lib, "winscard.lib")
#include <vector>
bool test()
{
DWORD dwReaders;
LPSTR szReaders = NULL;
SCARDCONTEXT hContext;
bool bRunning = true;
std::vector<const char*> cards;
LONG status = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &hContext);
if( status != SCARD_S_SUCCESS ) {
return false;
}
dwReaders = SCARD_AUTOALLOCATE;
if( SCardListReadersA(hContext, NULL, (LPSTR)&szReaders, &dwReaders) == SCARD_S_SUCCESS ) {
LPSTR reader = szReaders;
while (reader != NULL && *reader != '\0') {
std::cout << "Reader name: '" << reader << "'" << std::endl;
cards.push_back( reader );
reader += strlen(reader)+1;
}
LPSCARD_READERSTATEA lpState = new SCARD_READERSTATEA[cards.size()];
for( size_t n = 0; n < cards.size(); ++n ) {
memset( lpState + n, 0, sizeof(SCARD_READERSTATEA) );
lpState[n].szReader = cards[n];
}
do {
status = SCardGetStatusChangeA( hContext, 500, lpState, cards.size() );
switch( status )
{
case SCARD_S_SUCCESS:
case SCARD_E_TIMEOUT:
for( size_t n = 0; n < cards.size(); ++n ) {
if( lpState[n].dwEventState & SCARD_STATE_PRESENT) {
std::cout << "'" << lpState[n].szReader << "' present" << std::endl;
} else {
std::cout << "'" << lpState[n].szReader << "' not present" << std::endl;
}
}
break;
default:
std::cout << "Other result: " << status << std::endl;
break;
}
Sleep( 1000 ); // do not spam too bad
} while( bRunning );
// only do this after being done with the strings, or handle the names another way!
SCardFreeMemory( hContext, szReaders );
}
SCardReleaseContext( hContext );
return true;
}