Windows系统提供了大量的API来方便的进行智能卡应用程序的开发,通过它们我们可以直接控制智能卡读卡器对智能卡进行操作,也可以与智能卡建立直接的虚拟连接而不用考虑智能卡读卡器。
智能卡应用程序开发的一般流程是:1)建立连接(使用函数SCardEstablishContext和SCardConnect,SCardReconnect);2)开始事务处理(使用函数SCardBeginTransaction);3)进行事务处理(使用函数SCardTransmit);4)结束事务处理(使用函数SCardEndTransaction);5)断开连接(使用函数SCardDisconnect和SCardReleaseContext)。
下面就具体看看各个函数的功能和用法吧!1)SCardEstablishContext函数用于建立进行设备数据库操作的资源管理器上下文:LONG WINAPI SCardEstablishContext(__in DWORD dwScope, //资源管理器上下文的范围,取值如下://SCARD_SCOPE_USER---数据库操作在用户域中//SCARD_SCOPE_SYSTEM---数据库操作在系统域中,调用的应用程序//必须具有对任何数据库操作的权限__in LPCVOID pvReserved1, //保留值,必须设为NULL__in LPCVOID pvReserved2, //保留值,必须设为NULL__out LPSCARDCONTEXT phContext //建立的资源管理器上下文句柄);返回值:成功时返回SCARD_S_SUCCESS;失败时返回智能卡特定错误码。
函数返回的资源管理器上下文句柄可以被对设备数据库进行查询和管理的函数使用。
如果一个客户试图在远程会话中实现智能卡操作,例如运行在终端服务器上的客户会话,而且客户会话所在的操作系统不支持智能卡重定向,则函数SCardEstablishContext返回ERROR_BROKEN_PIPE。
下面的代码是建立资源管理器上下文的例子:SCARDCONTEXT hSC;LONG lReturn;//Establish the contextlReturn = SCardEstablishContext(SCARD_SCOPE_USER,NULL, NULL, &hSC);if(SCARD_S_SUCCESS != lReturn)printf("Failed SCardEstablishContext/n");else{//Use the context as needed, when done,//free the context by calling SCardReleaseContext}2)SCardConnect函数利用特定资源管理器上下文,在应用程序与包含在特定读卡器中的智能卡之间建立一条连接:LONG WINAPI SCardConnect(__in SCARDCONTEXT hContext, //资源管理器上下文句柄__in LPCTSTR szReader, //包含目标智能卡的读写器名字__in DWORD dwShareMode, //标志其他应用程序是否可以与该智能卡建立连接,取值如下://SCARD_SHARE_SHARED---与其他应用程序共享该智能卡//SCARD_SHARE_EXCLUSIVE---独占该智能卡//SCARD_SHARE_DIRECT---本应用程序将读写器作为私有使用,并且直接//控制它,其他应用程序没有权限使用该读写器__in DWORD dwPreferredProtocols, //可接受协议的位掩码,可是如下的组合://SCARD_PROTOCOL_T0--- T=0是可接受协议//SCARD_PROTOCOL_T1--- T=0是可接受协议//0--- 该参数只有当dwShareMode是SCARD_SHARE_DIRECT时才能为0;//这种情况下,驱动程序不会处理任何协议协商,直到将控制指令//IOCTL_SMARTCARD_SET_PROTOCOL发送给SCardControl__out LPSCARDHANDLE phCard, //标识与特定读卡器中智能卡连接的句柄__out LPDWORD pdwActiveProtocol //返回已建立的活动协议,取值如下://SCARD_PROTOCOL_T0--- T=0是活动协议;//SCARD_PROTOCOL_T1--- T=1是活动协议;//SCARD_PROTOCOL_UNDEFINED---SCARD_SHARE_DIRECT标志被//被设置,因此没有任何协议协商发生;这时读卡器中可能没有智能卡);返回值:成功时返回SCARD_S_SUCCESS;失败时返回智能卡错误码。
函数SCardConnect是智能卡和读卡器访问函数,下面的代码创建和读卡器的连接,代码中假定hContext 是由函数SCardEstablishContext返回的有效的资源上下文句柄:SCARDHANDLE hCardHandle;LONG lReturn;DWORD dwAP;lReturn = SCardConnect(hContext, (LPCTSTR)"Rainbow Technologies SCR3531 0",SCARD_SHARE_SHARED,SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,&hCardHandle, &dwAP);if(SCARD_S_SUCCESS != lReturn){printf("Failed SCardConnect/n");return;}//Use the connection. Display the active protocolswitch(dwAP){case SCARD_PROTOCOL_T0:printf("Active protocol T0/n");break;case SCARD_PROTOCOL_T1:printf("Active protocol T1/n");break;case SCARD_PROTOCOL_UNDEFINED:default:printf("Active protocol unnegotiated or unknown/n");break;}//Remember to disconnect(by calling SCardDisconnect)3)SCardBeginTransaction函数在开始执行前,先等待其他所有事务完成。
当该事务开始后,其他应用程序不允许在事务期间访问智能卡:LONG WINAPI SCardBeginTransaction(__in SCARDHANDLE hCard //调用SCardConnect所获得的连接句柄);返回值:成功时返回SCARD_S_SUCCESS;失败时返回智能卡错误代码。
注意:即使另一个进程或线程重置了智能卡,本函数仍然返回SCARD_S_SUCCESS,要确定智能卡是否被重置,可以在该函数调用后立即调用SCardStatus函数。
SCardBeginTransaction函数同样是智能卡和读卡器访问函数。
下面的代码片段展示了开始智能卡事务:lReturn = SCardBeginTransaction( hCard );if ( SCARD_S_SUCCESS != lReturn )printf("Failed SCardBeginTransaction/n");4)SCardTransmit函数用来发送服务请求给智能卡,并接收从智能卡返回的数据:LONG WINAPI SCardTransmit(__in SCARDHANDLE hCard, //由函数SCardConnect返回的连接句柄__in LPCSCARD_IO_REQUEST pioSendPci, //指向指令的协议头结构的指针//一般使用系统定义的结构:// SCARD_PCI_T0(T=0协议);// SCARD_PCI_T1(T=1协议);// SCARD_PCI_RAW(原始协议)__in LPCBYTE pbSendBuffer, //要发送到智能卡的数据的指针__in DWORD cbSendLength, //pbSendBuffer的字节长度__inout_opt LPSCARD_IO_REQUEST pioRecvPci, //指向指令的协议头结构的指针,该参数当没有//协议控制信息PCI返回时可设为NULL__out LPBYTE pbRecvBuffer, //从智能卡返回的数据的指针__inout LPDWORD pcbRecvLength //pbRecvBuffer的字节长度);返回值:成功时返回SCARD_S_SUCCESS;失败时返回智能卡错误代码。
SCARD_IO_REQUEST结构开启一个协议控制信息结构,任何特定协议信息立即跟在这个结构之后。
该结构的总长度必须根据底层硬件结构字节长度进行对齐。
例如,在Win32中,任何PCI(Protocol Control Information)信息的长度一定是4字节的整数倍,即对齐到32位边界。
结构定义如下:typedef struct {DWORD dwProtocol; //使用的协议DWORD cbPciLength; //本结构的字节长度(加上任何跟随的特定PCI信息长度)} SCARD_IO_REQUEST;使用函数SCardTransmit的代码片段:// Transmit the request.// lReturn is of type LONG.// hCardHandle was set by a previous call to SCardConnect.// pbSend points to the buffer of bytes to send.// dwSend is the DWORD value for the number of bytes to send.// pbRecv points to the buffer for returned bytes.// dwRecv is the DWORD value for the number of returned bytes.lReturn = SCardTransmit(hCardHandle,SCARD_PCI_T0,pbSend,dwSend,NULL,pbRecv,&dwRecv );if ( SCARD_S_SUCCESS != lReturn ){printf("Failed SCardTransmit/n");exit(1); // or other appropriate error action}5)SCardEndTransaction函数完成先前声明的一个事务,并允许其他应用程序恢复与智能卡的交互:LONG WINAPI SCardEndTransaction(__in SCARDHANDLE hCard, //由函数SCardConnect返回的连接句柄__in DWORD dwDisposition //断开连接时对智能卡的操作,取值如下://SCARD_EJECT_CARD---弹出智能卡;//SCARD_LEAVE_CARD---不做任何操作//SCARD_RESET_CARD---复位智能卡//SCARD_UNPOWER_CARD---给智能卡掉电);返回值:成功时返回SCARD_S_SUCCESS;失败时返回智能卡错误代码,例如:SCARD_W_RESET_CARD---事务被释放,但是将来任何和智能卡的通信都需要调用SCardReconnect函数。