Windows 中的基本智能卡测试
Basic Smart Card testing in Windows
我正在尝试简单地测试 Windows 中是否存在智能卡。目标是让 "daemon" 运行 在插入卡片时(以及持续时间内)执行操作。
我对这种性质的事情零经验。我已经阅读了 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
智能卡分为不同的组。所以有一些功能可以与组一起工作,创建它等等。
要获得 readers 列表(对于基本应用程序,您实际上并不需要组)
SCardListReaders
它有4个参数,context,指向组的指针,指向readers的指针和指向reader count
的指针
你可以用这个
char *szGroups = NULL;
long readers = 0;
int res = SCardListReaders(hSCardContext, szGroups, NULL, &readers);
// handle errors
你先数 readers。现在您可以为实际 readers.
分配内存
szReaders = (char *) malloc(sizeof(char) * readers);
int res = SCardListReaders(hSCardContext, szGroups, szReaders , &readers);
现在您有 reader 个已连接的列表。
您可以像这样连接到 reader
LPSCARDHANDLE hSCard = NULL;
long activeProtocols = 0;
int ret = SCardConnect(hSCardContext, myReader, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_TX, &hSCard, &activeProtocols);
// .. handle errors
指定协议、共享模式,如果您正在处理敏感内容,请使用 SCARD_SHARE_EXCLUSIVE 共享模式 需要保护 OS 不会与交易交互。
再说一次,如果你要为 windows 和 unix 包装(unix 没有 SCARD_PROTOCOL_TX 协议),但它是这两个 SCARD_PROTOCOL_T0 的表示 | SCARD_PROTOCOL_T1.
myReader 是已连接 reader 的名称。喜欢 (LPCTSTR)"Dermalog LF10"
你从 SCardListReaders 函数中得到那些 reader 个名字。
现在您已连接到卡片。与 SCARD_SHARE_EXCLUSIVE 共享不要忘记释放智能卡上下文,因为它会死锁。
使用SCardDisconnect
断开连接,它需要2个参数,智能卡句柄和配置,对于基本应用SCARD_LEAVE_CARD配置应该没问题。它指定你不想对卡做任何特殊的事情,你不想弹出或其他任何东西。
交易更复杂,因为您需要了解 SCard 标准等等。但我涵盖了基础知识。
请记住,此代码可能无法编译,您需要改进类型,因为 windows 您需要将这些类型转换为 WinAPI 类型,例如 LPCTSTR,它不会抱怨并且unix 没有这样的类型,所以你也需要解决这些问题。
此示例代码假定读卡器在开始时已插入,它不处理读卡器数量的变化。
除此之外,它只是向控制台发送插入/未插入卡片状态的垃圾邮件。
请不要在生产代码中按原样使用它,省略了大多数错误检查,并采取了一些快捷方式来保持代码简短。
#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 != '[=10=]') {
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;
}
我正在尝试简单地测试 Windows 中是否存在智能卡。目标是让 "daemon" 运行 在插入卡片时(以及持续时间内)执行操作。
我对这种性质的事情零经验。我已经阅读了 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
智能卡分为不同的组。所以有一些功能可以与组一起工作,创建它等等。
要获得 readers 列表(对于基本应用程序,您实际上并不需要组)
SCardListReaders
它有4个参数,context,指向组的指针,指向readers的指针和指向reader count
的指针你可以用这个
char *szGroups = NULL;
long readers = 0;
int res = SCardListReaders(hSCardContext, szGroups, NULL, &readers);
// handle errors
你先数 readers。现在您可以为实际 readers.
分配内存szReaders = (char *) malloc(sizeof(char) * readers);
int res = SCardListReaders(hSCardContext, szGroups, szReaders , &readers);
现在您有 reader 个已连接的列表。
您可以像这样连接到 reader
LPSCARDHANDLE hSCard = NULL;
long activeProtocols = 0;
int ret = SCardConnect(hSCardContext, myReader, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_TX, &hSCard, &activeProtocols);
// .. handle errors
指定协议、共享模式,如果您正在处理敏感内容,请使用 SCARD_SHARE_EXCLUSIVE 共享模式 需要保护 OS 不会与交易交互。
再说一次,如果你要为 windows 和 unix 包装(unix 没有 SCARD_PROTOCOL_TX 协议),但它是这两个 SCARD_PROTOCOL_T0 的表示 | SCARD_PROTOCOL_T1.
myReader 是已连接 reader 的名称。喜欢 (LPCTSTR)"Dermalog LF10"
你从 SCardListReaders 函数中得到那些 reader 个名字。
现在您已连接到卡片。与 SCARD_SHARE_EXCLUSIVE 共享不要忘记释放智能卡上下文,因为它会死锁。
使用SCardDisconnect
断开连接,它需要2个参数,智能卡句柄和配置,对于基本应用SCARD_LEAVE_CARD配置应该没问题。它指定你不想对卡做任何特殊的事情,你不想弹出或其他任何东西。
交易更复杂,因为您需要了解 SCard 标准等等。但我涵盖了基础知识。
请记住,此代码可能无法编译,您需要改进类型,因为 windows 您需要将这些类型转换为 WinAPI 类型,例如 LPCTSTR,它不会抱怨并且unix 没有这样的类型,所以你也需要解决这些问题。
此示例代码假定读卡器在开始时已插入,它不处理读卡器数量的变化。 除此之外,它只是向控制台发送插入/未插入卡片状态的垃圾邮件。 请不要在生产代码中按原样使用它,省略了大多数错误检查,并采取了一些快捷方式来保持代码简短。
#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 != '[=10=]') {
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;
}