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. Git使用手册:HTTPS和SSH方式的区别和使用

    在管理Git项目上,很多时候都是直接使用https url克隆到本地,当然也有有些人使用SSH url克隆到本地.这两种方式的主要区别在于:使用https url克隆对初学者来说会比较方便,复制htt ...

  2. PMP考试--三点估计法

    如果你对项目管理.系统架构有兴趣,请加微信订阅号“softjg”,加入这个PM.架构师的大家庭 把施工时间划分为乐观时间.最可能时间.悲观时间 乐观时间:也就是工作顺利情况下的时间为a 最可能时间:最 ...

  3. 【转】Java的接口和抽象类的区别

    1.      抽象类和接口的区别 所谓抽象类是用来表征我们在对问题领域进行分析.设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象:所谓接口,相当于电源插座,可插入构件相当于 ...

  4. jquery zTree 查找所有的叶子节点

    jquery zTree 查找所有的叶子节点 // 保存所有叶子节点 10 为初始化大小,并非数组上限 var arrayObj = new Array([10]); /* treeNode: 根节点 ...

  5. devexpress中如何绑定ASPxTreeList控件

    效果图: //前端控件代码: <dx:ASPxTreeList ID="Tree_Gooslist" AutoGenerateColumns="False" ...

  6. android 控件描边取消重叠

    今天写组件的时候用到了描边.可是两个组件放在一起时,描边会变重叠,使之变粗.就不是很美观了. 如何取消呢?网上查了好久没找到,然后就自己试了试,找到了解决方法,就在此记录一下,防止以后忘记. 很简单分 ...

  7. coffeeScript 语法总结

    CoffeeScript ---->安装node.js ---->安装coffeeScript 语句: 注意:没有分号,语句由新的一行结束:多条语句写到同一行时需要分号表示一条语句的结束( ...

  8. AX 获得当前Grid的数据源的记录行数

    sysQuery::CountTotal();方法 eg: int lines = sysQuery::CountTotal( SalesTable_ds.QueryRun());

  9. JavaScript基本用法

    首次创建 $(document).ready(function () { });

  10. Android IOS WebRTC 音视频开发总结(三一)-- 自定义传输实现一对多

    本文主要介绍基于Webrtc的多人视频会议的简单实现,文章来自博客园RTC.Blacker,支持原创,转载请说明出处. 前面提到基于开源框架的视频会议都存在诸多问题,所以我们通过重写WEBRTC传输模 ...