友我科技PCSC双界面读写器YW-606开发指南

1.建立资源管理器的上下文

函数ScardEstablishContext()用于建立将在其中进行设备数据库操作的资源管理器上下文(范围)。

函数原型:LONG SCardEstablishContext(DWORD dwScope,  LPCVOID pvReserved1,  LPCVOID pvReserved2,  LPSCARDCONTEXT phContext);

各个参数的含义:

(1)dwScope:输入类型;表示资源管理器上下文范围,取值为:SCARD_SCOPE_USER(在用户域中完成设备数据库操作)、SCARD_SCOPE_SYSTEM(在系统域中完成设备数据库操作)。要求应用程序具有相应的操作权限。

(2)pvReserved1:输入类型;保留,必须为NULL。

(3)pvReserved2:输入类型;保留,必须为NULL。

(4)phContext:输出类型;建立的资源管理器上下文的句柄。

下面是建立资源管理器上下文的代码:

SCARDCONTEXT hSC;

LONG lReturn;

lReturn = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &hSC);

if ( lReturn!=SCARD_S_SUCCESS )

printf("Failed SCardEstablishContext\n");

2. 获得系统中安装的读卡器列表

函数ScardListReaders()可以列出系统中安装的读卡器的名字。

函数原型:LONG SCardListReaders(SCARDCONTEXT hContext,  LPCTSTR mszGroups,  LPTSTR mszReaders,  LPDWORD pcchReaders);

各个参数的含义:

(1)hContext:输入类型;ScardEstablishContext()建立的资源管理器上下文的句柄,不能为NULL。

(2)mszGroups:输入类型;读卡器组名,为NULL时,表示列出所有读卡器。

(3)mszReaders:输出类型;系统中安装的读卡器的名字,各个名字之间用’\0’分隔,最后一个名字后面为两个连续的’\0’。

(4)pcchReaders:输入输出类型;mszReaders的长度。

系统中可能安装多个读卡器,因此,需要保存各个读卡器的名字,以便以后与需要的读卡器建立连接。

下面是获得系统中安装的读卡器列表的代码:

char mszReaders[1024];

LPTSTR pReader, pReaderName[2];

DWORD dwLen=sizeof(mzsReaders);

int nReaders=0;

lReturn = SCardListReaders(hSC, NULL, (LPTSTR)mszReaders, &dwLen);

if ( lReturn==SCARD_S_SUCCESS )

{

pReader = (LPTSTR)pmszReaders;

while (*pReader !='\0'  )

{

if ( nReaders<2 ) //使用系统中前2个读卡器

pReaderName[nReaders++]=pReader;

printf("Reader: %S\n", pReader );

//下一个读卡器名

pReader = pReader + strlen(pReader) + 1;

}

}

3. 与读卡器(智能卡)连接

函数ScardConnect()在应用程序与读卡器上的智能卡之间建立一个连接。

函数原型:LONG SCardConnect(SCARDCONTEXT hContext,  LPCTSTR szReader,  DWORD dwShareMode,  DWORD dwPreferredProtocols,  LPSCARDHANDLE phCard,  LPDWORD pdwActiveProtocol);

各个参数的含义:

(1)hContext:输入类型;ScardEstablishContext()建立的资源管理器上下文的句柄。

(2)szReader:输入类型;包含智能卡的读卡器名称(读卡器名称由ScardListReaders()给出)。

(3)dwShareMode:输入类型;应用程序对智能卡的操作方式,SCARD_SHARE_SHARED(多个应用共享同一个智能卡)、SCARD_SHARE_EXCLUSIVE(应用独占智能卡)、SCARD_SHARE_DIRECT(应用将智能卡作为私有用途,直接操纵智能卡,不允许其它应用访问智能卡)。

(4)dwPreferredProtocols:输入类型;连接使用的协议,SCARD_PROTOCOL_T0(使用T=0协议)、SCARD_PROTOCOL_T1(使用T=1协议)。

(5)phCard:输出类型;与智能卡连接的句柄。

(6)PdwActiveProtocol:输出类型;实际使用的协议。

下面是与智能卡建立连接的代码:

SCARDHANDLE hCardHandle[2];

DWORD dwAP;

lReturn = SCardConnect( hContext, pReaderName[0],    SCARD_SHARE_SHARED,

SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCardHandle[0], &dwAP );

if ( lReturn!=SCARD_S_SUCCESS )

{

printf("Failed SCardConnect\n");

exit(1);

}

