PC/SC规范是一个基于WINDOWS平台的一个标准用户接口(API),提供了一个从个人电脑(Personal Computer)到智能卡(SmartCard)的整合环境,PC/SC规范建立在工业标准-ISO7816和EMV标准的基础上,但它对底层的设备接口和独立于设备的应用API接口(例如用来允许多个应用共享使用系统同一张智能卡的资源管理器)做了更详尽的补充。PC/SC体系由三个主要部件组成,分别规定的操作系统厂商、读写器(IFD)厂商、智能卡(ICC)厂商的职责。PC/SC的API函数由操作系统提供,在微软公司提供的MSDN有相关帮助(路径\\MSDN\Platform
SDK\Security\Smart Card),函数声明在Winscard.h中。
由于经常使用,所以我将PC/SC几个常用函数进行封装,方便调用。
1.载入头文件
#include <WinSCard.h> #pragma comment(lib,"WinSCard.lib") #define NUMBER_OF_READERS 4 #define INDEX_LENGTH 2 #define KEY_LENGTH 32 #define NAME_LENGTH 100 #define MAX_INPUT 1024 #define MAX_OUTPUT 4000 #define MAX_RESPONSE 2000
2 建立资源管理器的上下文,并获得读卡器列表
/************************************************************************/ /* 与读卡器建立连接 返回:连接失败0,否则返回读卡器列表数目 */ /************************************************************************/ extern "C" __declspec(dllexport) int CardReaderInit( char* messageBuffer, //_out_ 返回错误信息 char(*ReaderName)[NAME_LENGTH], //_out_ 返回读卡器列表信息 SCARDCONTEXT* ContextHandle //_out_ 返回读卡器句柄 ) { // extra initialization //char ReaderName[NUMBER_OF_READERS][NAME_LENGTH]; memset(messageBuffer, 0, NAME_LENGTH); memset(ReaderName[0], 0, NAME_LENGTH); memset(ReaderName[1], 0, NAME_LENGTH); memset(ReaderName[2], 0, NAME_LENGTH); memset(ReaderName[3], 0, NAME_LENGTH); PBYTE pOutBuffer = (PBYTE)malloc(MAX_OUTPUT); int OutBufferLine = 0; PBYTE pResponseBuffer = (PBYTE)malloc(MAX_RESPONSE); memset(pResponseBuffer, 0x00, MAX_RESPONSE); // // Open a context which communication to the Resource Manager // long ret = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, ContextHandle); if (ret != SCARD_S_SUCCESS) { sprintf_s(messageBuffer, NAME_LENGTH, "Function SCardEstablishContext returned 0x%X error code.", ret); return false; } int ReaderCount = 0; unsigned long ResponseLength = MAX_RESPONSE; ret = SCardListReaders(*ContextHandle, 0, (char *)pResponseBuffer, &ResponseLength); if (ret != SCARD_S_SUCCESS) { sprintf_s(messageBuffer, NAME_LENGTH, "Function SCardListReaders returned 0x%X error code.", ret); return false; } else { unsigned int StringLen = 0; SCARDHANDLE CardHandle = NULL; while (ResponseLength > StringLen + 1) { strcpy(ReaderName[ReaderCount], (LPCTSTR)pResponseBuffer + StringLen); DWORD ActiveProtocol = 0; ret = SCardConnect(*ContextHandle, ReaderName[ReaderCount], SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &CardHandle, &ActiveProtocol); if (ret != SCARD_E_UNKNOWN_READER) ReaderCount++; if (ret == SCARD_S_SUCCESS) SCardDisconnect(CardHandle, SCARD_EJECT_CARD); StringLen += strlen((LPCTSTR)pResponseBuffer + StringLen + 1); StringLen += 2; } } if (ReaderCount == 0) { sprintf_s(messageBuffer, NAME_LENGTH, "No driver is available for use with the resource manager!"); return false; } return ReaderCount; }
3 读卡器与智能卡连接
/************************************************************************/ /* 与卡片建立连接 返回:连接失败0,否则返回1 */ /************************************************************************/ extern "C" __declspec(dllexport) bool CardConnect( SCARDCONTEXT ContextHandle, //_in_ 传入读卡器句柄 char(*ReaderName)[NAME_LENGTH], //_in_ 传入读卡器列表信息(二维数组) int actName, //_in_ 传入选择的列表序号 SCARDHANDLE *CardHandle, //_out_ 返回卡片句柄 long* ProtocolType, //_out_ 返回卡片协议 char* messageBuffer //_out_ 返回错误信息 ) { // <span style="font-family: 'Courier New';font-size:14px;">ScardTransmit </span><a target=_blank target="_blank" href="http://baike.baidu.com/view/8257336.htm" style="font-family: 'Courier New';font-size:14px;">http://baike.baidu.com/view/8257336.htm</a> DWORD ActiveProtocol = 0; *ProtocolType = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1; long ret = SCardConnect(ContextHandle, ReaderName[actName], SCARD_SHARE_EXCLUSIVE, *ProtocolType, CardHandle, &ActiveProtocol); memset(messageBuffer, 0x00, sizeof(messageBuffer) / sizeof(char)); if (ret != SCARD_S_SUCCESS){ GetErrorCode(ret, messageBuffer); return false; } *ProtocolType = ActiveProtocol; switch (*ProtocolType) { case SCARD_PROTOCOL_T0: sprintf_s(messageBuffer, NAME_LENGTH, "Function SCardConnect ok\nProtocoltype = T0"); break; case SCARD_PROTOCOL_T1: sprintf_s(messageBuffer, NAME_LENGTH, "Function SCardConnect ok\nProtocoltype = T1"); break; default: sprintf_s(messageBuffer, NAME_LENGTH, "Function SCardConnect ok\n%.8x", ActiveProtocol); break; } return true; }
4 断开与读卡器的连接
/************************************************************************/ /* 与卡片断开连接 返回:连接成功0.否则错误http://msdn.microsoft.com/en-us/library/windows/desktop/aa374738(v=vs.85).aspx */ /************************************************************************/ extern "C" __declspec(dllexport) long CardDisconnect( SCARDHANDLE CardHandle //_in_ 传入卡片句柄 ) { return SCardDisconnect(CardHandle, SCARD_EJECT_CARD); }
5 释放资源管理上下文
/************************************************************************/ /* 与读卡器断开连接 返回:连接成功0.否则错误http://msdn.microsoft.com/en-us/library/windows/desktop/aa374738(v=vs.85).aspx */ /************************************************************************/ extern "C" __declspec(dllexport) long CardReaderDisconnect( SCARDCONTEXT ContextHandle //_in_ 传入读卡器句柄 ) { return SCardReleaseContext(ContextHandle); }
6 向智能卡发送指令
int Transmit(byte* cmd, long ProtocolType, SCARDHANDLE CardHandle ) int Transmit(byte* cmd, long ProtocolType, SCARDHANDLE CardHandle) { char mhstr[MAX_INPUT]; char buf[MAX_INPUT / 2]; PBYTE pInBuffer; PBYTE pResponseBuffer; memset(mhstr, 0, MAX_INPUT); sprintf_s(mhstr, MAX_INPUT, "%s", cmd); int bufferLen = AToHex((char *)&mhstr, (BYTE *)&buf); if (!bufferLen) { return false; } SCARD_IO_REQUEST IO_Request; IO_Request.dwProtocol = ProtocolType; IO_Request.cbPciLength = (DWORD) sizeof(SCARD_IO_REQUEST); pInBuffer = (PBYTE)malloc(MAX_INPUT); memcpy(pInBuffer, buf, bufferLen); pResponseBuffer = (PBYTE)malloc(MAX_INPUT); memset(pResponseBuffer, 0x00, bufferLen); unsigned long ResponseLength = MAX_RESPONSE; long ret = SCardTransmit(CardHandle, &IO_Request, pInBuffer, bufferLen, 0, pResponseBuffer, &ResponseLength); if (ret != SCARD_S_SUCCESS){ GetErrorCode(ret, (char*)cmd); return false; } DataX::AscToHex(pResponseBuffer, ResponseLength, cmd); cmd[ResponseLength * 2] = 0x00; return ResponseLength * 2; }
7 获取错误信息
void GetErrorCode(long ret, char* messageBuffer) { switch (ret) { case SCARD_E_CANCELLED: sprintf_s(messageBuffer, NAME_LENGTH, "The action was cancelled by an SCardCancel request."); break; case SCARD_E_CANT_DISPOSE: sprintf_s(messageBuffer, NAME_LENGTH, "The system could not dispose of the media in the requested manner."); break; case SCARD_E_CARD_UNSUPPORTED: sprintf_s(messageBuffer, NAME_LENGTH, "The smart card does not meet minimal requirements for support."); break; case SCARD_E_DUPLICATE_READER: sprintf_s(messageBuffer, NAME_LENGTH, "The reader driver didn't produce a unique reader name."); break; case SCARD_E_INSUFFICIENT_BUFFER: sprintf_s(messageBuffer, NAME_LENGTH, "The data buffer to receive returned data is too small for the returned data."); break; case SCARD_E_INVALID_ATR: sprintf_s(messageBuffer, NAME_LENGTH, "An ATR obtained from the registry is not a valid ATR string."); break; case SCARD_E_INVALID_HANDLE: sprintf_s(messageBuffer, NAME_LENGTH, "The supplied handle was invalid."); break; case SCARD_E_INVALID_PARAMETER: sprintf_s(messageBuffer, NAME_LENGTH, "One or more of the supplied parameters could not be properly interpreted."); break; case SCARD_E_INVALID_TARGET: sprintf_s(messageBuffer, NAME_LENGTH, "Registry startup information is missing or invalid."); break; case SCARD_E_INVALID_VALUE: sprintf_s(messageBuffer, NAME_LENGTH, "One or more of the supplied parameters?values could not be properly interpreted."); break; case SCARD_E_NOT_READY: sprintf_s(messageBuffer, NAME_LENGTH, "The reader or card is not ready to accept commands."); break; case SCARD_E_NOT_TRANSACTED: sprintf_s(messageBuffer, NAME_LENGTH, "An attempt was made to end a non-existent transaction."); break; case SCARD_E_NO_MEMORY: sprintf_s(messageBuffer, NAME_LENGTH, "Not enough memory available to complete this command."); break; case SCARD_E_NO_SERVICE: sprintf_s(messageBuffer, NAME_LENGTH, "The Smart card resource manager is not running."); break; case SCARD_E_NO_SMARTCARD: sprintf_s(messageBuffer, NAME_LENGTH, "The operation requires a smart card but no smart card is currently in the device."); break; case SCARD_E_PCI_TOO_SMALL: sprintf_s(messageBuffer, NAME_LENGTH, "The PCI Receive buffer was too small."); break; case SCARD_E_PROTO_MISMATCH: sprintf_s(messageBuffer, NAME_LENGTH, "The requested protocols are incompatible with the protocol currently in use with the card."); break; case SCARD_E_READER_UNAVAILABLE: sprintf_s(messageBuffer, NAME_LENGTH, "The specified reader is not currently available for use."); break; case SCARD_E_READER_UNSUPPORTED: sprintf_s(messageBuffer, NAME_LENGTH, "The reader driver does not meet minimal requirements for support."); break; case SCARD_E_SERVICE_STOPPED: sprintf_s(messageBuffer, NAME_LENGTH, "The Smart card resource manager has shut down."); break; case SCARD_E_SHARING_VIOLATION: sprintf_s(messageBuffer, NAME_LENGTH, "The card cannot be accessed because of other connections outstanding."); break; case SCARD_E_SYSTEM_CANCELLED: sprintf_s(messageBuffer, NAME_LENGTH, "The action was cancelled by the system presumably to log off or shut down."); break; case SCARD_E_TIMEOUT: sprintf_s(messageBuffer, NAME_LENGTH, "The user-specified timeout value has expired."); break; case SCARD_E_UNKNOWN_CARD: sprintf_s(messageBuffer, NAME_LENGTH, "The specified card name is not recognized."); break; case SCARD_E_UNKNOWN_READER: sprintf_s(messageBuffer, NAME_LENGTH, "The specified reader name is not recognized."); break; case SCARD_F_COMM_ERROR: sprintf_s(messageBuffer, NAME_LENGTH, "An internal communications error has been detected."); break; case SCARD_F_INTERNAL_ERROR: sprintf_s(messageBuffer, NAME_LENGTH, "An internal consistency check failed."); break; case SCARD_F_UNKNOWN_ERROR: sprintf_s(messageBuffer, NAME_LENGTH, "An internal error has been detected but the source is unknown."); break; case SCARD_F_WAITED_TOO_LONG: sprintf_s(messageBuffer, NAME_LENGTH, "An internal consistency timer has expired."); break; case SCARD_S_SUCCESS: sprintf_s(messageBuffer, NAME_LENGTH, "OK"); break; case SCARD_W_REMOVED_CARD: sprintf_s(messageBuffer, NAME_LENGTH, "The card has been removed so that further communication is not possible."); break; case SCARD_W_RESET_CARD: sprintf_s(messageBuffer, NAME_LENGTH, "The card has been reset so any shared state information is invalid."); break; case SCARD_W_UNPOWERED_CARD: sprintf_s(messageBuffer, NAME_LENGTH, "Power has been removed from the card so that further communication is not possible."); break; case SCARD_W_UNRESPONSIVE_CARD: sprintf_s(messageBuffer, NAME_LENGTH, "The card is not responding to a reset."); break; case SCARD_W_UNSUPPORTED_CARD: sprintf_s(messageBuffer, NAME_LENGTH, "The reader cannot communicate with the card due to ATR configuration conflicts."); break; default: sprintf_s(messageBuffer, NAME_LENGTH, "Function returned unknown error code: #%ld", ret); break; } }
8 复位卡片
bool CpuReset(SCARDHANDLE CardHandle, byte* atr) { CHAR szReader[200]; DWORD cch = 200; BYTE bAttr[32]; DWORD cByte = 32; DWORD dwState, dwProtocol; LONG lReturn; string AtrValue; memset(bAttr, 0, 32); memset(szReader, 0, 200); // Determine the status. // hCardHandle was set by an earlier call to SCardConnect. lReturn = SCardStatus(CardHandle, szReader, &cch, &dwState, &dwProtocol, (LPBYTE)&bAttr, &cByte); if (SCARD_S_SUCCESS != lReturn) return FALSE; DataX::AscToHex(bAttr, cByte, atr); return TRUE; }
文/闫鑫原创转载请注明出处http://blog.csdn.net/yxstars/article/details/41522467
时间: 2024-11-07 21:01:09