Windows中的基本智能卡测试

时间:2015-07-23 15:45:16

标签: c++ smartcard

我试图在Windows中测试智能卡的存在。目标是拥有一个"守护进程"在插入卡片的任何时间(以及持续时间)执行动作的跑步。

我对这种性质的事物没有经验。我已经阅读了SCardStatus等文档,但我不了解整个API是如何工作的,所以我有点迷失。

对我来说最有帮助的是,如果有人有一个非常简单的完整程序示例,只需测试卡的存在(最好用C ++,但我会采取我能得到的!)。我非常感激。除了它之外,我不需要任何卡状态。谢谢!

2 个答案:

答案 0 :(得分:1)

如果您在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个参数,上下文,指向组的指针,指向读者的指针和指向读者计数的指针

你可以用它来舔这个

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进行共享模式。

如果你正在为windows和unix包装(unix没有SCARD_PROTOCOL_TX协议),那么它再次表示这两个SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1。

myReader是已连接阅读器的名称。像(LPCTSTR)"Dermalog LF10"一样 你从SCardListReaders函数中获得这些读者名称。

现在你用卡片连接了。与SCARD_SHARE_EXCLUSIVE共享不要忘记释放智能卡上下文,因为它会死锁。 使用SCardDisconnect断开连接,它需要2个参数,智能卡处理和处置,对于基本应用程序SCARD_LEAVE_CARD配置应该没问题。它规定你不想对卡片做任何特别的事情,你不想弹出或其他什么。

交易更复杂,因为你需要了解SCard标准,什么不是。但我介绍了基础知识。

请记住,此代码可能无法编译,您需要改进类型,对于需要在WinAPI类型中转换类型的窗口,如LPCTSTR,它不会抱怨并且unix没有这样的类型因此您需要解决这些问题也是如此。

答案 1 :(得分:1)

此示例代码假定读卡器在开始时插入,它不能处理不断变化的读卡器数量。 除此之外,它只是插入控制台插入/未插入状态的卡。 请不要在生产代码中使用它,大多数错误检查都会被省略,并且会采用一些快捷方式来保持代码简短(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;
}
相关问题