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. 多媒体编程基础之RGB和YUV

    一.概念 1.什么是RGB? 对一种颜色进行编码的方法统称为“颜色空间”或“色域”.用最简单的话说,世界上任何一种颜色的“颜色空间”都可定义成一个固定的数字或变量.RGB(红.绿.蓝)只是众多颜色空间 ...

  2. Flash与IE奇怪的关键字冲突

    我有一个小小的swf文件,用来播放声音,加入到HTML后,在Firefox/chrome下播放正常,唯独IE8提示 消息: 对象不支持此属性或方法 行: 48 字符: 3 代码: 0 URI: ... ...

  3. 利用KeyVault来加强存储Azure Storage访问密钥管理

    很多时候管理Azure的存储账号我们都需要通过下面的界面管理访问密钥,大部分情况下通过密钥的轮替使用更新就可以做到安全管理了. 但是很多时候存储账号的Key就会不小心分发到开人员.测试人员.和管理员手 ...

  4. 【LeetCode】11. Container With Most Water

    题目: Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, a ...

  5. 未在本地计算机上注册“Microsoft.Jet.OLEDB.4.0”提供程序的处理方式

    今天客户向我反映一个问题,当他们在用我们的系统导出excel表格时,报错:未在本地计算机上注册“Microsoft.Jet.OLEDB.4.0”提供程序 经过找资料终于得到解决方法,记录一下. 在对应 ...

  6. MSP430F149学习之路——按键

    代码一: /********************************** 程序功能:用按键控制LED灯熄灭 ***********************************/ #incl ...

  7. rsync 参数断点续传

    断点续传是使用大写P参数,-P这个参数是综合了--partial --progress两个参数 rsync -avzP /home/hadoop/jdk1..0_73.tar.gz root@10.2 ...

  8. python的文件操作方法

    python中的文件对象:文件对象不仅可以用来访问普通的磁盘文件, 而且也可以访问任何其它类型抽象层面上的"文件". 一旦设置了合适的"钩子", 你就可以访问具 ...

  9. 【spring 7】spring和Hibernate的整合:声明式事务

    一.声明式事务简介 Spring 的声明式事务管理在底层是建立在 AOP 的基础之上的.其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者 ...

  10. Android IOS WebRTC 音视频开发总结(三四)-- windows.20150706

    最近好不容易更新了PC版的WEBRTC,总结下有哪些调整,文章来自博客园RTC.Blacker,支持原创,转载请说明出处. 图1:解决方案工程结构对比: 说明: 1, 最大的调整就是移除了VideoE ...