• 常用的PC/SC接口函数


       PC/SC规范是一个基于WINDOWS平台的一个标准用户接口(API),提供了一个从个人电脑(Personal Computer)到智能卡(SmartCard)的整合环境,PC/SC规范建立在工业标准-ISO7816和EMV标准的基础上,但它对底层的设备接口和独立于设备的应用API接口(例如用来允许多个应用共享使用系统同一张智能卡的资源管理器)做了更详尽的补充。PC/SC体系由三个主要部件组成,分别规定的操作系统厂商、读写器(IFD)厂商、智能卡(ICC)厂商的职责。PC/SC的API函数由操作系统提供,在微软公司提供的MSDN有相关帮助(路径\MSDNPlatform SDKSecuritySmart 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
    Protocoltype = T0");
    		break;
    	case SCARD_PROTOCOL_T1:
    		sprintf_s(messageBuffer, NAME_LENGTH, "Function SCardConnect ok
    Protocoltype = T1");
    		break;
    	default:
    		sprintf_s(messageBuffer, NAME_LENGTH, "Function SCardConnect ok
    %.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;
    }


    文/yanxin8原创,获取更多信息请移步至yanxin8.com...


  • 相关阅读:
    HTML页面空格记录&nbsp;&ensp; &emsp; (小计)
    JS对象、构造器函数和原型对象之间的关系
    情人节,送女友一桶代码可否?
    JavaScript中的BOM和DOM
    js中字符替换函数String.replace()使用技巧
    XML DOM 节点类型(Node Types)
    node 基础
    npm脚本命令npm run script的使用
    Node.js学习笔记六,获取get/post请求的参数
    querystring模块详解
  • 原文地址:https://www.cnblogs.com/iplus/p/4467093.html
Copyright © 2020-2023  润新知