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;
}

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

常用的PC/SC接口函数的更多相关文章

  1. PC/SC双界面读写器开发指南

    友我科技PCSC双界面读写器YW-606开发指南 1.建立资源管理器的上下文 函数ScardEstablishContext()用于建立将在其中进行设备数据库操作的资源管理器上下文(范围). 函数原型 ...

  2. PC/SC

    简介 PC/SC规范由微软公司与世界其它著名的智能卡厂商组成的PC/SC工作组提出的.PC/SC规范是一个基于WINDOWS平台的一个标准用户接口(API),提供了一个从个人电脑(Personal C ...

  3. MVC支付宝PC网站接口对接

    PC网站支付接口,请参考支付宝官方文档:https://b.alipay.com/signing/productSet.htm?navKey=all 1.需要提供签约账号.商户密钥 2.代码实现: 支 ...

  4. 支付宝PC网站接口对接

    PC网站支付接口,请参考支付宝官方文档:https://b.alipay.com/signing/productSet.htm?navKey=all 1.需要提供签约账号.商户密钥 2.代码实现: 支 ...

  5. 对比讲解lambda表达式与传统接口函数实现方式

    在本号之前写过的一些文章中,笔者使用了lambda表达式语法,一些读者反映说代码看不懂.本以为java 13都已经出了,java 8中最重要特性lambda表达式大家应该都掌握了,实际上还是存在大量的 ...

  6. sysfs接口函数的建立_DEVICE_ATTR(转)

    sysfs接口函数到建立_DEVICE_ATTR 最近在弄Sensor驱动,看过一个某厂家的成品驱动,里面实现的全都是sysfs接口,hal层利用sysfs生成的接口,对Sensor进行操作. 说道s ...

  7. sysfs接口函数到建立_DEVICE_ATTR

    sysfs接口函数到建立_DEVICE_ATTR 最近在弄Sensor驱动,看过一个某厂家的成品驱动,里面实现的全都是sysfs接口,hal层利用sysfs生成的接口,对Sensor进行操作. 说道s ...

  8. USB CCID协议和PC/SC标准

    CCID是USB Chip/Smart Card Interface Devices,也就是USB芯片智能卡接口设备,是USB规范下的一种设备类型.就像HID设备一样,需要参考USB规范来写固件程序来 ...

  9. ioctl、文件操作接口函数以及nand的升级模式的操作过程详解

    概述 内核中驱动文件的操作通常是通过write和read函数进行的,但是很多时候再用户空间进行的操作或许不是内核中公共代码部分提供的功能,此时就需要使用一种个性化的方法进行操作--ioctl系统调用. ...

随机推荐

  1. 翻译:wiki中的business logic词条

    Business logic 业务逻辑 From Wikipedia, the free encyclopedia 来自Wikipedia,自由的百科全书 In computer software, ...

  2. 慕课网-安卓工程师初养成-3-3 Java中的赋值运算符

    来源:http://www.imooc.com/code/1298 赋值运算符是指为变量或常量指定数值的符号.如可以使用 “=” 将右边的表达式结果赋给左边的操作数. Java 支持的常用赋值运算符, ...

  3. UIBlurEffect实现模糊效果

    //使用图片初始化背景 Pattern 图案,模式 self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageN ...

  4. windows 服务的启动与安装

    在使用windows 操作系统时,我们对windows服务再也熟悉不过了,这些服务有的是系统层的,有的是应用层的,大部分都是运行在桌面的后台,可以在进程中看到,有时候在做web项目时,在站点启动时要启 ...

  5. JS 在open打开的子窗口页面中调用父窗口页面的JS方法

    需求的情景如下: 1:做新增或修改等操作的时候打开一个新的浏览器窗口(使用window.open(参数等)方法) 2:在新增或修改等的页面上有返回按钮.重置按钮.保存按钮,对于返回就直接关闭此窗口(使 ...

  6. SSH环境搭建步骤解析

    一.建立Java web project:AngelSSH 二.引入jar包,必要清单如下 2.1,Struts2 commons-fileupload  文件上传组件 commons-io   io ...

  7. SQL数据库基本语句

    SQL特点--> 1)综合统一.SQL是集数据定义.数据操作和数据控制于一体,语言峰峰统一,可独立完成数据库生命周期的所有活动. 2)高度非过程化.SQL语言是高度非过程化语言,当进行数据操作时 ...

  8. HiveSQL解析过程详解 | 学步园

    HiveSQL解析过程详解 | 学步园   http://www.xuebuyuan.com/2210261.html

  9. css实现div悬浮层,始终停留在浏览器的最下方,不随页面的滚动条滚动改变位置或消失

    .bottom_xf{ background-color:#1D69A9; width:100%; height:2.8em; margin:0 auto; overflow:hidden; posi ...

  10. leetcode 88

    88. Merge Sorted Array Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as on ...