与智能卡建立连接后,就可以向智能卡发送指令,与其交换数据了。

4. 断开与读卡器(智能卡)的连接

在与智能卡的数据交换完成后,可以使用函数ScardDisconnect()终止应用与智能卡之间的连接。

函数原型:LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition);

各个参数的含义:

(1)hCard:输入类型;与智能卡连接的句柄。

(2)dwDisposition:输入类型;断开连接时,对智能卡的操作,SCARD_LEAVE_CARD(不做任何操作)、SCARD_RESET_CARD(复位智能卡)、SCARD_UNPOWER_CARD(给智能卡掉电)、SCARD_EJECT_CARD(弹出智能卡)。

下面是断开与智能卡连接的代码:

lReturn = SCardDisconnect(hCardHandle[0], SCARD_LEAVE_CARD);

if ( lReturn != SCARD_S_SUCCESS )

{

printf("Failed SCardDisconnect\n");

exit(1);

}

5. 释放资源管理上下文

在应用程序终止前时,应该调用函数ScardReleaseContext()释放资源管理器的上下文。

函数原型:LONG SCardReleaseContext(SCARDCONTEXT hContext);

各个参数含义:

(1)hContext:输入类型;ScardEstablishContext()建立的资源管理器上下文的句柄,不能为NULL。

下面是释放资源管理上下文的代码:

lReturn = SCardReleaseContext(hSC);

if ( lReturn!=SCARD_S_SUCCESS )

printf("Failed SCardReleaseContext\n");

以上介绍的通过PC/SC来操作智能卡的流程,可以封装在一个类中。例如,我们可以设计一个类:

class CYOWORFIDReader

{

private:

SCARDCONTEXT hSC;

LONG lReturn;

char mszReaders[1024];

LPTSTR pReader, pReaderName[2];

DWORD dwLen;

int nReaders, nCurrentReader;

SCARDHANDLE hCardHandle[2];

DWORD dwAP;

public:

CSmartReader(); //建立上下文、取读卡器列表

~CSmartReader(); //释放上下文

void SetCurrentReader(int currentReader);

int GetReaders(); //获得读卡器数目

int ConnectReader(); //与当前读卡器建立连接

int DisConnectReader(); //与当前读卡器断开连接

int SendCommand(BYTE command[], int commandLength, BYTE result[], int *resultLength); //向读卡器发送命令,并接收返回的数据。返回值为sw

};

这样,我们就可以方便地使用PC/SC接口了。

6. 向智能卡发送指令

函数ScardTransmit()向智能卡发送指令,并接受返回的数据。

函数原型:LONG SCardTransmit(SCARDHANDLE hCard, LPCSCARD_I0_REQUEST pioSendPci, LPCBYTE pbSendBuffer, DWORD cbSendLength, LPSCARD_IO_REQUEST pioRecvPci, LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength);

各个参数的含义:

(1)hCard:输入类型;与智能卡连接的句柄。

(2)pioSendPci:输入类型;指令的协议头结构的指针,由SCARD_IO_REQUEST结构定义。后面是使用的协议的协议控制信息。一般使用系统定义的结构,SCARD_PCI_T0(T=0协议)、 SCARD_PCI_T1(T=1协议)、SCARD_PCI_RAW(原始协议)。

(3)pbSendBuffer:输入类型;要发送到智能卡的数据的指针。

(4)cbSendLength:输入类型;pbSendBuffer的字节数目。

(5)pioRecvPci:输入输出类型;指令协议头结构的指针,后面是使用的协议的协议控制信息,如果不返回协议控制信息,可以为NULL。

(6)pbRecvBuffer:输入输出类型;从智能卡返回的数据的指针。

(7)pcbRecvLength:输入输出类型;pbRecvBuffer的大小和实际大小。

对于T=0协议,收发缓冲的用法如下:

(a)向智能卡发送数据:要向智能卡发送n>0字节数据时,pbSendBuffer 前4字节分别为T=0的CLA、INS、P1、P2,第5字节是n,随后是n字节的数据;cbSendLength值为n+5(4字节头+1字节Lc+n字节数据)。PbRecvBuffer将接收SW1、SW2状态码;pcbRecvLength值在调用时至少为2,返回后为2。

BYTE recvBuffer[260];

int sendSize, recvSize;

BTYE sw1, sw2;

BYTE    select_mf[]={0xC0, 0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00};

sendSize=7;

recvSize=sizeof(recvBuffer);

