常用的PC/SC接口函数
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接口函数的更多相关文章
- PC/SC双界面读写器开发指南
友我科技PCSC双界面读写器YW-606开发指南 1.建立资源管理器的上下文 函数ScardEstablishContext()用于建立将在其中进行设备数据库操作的资源管理器上下文(范围). 函数原型 ...
- PC/SC
简介 PC/SC规范由微软公司与世界其它著名的智能卡厂商组成的PC/SC工作组提出的.PC/SC规范是一个基于WINDOWS平台的一个标准用户接口(API),提供了一个从个人电脑(Personal C ...
- MVC支付宝PC网站接口对接
PC网站支付接口,请参考支付宝官方文档:https://b.alipay.com/signing/productSet.htm?navKey=all 1.需要提供签约账号.商户密钥 2.代码实现: 支 ...
- 支付宝PC网站接口对接
PC网站支付接口,请参考支付宝官方文档:https://b.alipay.com/signing/productSet.htm?navKey=all 1.需要提供签约账号.商户密钥 2.代码实现: 支 ...
- 对比讲解lambda表达式与传统接口函数实现方式
在本号之前写过的一些文章中,笔者使用了lambda表达式语法,一些读者反映说代码看不懂.本以为java 13都已经出了,java 8中最重要特性lambda表达式大家应该都掌握了,实际上还是存在大量的 ...
- sysfs接口函数的建立_DEVICE_ATTR(转)
sysfs接口函数到建立_DEVICE_ATTR 最近在弄Sensor驱动,看过一个某厂家的成品驱动,里面实现的全都是sysfs接口,hal层利用sysfs生成的接口,对Sensor进行操作. 说道s ...
- sysfs接口函数到建立_DEVICE_ATTR
sysfs接口函数到建立_DEVICE_ATTR 最近在弄Sensor驱动,看过一个某厂家的成品驱动,里面实现的全都是sysfs接口,hal层利用sysfs生成的接口,对Sensor进行操作. 说道s ...
- USB CCID协议和PC/SC标准
CCID是USB Chip/Smart Card Interface Devices,也就是USB芯片智能卡接口设备,是USB规范下的一种设备类型.就像HID设备一样,需要参考USB规范来写固件程序来 ...
- ioctl、文件操作接口函数以及nand的升级模式的操作过程详解
概述 内核中驱动文件的操作通常是通过write和read函数进行的,但是很多时候再用户空间进行的操作或许不是内核中公共代码部分提供的功能,此时就需要使用一种个性化的方法进行操作--ioctl系统调用. ...
随机推荐
- windows下忘记mysql密码怎么办
长时间不用mysql,密码忘记了怎么办,按照下面的步骤可以重新设置密码: 1.先把mysql服务停了,右键计算机-->选择管理-->选择服务和应用程序-->选择服务-->找到m ...
- 手机app测试之我见
app端功能测试不是单纯的点点点,在实际的工作中,测试小白需要从业务入手,熟悉基本测试点.测试技巧和方法,以点带面,从功能和思维入手,避免眼高手低: app端测试,首先我们需要考虑不同的机型系统.不同 ...
- CSS3里的常用选择器总结
选择器 属性选择器: img[src="images/2.jpg"] 开头匹配: a[href ^="page/"] ...
- makefile 学习(一)
一.Makefile的基本规则 GNU make 规则: target ... : prerequisites ... command .... .... target - 目 ...
- EXT学习之——Extjs 文本框 TextField 添加点击(onclick)事件方法
{ xtype:'textfield', listeners: { render: function(p) { // Append the Panel to the click handler's a ...
- SQL模式匹配
标准的SQL的模式匹配允许你使用“_”匹配任何单个字符,而“%”匹配任意数目字符(包括零个字符).在 MySQL中,SQL的模式缺省是忽略大小写的.下面显示一些例子.注意在你使用SQL模式时,你不能使 ...
- 数据库中GUID的生成
GUID, 即Globally Unique Identifier(全球唯一标识符) 也称作 UUID(Universally Unique IDentifier) . GUID是一个通过特定算法产生 ...
- 学习练习 java 线程
package com.hanqi.xc; import java.util.*; public class lianxi extends Thread { public void run() { c ...
- mysql 连接命令 表管理 ,克隆表,临时表,字符串属性,设定语句间的分隔符
连接和断开连接mysql -h host -u user -p (即,连接的主机.用户名和使用的密码).断开输入QUIT (或\q)随时退出: 表管理克隆表注意:create table ... li ...
- 揭秘TPM安全芯片技术及加密应用
揭秘TPM安全芯片技术及加密应用 首发:http://safe.it168.com/a2012/0912/1396/000001396884.shtml 从2003年开始,重要数据丢失已经成为严重的信 ...