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. SDUT 3311 数据结构实验之串三:KMP应用

    数据结构实验之串三:KMP应用 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Problem Description 有n个小朋友 ...

  2. 使用git管理github上的项目

    使用git可以把我们的项目代码上传到github上面去,方便自己管理,如何使用git?觉得是每位程序猿所必需要有的谋生技能,所以在此记录一下自己学会使用的这个过程: 一.需要注册github账号,这样 ...

  3. 【Unity Shaders】学习笔记——SurfaceShader(八)生成立方图

    [Unity Shaders]学习笔记——SurfaceShader(八)生成立方图 转载请注明出处:http://www.cnblogs.com/-867259206/p/5630261.html ...

  4. Filter Blue Light for Better Sleep(APP 推荐)

    Filter Blue Light for Better Sleep By Carolyn Mohr11 May, 2016 Many people like to use their phones ...

  5. opencv 连通域需要的函数解析

    OpenCV支持大量的轮廓.边缘.边界的相关函数,相应的函数有moments.HuMoments.findContours.drawContours.approxPolyDP.arcLength.bo ...

  6. .NET MVC4.0与CA对接

    1.改web.confog 2.引用CA提供的 dll 3.在controller层加个方法,记得加上授权认证的特性,获取信息 [Authorize] publi void calogin() { H ...

  7. 简单jQuery实现选项框中列表项的选择

    这段代码非常的简单,仅仅作为自己的一个小小的记录! ok,先上一个简单的图例,效果如下(注意:这只是一个简单的例子,不过可以根据这个简单的例子,变化出更为复杂的效果)! 代码也非常的简单,如下所示(注 ...

  8. JavaCC首页、文档和下载 - 语法分析生成器 - 开源中国社区

    JavaCC首页.文档和下载 - 语法分析生成器 - 开源中国社区

  9. c++ builder TListView控件按字符串排序(根据网上代码亲测ok)

    //--------------------------------------------------------------------------- /* 首先将一个列表框控件安放在Form上, ...

  10. leetcode 26

    26. Remove Duplicates from Sorted Array Given a sorted array, remove the duplicates in place such th ...