lReturn = SCardTransmit(hCardHandle[0], SCARD_PCI_T0, select_mf, sendSize,

NULL, recvBuffer, &recvSize);

if ( lReturn != SCARD_S_SUCCESS )

{

printf("Failed SCardTransmit\n");

exit(1);

}

//返回的数据,recvSize=2

sw1=recvBuffer[recvSize-2];

sw2=recvBuffer[recvSize-1];

(b)从智能卡接收数据:为从智能卡接收n>0字节数据,pbSendBuffer 前4字节分别为T=0的CLA、INS、P1、P2,第5字节是n(即Le),如果从智能卡接收256字节,则第5字节为0;cbSendLength值为5(4字节头+1字节Le)。PbRecvBuffer将接收智能卡返回的n字节,随后是SW1、SW2状态码;pcbRecvLength的值在调用时至少为 n+2,返回后为n+2。

BYTE     get_challenge[]={0x00, 0x84, 0x00, 0x00, 0x08};

sendSize=5;

recvSize=sizeof(recvBuffer);

lReturn = SCardTransmit(hCardHandle[0], SCARD_PCI_T0, get_challenge,

sendSize, NULL, recvBuffer, &recvSize);

if ( lReturn != SCARD_S_SUCCESS )

{

printf("Failed SCardTransmit\n");

exit(1);

}

//返回的数据, recvSize=10

sw1=recvBuffer[recvSize-2];

sw2=recvBuffer[recvSize-1];

//data=recvBuffer[0]----recvBuffer[7]

(c)向智能卡发送没有数据交换的命令:应用程序既不向智能卡发送数据,也不从智能卡接收数据,pbSendBuffer 前4字节分别为T=0的CLA、INS、P1、P2,不发送P3;cbSendLength 值必须为4。PbRecvBuffer从智能卡接收SW1、SW2状态码;pcbRecvLength值在调用时至少为2,返回后为2。

BYTE    set_flag[]={0x80, 0xFE, 0x00, 0x00};

sendSize=4;

recvSize=sizeof(recvBuffer);

lReturn = SCardTransmit(hCardHandle[0], SCARD_PCI_T0, set_flag, sendSize,

NULL, recvBuffer, &recvSize);

if ( lReturn != SCARD_S_SUCCESS )

{

printf("Failed SCardTransmit\n");

exit(1);

}

//返回的数据,recvSize=2

sw1=recvBuffer[recvSize-2];

sw2=recvBuffer[recvSize-1];

(d)向智能卡发送具有双向数据交换的命令:T=0协议中,应用程序不能同时向智能卡发送数据,并从智能卡接收数据,即发送到智能卡的指令中,不能同时有Lc和Le。这只能分两步实现:向智能卡发送数据,接收智能卡返回的状态码,其中,SW2是智能卡将要返回的数据字节数目;从智能卡接收数据(指令为0x00、0xC0、0x00、0x00、Le)。

BYTE get_response={0x00, 0xc0, 0x00, 0x00, 0x00};

BYTE    internal_auth[]={0x00, 0x88, 0x00, 0x00, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};

sendSize=13;

recvSize=sizeof(recvBuffer);

lReturn = SCardTransmit(hCardHandle[0], SCARD_PCI_T0, internal_auth,

sendSize, NULL, recvBuffer, &recvSize);

if ( lReturn != SCARD_S_SUCCESS )

{

printf("Failed SCardTransmit\n");

exit(1);

}

//返回的数据,recvSize=2

sw1=recvBuffer[recvSize-2];

sw2=recvBuffer[recvSize-1];

if ( sw1!=0x61 )

{

printf("Failed Command\n");

exit(1);

}

get_response[4]=sw2;

sendSize=5;

recvSize=sizeof(recvBuffer);

lReturn = SCardTransmit(hCardHandle[0], SCARD_PCI_T0, get_response,

sendSize, NULL, recvBuffer, &recvSize);

if ( lReturn != SCARD_S_SUCCESS )

{

printf("Failed SCardTransmit\n");

exit(1);

}

//返回的数据,recvSize=10

sw1=recvBuffer[recvSize-2];

sw2=recvBuffer[recvSize-1];

//data=recvBuffer[0]----recvBuffer[7]

RFID产品手册下载

