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 context
lReturn = 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 protocol
switch(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函数。但是对于以下操作系统:Windows Server 2008,WindowsVista,Windows Server 2003,Windows XP和Windows 2000而言,事务并没有释放掉,应用程序必须马上调用函数SCardDisconnect、SCardReconnect或SCardReleaseContext来避免该事务阻塞其他线程或进程与智能卡的交互。
函数使用的代码片段如下:
lReturn = SCardEndTransaction(hCard, SCARD_LEAVE_CARD);
if ( SCARD_S_SUCCESS != lReturn )
printf("Failed SCardEndTransaction/n");
6)SCardDisconnect函数用来断开先前在应用程序和智能卡之间建立的连接:
LONG WINAPI SCardDisconnect(
__in SCARDHANDLE hCard, //由函数SCardConnect返回的连接句柄
__in DWORD dwDisposition //断开连接时对智能卡的操作,取值如下:
//SCARD_EJECT_CARD---弹出智能卡;
//SCARD_LEAVE_CARD---不做任何操作
//SCARD_RESET_CARD---复位智能卡
//SCARD_UNPOWER_CARD---给智能卡掉电
);
返回值:成功时是SCARD_S_SUCCESS;失败时是智能卡错误代码。
如果一个先前建立连接的应用程序退出前没有调用SCardDisconnect函数,则智能卡会自动重置。函数使用的代码片段如下:
lReturn = SCardDisconnect(hCardHandle,
SCARD_LEAVE_CARD);
if ( SCARD_S_SUCCESS != lReturn )
{
printf("Failed SCardDisconnect/n");
exit(1); // Or other appropriate action.
}
7)SCardReconnect函数用来重新建立应用程序与智能卡直接已存在的连接。该函数可以使智能卡句柄从直接访问变为普通访问,或者确认并清除阻止对智能卡进行访问的错误状态:
LONG WINAPI SCardReconnect(
__in SCARDHANDLE hCard, //由SCardConnect返回的连接句柄
__in DWORD dwShareMode, //标志其他应用程序能否建立与该智能卡的连接,取值如下:
//SCARD_SHARE_SHARED---可以共享;
//SCARD_SHARE_EXCLUSIVE---独占使用
__in DWORD dwPreferredProtocols, //该连接允许接受的协议,组合如下:
//SCARD_PROTOCOL_T0--- T=0是可接受的协议;
//SCARD_PROTOCOL_T1--- T=1是可接受的协议
__in DWORD dwInitialization, //初始化类型:
//SCARD_LEAVE_CARD---不做任何操作
//SCARD_RESET_CARD---重置智能卡(热重置)
//SCARD_UNPOWER_CARD---将智能卡掉电后再重置(冷重置)
__out_opt LPDWORD pdwActiveProtocol //已建立的活动协议:
//SCARD_PROTOCOL_T0--- T=0是活动协议
//SCARD_PROTOCOL_T1--- T=1是活动协议
);
返回值:成功时是SCARD_S_SUCCESS;失败时是智能卡错误代码。
函数使用的代码片段如下:
DWORD dwAP;
LONG lReturn;
// Reconnect.
// hCardHandle was set by a previous call to SCardConnect.
lReturn = SCardReconnect(hCardHandle,
SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
SCARD_LEAVE_CARD,
&dwAP );
if ( SCARD_S_SUCCESS != lReturn )
printf("Failed SCardReconnect/n");
8)SCardReleaseContext函数关闭建立的资源管理器上下文,并释放分配给该上下文的资源:
LONG WINAPI SCardReleaseContext(
__in SCARDCONTEXT hContext
);
返回值:成功时是SCARD_S_SUCCESS;失败时是智能卡错误代码。
函数使用的代码片段如下:
// Free the context.
// lReturn is of type LONG.
// hSC was set by an earlier call to SCardEstablishContext.
lReturn = SCardReleaseContext(hSC);
if ( SCARD_S_SUCCESS != lReturn )
printf("Failed SCardReleaseContext/n");