卷 5
上面说了,很多情况下,得直面 ResourceManager 。
既然如此,就耐心分析分析。
RESOURCEMANAGER
Class RESOURCEMANAGER[6]
属性
HANDLE hContext
方法
RESOURCEMANAGER()
~RESOURCEMANAGER()
RESPONSECODE EstablishContext (
IN DWORD Scope, // A scope indicator (see below)
IN DWORD Reserved1, // Reserved for future use to allow privileged // administrative programs to act on behalf of
// another user
IN DWORD Reserved2 // Reserved for future use to allow privileged // administrative programs to act on behalf of
// another terminal
)
建立与 ICC ResourceManager 通讯的上下文。
Scope :
SCARD_SCOPE_USER (在用户域中完成设备数据库操作)、 SCARD_SCOPE_SYSTEM (在系统域中完成设备数据库操作)。要求应用程序具有相应的操作权限。在 PCSC-LITE
中就不用操心了,只有 SCARD_SCOPE_SYSTEM 。
RESPONSECODE ReleaseContext()
释放已经建立的通讯上下文。
RESOURCEDB
Class RESOURCEDB[6]
这个专门用来体现 ICC Resource Manager 的主要责任,包括维护系统已知的 ICCSPs,cards 和 readers 的信息。
看这个名字,就明白些了。名字和风水很有关系。这在设计中,专门有提到命名的方法,
名字起得不好,最终会遭到重构。
RESOURCEDB , DB 就是数据库。提供了各种方法用于管理这些信息。手段当然和一般的 DB 有些类似,包括 insert , delete , create 各种 resources 之间的联系,查询数据库。
RESOURCEDB 实际从 RESOURCEDBQUERY 派生,并继承了 RESOURCEDBQUERY 的方法。
属性
RESOURCEMANAGER resmgr
方法
RESOURCEDB(IN RESOURCEMANAGER resmgr)
这招是什么?很正常,初始化。
那是表面。
实际体现了组合优于继承的大师级设计思想。
~RESOURCEDB()
RESPONSECODE IntroduceReader(
IN STR ReaderName // Friendly name to be associated with the // reader
IN STR DeviceName // System-specific name of the reader device. // Should conform to OS-specific naming // conventions.
)
组织说,相关的安装程序或读卡器驱动会用到这个函数。
把读卡器介绍给 Resource Manager database 。关联上 ReaderName , DeviceName.
看看,被介绍给 Resource Manager database ,从此和 Resource Manager 有了千丝万缕的
联系。
RESPONSECODE ForgetReader(IN STR ReaderName//Friendly name associated with
reader
)
咳。得罪了 ResourceManager ,被从团体中,剔除出去。
RESPONSECODE IntroduceReaderGroup(
IN STR GroupName // Group name to be added to the // Resource Manager database
)
ResourceManager 的收金人 Resource Manager database ,建立了一个读卡器组,
还起了名字 GroupName 。准备广收门徒。
RESPONSECODE ForgetReaderGroup(
IN STR GroupName // Group name to be removed from the Resource // Manager database
)
这个 GroupName ,犯了风水大忌,被 Resource Manager database 删除了。
RESPONSECODE AddReaderToGroup(
IN STR ReaderName // Name of Reader
IN STR GroupName // Group name to which Reader is to be added
)
前面的 IntroduceReaderGroup 说明了,立了牌子,起了名,准备收读卡器,
充实组员。 Reader 组员名字, GroupName 组名字。
RESPONSECODE RemoveReaderFromGroup(
IN STR ReaderName // Name of Reader
IN STR GroupName // Group name from which Reader is to be // removed
)
某组员,得罪了 DB ,或出意外了, DB 把它从 Group 中剔除。
RESPONSECODE IntroduceCardType(
IN STR CardName // Friendly name for the card being introduced
IN BYTE[] ATRRefVal // ATR reference value to match in determining card type
IN BYTE[] ATRMask // Mask which is logically AND’d with an card ATR // prior to comparison with the ATR reference value
IN BYTE[] ProviderId // Unique identifier for the primary service provider, // encoding is system specific
IN GUID[] Interfaces // List of unique identifiers for the card Interfaces // supported by the card
)
根据 ATR ,相关的 Mask , ICCSP ,和卡接口,把 card type 介绍给 DB.
这个函数在什么时候使用,在 ICCSP 安装的时候使用到。
从前面,你能看出 Resource Manager 命令 Resource Manager DB 去招募读卡器。
在谈卷7的时候,大家知道了读卡器经常欺负 card type 。
所以,还得招募 card type ,要不读卡器去欺负谁?读卡器就是工头,卡卡们就是
广大工人。
RESPONSECODE ForgetCardType(
IN STR CardName // Friendly name for the card to be removed
)
有个卡卡离开了。 DB 把它从花名册中删除。
RESOURCEQUERY
Class RESOURCEQUERY[6]
上面提到了。 RESOUCEQUERY 是 DB 的 parent.
老子英雄儿好汉。
这里采用了继承,体现了 has-a 的关系。设计大师如是说。
RESOUCEQUERY(IN RESOURCEMANAGER resmgr)
~RESOURCEQUERY()
RESPONSECODE ListReaderGroups(
OUT STR[] Groups // Array of strings containing the Group names
)
列出 DB 中所有读卡器组名。开始阅兵了。
RESPONSECODE ListReaders(
IN STR[] Groups // Array of strings containing Group names of // interest
OUT STR[] Readers // Array of strings containing Readers within the // Groups
)
列出 DB 中 Groups 这些组中所有读卡器的名字。
RESPONSECODE ListCardTypes(
IN BYTE[] ATR // ATR string to compare against known card types; // maybe NULL
IN GUID[] Interfaces // Array of GUIDs associated with the desired // interfaces
OUT STR[] Cards // Array of strings containing Card Types
)
返回所有的匹配 ATR 或者 interface 的 card types. 如果 ATR 和 Interface 都是 NULL ,则
返回系统中所有的 card types.
ATR 的匹配是通过查找 DB ,把参数 ATR 和 DB 中的 ATR 的 ATRMask 与操作后,和 DB 中
ATR 比较。如果参数 ATR 是 NULL ,则那么列出所有的卡类型。
RESPONSECODE GetProviderId(
IN STR CardName // Friendly name for a Card Type
OUT BYTE[] ProviderId // Reference to the Primary SP(s)
)
给定 Card Type 的 name ,查询该种 Card Type 能够提供的 SP id.
RESPONSECODE ListInterfaces(
IN STR CardName // Friendly name for a Card Type
OUT GUID[] Interfaces // Array of GUIDs associated with the supported // Interfaces
)
根据给定的 card type 名字,返回该 card type 对应的 interfaces .
SCARDTRACK
Class SCARDTRACK[6]
要认识 SCARDTRACK ,先认识 SCARD_READERSTATE.
structure {
STR Reader; // reader name
VOID UserData; // user defined data
DWORD CurrentState; // current state of reader at time of call
DWORD EventState; // state of reader after state change } SCARD_READERSTATE;
Reader 要被监控的读卡器的名字
UserData 任意的应用相关数据
CurrentState 读卡器的当前状态,可以是如下值或如下值的组合
SCARD_STATE_UNAWARE 对于 APPLICATION 来说,读卡器状态未知
SCARD_STATE_IGNORE APPLICATION 对这个读卡器不感兴趣,排除出监控行列
SCARD_STATE_UNAVAILABLE APPLICATION 认为读卡器处于不可用状态
SCARD_STATE_EMPTY APPLICATION 认为读卡器中没有卡
SCARD_STATE_PRESENT APPLICATION 认为读卡器中已经插入卡片
SCARD_STATE_ATRMATCH APPLICATION 认为匹配目标 ATR 卡片已经插入读卡器,这种状态假设 SCARD_STATE_PRESENT 成立。
SCARD_STATE_EXCLUSIVE APPLICATION 认为读卡器中的卡操作排它使用,采用了独占机制。这种状态假设 SCARD_STATE_PRESENT 成立。
SCARD_STATE_INUSE APPLICATION 认为读卡器中卡正被一个或多个应用程序使用。
这种状态假设 SCARD_STATE_PRESENT 成立。
EventState 从 Resource Manager 获取到的读卡器的当前状态。
状态值可以是如下值或值的组合。
SCARD_STATE_IGNORE APPLICATION 已经设置了 IGNORE 状态。
SCARD_STATE_CHANGED 读卡器的状态发生了变化。
SCARD_STATE_UNKNOWN
Resource Manger 发现给定读卡器的名字没有被注册。设置该位同时也设置。 SCARD_STATE_CHANGED.
SCARD_STATE_UNAVAILABLE 读卡器不可用。
SCARD_STATE_EMPTY 读卡器中没有卡。
SCARD_STATE_PRESENT 读卡器已经插入卡。
SCARD_STATE_ATRMATCH 已经找到和目标 ATR 匹配的卡。如果该位被设置,则同时设置 SCARD_STATE_PRESENT.
SCARD_STATE_EXCLUSIVE 读卡器中的卡采用了排它机制。
SCARD_STATE_INUSE 读卡器中的卡正被一个或多个应用程序使用。
如果该位被设置,则同时设置 SCARD_STATE_PRESENT.
接着讲 SCARDTRACK
SCARDTRACK(IN RESOURCEMANGER resmgr)
这招式,提过了。
~SCARDTRACK()
RESPONSECODE LocateCards(
IN STR[] Cards // Array of strings giving the names of the Card // Types of interest
IN OUT SCARD_READERSTATE[] ReaderStates // Array of READERSTATE // structures for readers of interest
)
这是个非阻塞函数。根据第一个参数提供的 card type 名字,在第二个参数
中返回读卡器状态。
RESPONSECODE GetStatusChange(
IN OUT SCARD_READERSTATE[] ReaderStates // Array of READERSTATE // structures for readers of interest
IN DWORD Timeout // Time-out value in milliseconds
)
这是个阻塞函数。调用该方法,发生阻塞,直到 ReaderStates 中表示
的状态发生改变或者超时。
Timeout 是 INFINITE 时候,表示永久等待。
多好呀,能够永久等待,直到某个 Reader 的状态发生变化。
Timeout 是0,则该函数立即返回。
RESPONSECODE Cancel()
取消阻塞的 GetStatusChange() 函数。
SCARDCOMM
Class SCARDCOMM[6]
这个类的主要职责 提供和特定的卡或读卡器的通讯接口。
管理连接,控制传输,收发命令,和提供卡状态信息。
属性
private RESOURCEMANAGER resmgr // Reference to a RESOURCEMANAGER // object
private HANDLE hCard // Handle to a Context associated with communication to a specific card and/or Reader. Set to NULL on object creation. This context is established using the Connect()method and destroyed using Disconnect().
方法
SCARDCOMM(RESOURCEMANAGER resmgr)
这招不再提了。入门招式。
~SCARDCOMM()
RESPONSECODE Connect(
IN STR ReaderName // Friendly name for a Reader
IN DWORD Flags // Desired access mode information
IN DWORD PreferredProtocols // Card communications protocols that may be used
OUT DWORD ActiveProtocol // Protocol actually in use
)
Flags 访问模式 表明是否可共享访问读卡器
PreferredProtocols 通讯协议 T0 T1
实际使用的协议在 ActiveProtocol 中返回
RESPONSECODE Reconnect(
IN DWORD Flags // desired access mode
IN DWORD PreferredProtocols // card communications protocols
// which may be used
IN DWORD Initialization // Specify card initialization to be performed
OUT DWORD ActiveProtocol // protocol actually in use
)
这个方法用来清除错误。
Initialization 参数用来指定重新连接时候的附加动作
SCARD_RESET_CARD 热复位
SCARD_UNPOWER_CARD 冷复位
可以在 Flags 更改连接协议。
RESPONSECODE Disconnect(
IN DWORD Disposition // Desired Card disposition action
)
Dispostion 指定附加动作
拔除卡片
复位卡片
断电关闭卡片
弹出卡片
没收卡片
RESPONSECODE Status(
OUT STR[] Reader // Friendly name of the connected reader
OUT DWORD State // Current status the connection
OUT DWORD ActiveProtocol // protocol actually in use
OUT BYTE Atr[] // ATR data buffer
)
返回当前连接的状态
Reader 返回所连接读卡器的名字
State 返回当前的读卡器状态
如果有卡片插入读卡器
ActiveProtocol 返回通讯的握手协议
Atr 返回卡片的 ATR
State
SCARD_UNKNOWN
无法通讯。
SCARD_ABSENT
读卡器中没有卡片。
SCARD_PRESENT
读卡器中已经插入卡片,但未到达可以使用的位置。
SCARD_SWALLOWED
读卡器中已经插入卡片,且到达可以使用的位置,但是还没有上电。
SCARD_POWERED
卡片已经上电,但是 hanlder 还无法识别卡模式。
SCARD_NEGOTIABLE
卡片已经复位,并等待 PTS 协商。
SCARD_SPECIFIC
卡片已经复位,特定的通讯协议已经建立。
RESPONSECODE BeginTransaction()
事务处理开始
RESPONSECODE EndTransaction()
事务处理结束
RESPONSECODE Cancel()
解除 BeginTransaction 给其它 APPLICATION 带来的阻塞
RESPONSECODE Transmit(
IN SCARD_IO_HEADER SendPci // Send protocol structure
IN BYTE[] SendBuffer // Data buffer for send data
IN OUT SCARD_IO_HEADER RecvPci // Receive protocol structure
IN OUT BYTE[] RecvBuffer // Data buffer for receive data
OUT DWORD RecvLength // Length of received data
)
收发函数
但前进之前,先停下,看看
structure {
DWORD Protocol;
DWORD Length;
} SCARD_IO_HEADER;
Protocol 通讯协议
Length SCARD_IO_HEADER 结构体长度
继续前进。
RecvBuffer 接收缓冲区
RecvLength 接收到的数据长度
SendBuffer 发送缓冲区
RESPONSECODE Control(
IN DWORD ControlCode // Vendor-defined control code
IN BYTE[] InBuffer // Input data buffer
IN OUT BYTE[] OutBuffer // Output data buffer
OUT DWORD OutBufferLength // Length of data in output data buffer
)
这个嘛?通过 Ioctl 对读卡器进行直接通讯。主要目的是提供与产商
定义功能特征的通讯。
RESPONSECODE GetReaderCapabilities (
IN OUT DWORD Tag // Value of tag associated with attribute to retrieve
OUT BYTE[] Buffer // Data returned
)
返回读卡器属性 ( 卷3 ).
RESPONSECODE SetReaderCapabilities (
IN DWORD Tag // Value of tag associated with attribute to retrieve
IN BYTE[] Buffer // Data returned
)
设置读卡器属性 ( 卷3 ).
卷 5 结束。
声明:
如果目前,您仅仅只想用用 API 函数,或者您想先体验体验,
见网络上的 vc 中 PCSC 接口编程,
或者直接看 PCSC-LITE 提供 API 头文件,
或者直接看 testpcsc.c 文件。
小结
大家有空的话,可以考虑看看卷 2 ,卷 3 ,卷4,卷 8 ,卷 9 ,卷 10 。
这些卷和应用的关系已经很小了。这里就不再消耗您的宝贵时间 ( 生命 ) 了。
下面开始对 PCSC-LITE 的代码解说。
快! The sands of time are running out for you.