PC/SC双界面读写器开发指南的更多相关文章

  1. IC卡接口芯片TDA8007的读写器设计

    摘要:阐述T=0传输协议,给出IC卡读写器中使用的IC卡APDU指令流程和原理框图:重点介绍其中的IC卡接口芯片Philips的TDA8007,给出通过TDA8007对CPU IC卡上下电过程.具体程 ...

  2. [PC]PHPCMS二次开发指南(上)

    ------------------------------------------------------------------------------------- PHPCMS本身功能已经很完 ...

  3. Andriod安卓下开发UHF读写器

    随着在Andriod设备上使用UHF读写器变得越来越广泛,友我科技独立研发了UHF读写器的android开发包,使用此开发包,工程师只需在工程中导入jar包,使用java语言就可以轻松的开发出Andr ...

  4. Google Chome浏览器下如何开发UHF读写器

    google Chrome浏览器不支持ocx,也就不能通过ocx来连接UHF读写器,只能使用RFID读写器云服务插件,通过javascript语言来连接和操控UHF读写器YW-602H.RFID读写器 ...

  5. nodejs开发指南读后感

    nodejs开发指南读后感 阅读目录 使用nodejs创建http服务器; supervisor的使用及nodejs常见的调式代码命令了解; 了解Node核心模块; ejs模板引擎 Express 理 ...

  6. RFID 读写器 Reader Writer Cloner

    RFID读写器的工作原理 RFID的数据采集以读写器为主导,RFID读写器是一种通过无线通信,实现对标签识别和内存数据的读出和写入操作的装置. 读写器又称为阅读器或读头(Reader).查询器(Int ...

  7. 常用的PC/SC接口函数

    PC/SC规范是一个基于WINDOWS平台的一个标准用户接口(API),提供了一个从个人电脑(Personal Computer)到智能卡(SmartCard)的整合环境,PC/SC规范建立在工业标准 ...

  8. PC/SC

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

  9. Knockout应用开发指南 第二章:监控属性(Observables)

    原文:Knockout应用开发指南 第二章:监控属性(Observables) 关于Knockout的3个重要概念(Observables,DependentObservables,Observabl ...

随机推荐

  1. MySQL数据库Group by分组之后再统计数目Count(*)与不分组直接统计数目的区别

    简述问题“统计最新时刻处于某一状态的设备的数量” 1. 首先子查询结果,可以看到每个设备最新的状态信息 2.1 在子查询的基础上,对设备状态进行分组,进行统计每个状态的设备数量 2.1.1 可以看到处 ...

  2. Cookie与Session会话技术

    Cookie与Session会话技术 一.什么是会话 会话:当用户打开浏览器,访问多个WEB资源,然后关闭浏览器的过程,称之为一个会话,选项卡,弹出页面都属于这个会话,且共享同一个session. 二 ...

  3. webpack4 配置

    package.json 开发环境/生产环境 webpack.config.js

  4. 利用WPF生成Q币充值二维码——扫码登录篇

    一.前言 虽然腾讯官方不支持使用二维码充值Q币,但对于喜欢钻研的人来说这不是问题,本文利用WPF技术讲解从扫码登录到生成Q币充值二维码的一整套解决方案. 因为充值Q币需要先用QQ号登录官网.所以我们首 ...

  5. Redis入门(四)-Java操作Redis

    <Redis入门>系列文章的第四篇,这一节看一下如何用Java版本的redis客户端工具--Jedis来操作redis. Jedis封装了丰富的api来对redis的五种数据类型 stri ...

  6. bbbbbb

    Blazor 机制初探以及什么是前后端分离,还不赶紧上车? 标签: Blazor .Net 上一篇文章我发了一个 BlazAdmin 的尝鲜版,这一次主要聊聊 Blazor 是如何做到用 C# 来写前 ...

  7. PLSQL设置查询快捷键

    Tools-->Preferences-->User Interface-->Editor-->AutoReplace 新建文本文件shortcut.txt(名称和路径可以自定 ...

  8. JavaWeb学习——Servlet相关的接口和类

    JavaWeb学习——Servlet相关的接口和类 摘要:本文主要学习了Servlet相关的接口和类. Servlet的接口和类 三种方式 实现Servlet有三种方式: 实现javax.servle ...

  9. OSG绘制空间凹多边形并计算其面积

    目录 1. 思路 1) 多边形分格化 2) 几何图元遍历 2. 实现 3. 参考 1. 思路 这个问题其实涉及到OSG中的两个问题:多边形分格化和几何图元遍历. 1) 多边形分格化 在OpenGL/O ...

  10. arcgis api 4.x for js 自定义叠加图片图层实现地图叠加图片展示(附源码下载)

    前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 4.x for js:esri 官网 api,里面详细的介绍 arcgis api 4.x 各个类 ...