第8章 USB接口HID设备 201
表8-11 用于HID设备的API函数 用于了解HID设备情况的API函数(hid.dll) HidD_GetAttributes 请求获得HID设备的厂商ID、产品ID和版本号 HidD_FreePreparsedData 释放函数HidD_GetPreparsedData所使用的资源 HidD_GetHidGuid 请求获得HID设备的GUID HidD_GetIndexString 请求获得由索引识别的字符串 HidD_GetManufactureString 请求获得设备制造商字符串 HidD_GetPhysicalDescriptor 请求获得设备实体字符串 HidD_GetPreparsedData 请求获得与设备能力信息相关的缓冲区的代号 HidD_GetProductString 请求获得产品字符串 HidD_GetSerialNumberString 请求获得产品序列号字符串 HidP_GetButtonCaps 请求获得HID报表中所有按钮的能力 HidP_GetCaps 请求获得用于描述设备能力的结构的指针 HidP_GetLinkCollectionNotes 请求获得描述在顶层集合中的连接集合(Link Collection)关系的结构的数组 HidP_GetSpecificButtonCaps 请求获得报表中按钮的能力,该请求可以设定一个Usage Page、Usage或是Link Collection HidP_GetSpecificValueCaps 请求获得报表中数值的能力,该请求可以设定一个Usage Page、Usage或是Link Collection HidP_GetValueCaps 请求获得HID报表中所有数值的能力 HidP_MaxUsageListLength 请求获得HID报表中可以回传的按钮的最大数目,该请求可以设定一个Usage Page HidP_UsageListDifference 比较两个按钮列表,并且求出在一个列表中设定而在另一个列表中没有设定的按钮 用于从设备读取、向设备传送报表的API函数(hid.dll) HidD_GetFeature 从设备读取一个特征报表 HidD_SetFeature 向设备传送一个特征报表 HidP_GetButtons 从设备读取包含每个按下的按钮的用法(Usage)的缓冲区的指针,该请求可以设定一个Usage Page HidP_GetButtonEx 从设备读取包含每个按下的按钮的Usage和Usage Page的缓冲区的指针 HidP_GetScaledUsageValue 从设备读取一个已经经过比例因子调整的有符号数值 HidP_GetUsageValue 从设备读取一个指向数值的指针 HidP_GetUsageValueArray 从设备读取包含多个数据项的Usage的数据 HidP_SetButtons 向设备传送设置按钮的数据 HidP_SetScaledUsageValue 将一个实际数值转换成设备使用的逻辑数值,并将其插入到报表中 HidP_SetUsageValue 向设备传送数据 HidP_SetUsageValueArray 向设备传送包含多个数据项的Usage的数据 HidD_FlushQueue 清空输入缓冲区 HidD_GetNumInputBuffer 获得驱动程序用于存储输入报表的环形缓冲区的大小,默认值是8 HidD_SetNumInputBuffer 设置驱动程序用于存储输入报表的环形缓冲区的大小 用于查找和识别设备的API函数(setupapi.dll) SetupDiGetClassDevs 获得HID的信息,针对已安装的设备,回传一个指向其信息集的代码 SetupDiEnumDeviceInterfaces 请求获得设备信息群内的一个设备的信息 SetupDiGetDeviceInterfaceDetail 请求获得设备的路径 SetupDiDestroyDeviceInfoList 释放SetupDiGetClassDevs使用的资源 用于打开、关闭设备和实现数据传送的API函数(kernal32.dll) 202 计算机高级接口实践 CreatFile 取得设备的路径后,调用该函数获得设备代号 WriteFile 向设备传送输出报表 ReadFile 从设备读取输入报表 CloseHandle 关闭设备,释放CreateFile所使用的资源
8.5.2 查找HID的过程
在实现HID的访问之前,首先要查找指定(根据设备的厂商ID、产品ID和产品序列号)的HID。查找指定设备的过程如下:
? 调用函数HidD_GetHidGuid获得USB设备的GUID;
? 调用函数SetupDiGetClassDevs,获得一个包含全部HID信息的结构数组的指针,下面根据此数组逐项查找指定的HID;
? 调用函数SetupDiEnumDeviceInterfaces,填写SP_DEVICE_INTERFACE_DATA结构的数据项,该结构用于识别一个HID设备接口;
? 调用函数SetupDiGetDeviceInterfaceDetail,获得一个指向该设备的路径名; ? 调用函数CreateFile,获得设备句柄;
? 调用函数HidD_GetAttributes,填写HIDD_ATTRIBUTES结构的数据项,该结构包含设备的厂商ID、产品ID和产品序列号,比照这些数值确定该设备是否是查找的设备。
查找HID的流程如下图。
第8章 USB接口HID设备 203
开始 调用HidD_GetHidGuid获得GUID 调用SetupDiGetClassDevs获得全部HID信息 调用SetupDiEnumDeviceInterfaces获得特定HID识别信息 调用SetupDiGetDeviceInterfaceDetail获得特定HID路径名 调用CreateFile获得特定HID句柄 调用HidD_GetAttributes获得特定HID的厂商ID、产品ID 找到指定HID? No No 查找完毕? Yes 结束 Yes 图8-6 查找设备的流程
下面介绍VB实现的查找过程。 (1) 获得GUID
应用程序要与HID设备通信之前,必须先获得HID类别的GUID(Globally Unique Indentifer)。GUID是一个128位的数值,每个对象都有惟一的GUID。HID类别的GUID包含在hidclass.h文档内,可以接引用,或是使用 HidD_GetHidGuid函数来取得HID类别的 GUID。
? 函数声明 Public Declare Function HidD_GetHidGuid Lib \) As Long ? GUID结构说明 Public Type GUID Data1 As Long Data2 As Integer Data3 As Integer 204 计算机高级接口实践 Data4(7) As Byte End Type ? 变量说明 Dim HidGuid as GUID ? 调用 Call HidD_GetHidGuid(HidGuid) (2) 获得HID的结构数组
得到GUID后调用SetupDiGetClassDevs函数传回所有已经连接并且检测过的HID包含其信息的结构数组的地址。
? 函数声明
Public Declare Function SetupDiGetClassDevs Lib \\ ByRef ClassGuid As GUID, _ ByVal Enumerator As String, _ ByVal hwndParent As Long, _ ByVal Flags As Long) _ As Long ? 常量说明
Public Const DIGCF_PRESENT = &H2
Public Const DIGCF_DEVICEINTERFACE = &H10
? 调用
hDevInfoSet = SetupDiGetClassDevs( HidGuid, _ ?通过HidD_GetHidGuid函数获得GUID vbNullString, _ 0, _ (DIFCG_PRESENT or DIFCG_DEVICEINTERFACE) _ )
该函数的ClassGuid参数值为通过HidD_GetHidGuid函数获得GUID。Enumerator与hwndParent参数没有用到,Flags参数是两个定义在setupapi.h文档内的系统常数。代码中的Flags常数告诉SetupDiGetClassDevs函数只寻找目前存在(连接并且检测过)的设备接口,并且是HID类别的成员。
返回值hDevlnfoSet是包含所有连接并且检测到的全部HID的信息的结构数组的地址。在程序中并不需要访问hDevInfoSet的元素,只需要将hDevlnfSet值传给SetupDiEnumDeviceInterfaces函数即可。
当程序不再需要hDevInfoSet指向的数组时,应该调用 SetupDiDestroyDeviceInfo List函数来释放资源。
下面在hDevInfoSet指向的结构数组中查找。 (3) 识别HID接口
接下来调用SetupDiEnumDeviceInterfaces,填写SP_DEVICE_INTERFACE_DATA结构的数据项,该结构用于识别一个HID设备接口。
? 函数声明 Public Declare Function SetupDiEnumDeviceInterfaces Lib \ ByVal DeviceInfoSet As Long, _ 第8章 USB接口HID设备 205
ByVal DeviceInfoData As Long, _
ByRef InterfaceClassGuid As GUID, _ ByVal MemberIndex As Long, _
ByRef DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA _ )As Long
? 结构定义
Public Type SP_DEVICE_INTERFACE_DATA cbSize As Long
InterfaceClassGuid As GUID Flags As Long Reserved As Long End Type
? 变量说明
Dim Result as Long
Dim MemberIndex as Long
Dim MyDeviceInterfaceData as SP_DEVICE_INTERFACE_DATA
? 调用
MyDeviceInterfaceData.cbSize = LenB(MyDeviceInterfaceData) MemberIndex = 0
Result = SetupDiEnumDeviceInterfaces( DeviceInfoSet, _ ?SetupDiGetClassDevs的返回值 0, _ HidGuid, _ ?通过HidD_GetHidGuid函数获得的GUID MemberIndex, _ ?第一次调用设置为0 MyDeviceInterfaceData _ )
参数cbSize是SP_DEVICE_INTERFACE_DATA结构的大小,以字节为单位。在调用SetupDiEnumDeviceInterfaces函数之前,cbSize必须储存在结构内来当做传递的参数。
参数HidGuid和DeviceInfoSet是函数之前的传回值。
DeviceInfoData是SP_DEVICE_INTERFACE_DATA结构的指针,用来限制检测特定设备的接口。MemberIndex是DeviceInfoSet数组的索引值,在遍历整个数组的循环中MemberIndex递增。MyDeviceInterfaceData是回传的结构,用来识别HID的一个接口。
(4) 获得设备路径
下面通过调用SetupDiGetDeviceInterfaceDetail函数用来获得另外一个结构:SP_DEVICE_INTERFACE_DETAIL_DATA。此结构与前一个函数SetupDiEnumDeviceInterfaces所识别的设备接口有关。结构的DevicePath成员是一个设备路径,应用程序可以用此路径来实现与该设备的通信。
? 函数声明: Public Declare Function SetupDiGetDeviceInterfaceDetail Lib \ Alias \ ByVal DeviceInfoSet As Long, _ ByRef DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA, _ ByVal DeviceInterfaceDetailData As Long, _ ByVal DeviceInterfaceDetailDataSize As Long, _ ByRef RequiredSize As Long, _ ByVal DeviceInfoData As Long _ ) As Long