USB-HID协议中文版 - 图文 下载本文

206 计算机高级接口实践

? 结构声明

Public Type SP_DEVICE_INTERFACE_DETAIL_DATA cbSize As Long

DevicePath As Byte End Type

? 变量定义

Dim Needed as Long, DetailData as long

Dim MyDeviceInterfaceDetailData As SP_DEVICE_INTERFACE_DETAIL_DATA Dim DetailDataBuffer() as Byte Dim DevicePathName As String

? 调用

MyDeviceInterfaceData.cbSize = LenB(MyDeviceInterfaceData)

Result = SetupDiGetDeviceInterfaceDetailA( DeviceInfoSet, _ DeviceInterfaceData, _ 0, _ 0, _ Needed, _ 0 _ )

DetailData = needed

MyDeviceInterfaceDetailData.cbSize = Len(MyDeviceInterfaceDetailData) ReDim DetailDataBuffer(Needed)

Call RtlMoveMemory(DetailDataBuffer(0), MyDeviceInterfaceDetailData, 4) Result = SetupDiGetDeviceInterfaceDetailA( DeviceInfoSet, _ DeviceInterfaceData, _ VarPtr(DetailDataBuffer(0)), _ DetailData, _ Needed, _ 0 _ )

? 转换成字符串,再转换成Unicode并从中删除4个字符得到设备路径 DevicePathName = Cstr(DetailDataBuffer())

DevicePathName = StrCovn(DevicePathName, vbUnicode)

DevicePathName = Right$(DevicePathName, Len(DevicePathName)-4)

DeviceInterfaceDetailDataSize包含DeviceInterfaceData结构的大小,以字节为单位。但是,在调用SetupDiGetDeviceInterfaceDetail函数之前无法知道此数值的大小,如果没有DeviceInterfaceDetailDataSize函数,SetupDiGetDeviceInterfaceDetail函数不会传回所需的结构。

这个问题的解决方式是两次调用SetupDiGetDeviceInterfaceDetail函数。第一次调用时GetLastError函数会传回错误信息,即:The data erea passed to a system call is too small,但是RequireSize参数会包含正确的DeviceInterfaceDetailDataSize数值。再次调用时传递此传回值,函数就会执行成功。

(5) 获得设备句柄

取得设备的路径以后,就可以准备开始与设备通信。使用CreateFile来打开一个HID设备,并且取得此设备的句柄,使用设备的句柄来与设备交换数据。当不再需要访问此设备时,应该调用CIoseHandle函数来关闭设备并释放系统资源。

第8章 USB接口HID设备 207

? 函数声明:

Public Declare Function CreateFile Lib \ ByVal lpFileName As String, _ ByVal dwDesiredAccess As Long, _ ByVal dwShareMode As Long, _

ByRef lpSecurityAttributes As Long, _ ByVal dwCreationDisposition As Long, _ ByVal dwFlagsAndAttributes As Long, _ ByVal hTemplateFile As Long _ ) As Long

? 常量定义

Public Const GENERIC_READ = &H80000000 Public Const GENERIC_WRITE = &H40000000 Public Const FILE_SHARE_READ = &H1 Public Const FILE_SHARE_WRITE = &H2 Public Const OPEN_EXISTING = 3

? 调用

HidDevice = CreateFile( _ DevicePathName, _

GENERIC_READ Or GENERIC_WRITE, _

(FILE_SHARE_READ Or FILE_SHARE_WRITE), _ 0, _

OPEN_EXISTING, _ 0, _ 0 )

(6) 获得设备的厂商ID、产品ID和产品序列号

要识别一个设备是否是所要的设备,只要比较此设备的厂商与产品ID 即可。

HidD_GetAttributes函数用来取得一个包含厂商与产品ID以及产品的版本号码的结构。

? 函数声明

Public Declare Function HidD_GetAttributes Lib \ByVal HidDeviceObject As Long, _

ByRef Attributes As HIDD_ATTRIBUTES _ ) As Long

? 结构说明

Public Type HIDD_ATTRIBUTES Size As Long

VendorID As Integer ?厂商ID ProductID As Integer ?产品ID VersionNumber As Integer ?产品版本号 End Type

? 变量定义

Dim DeviceAttributes As HIDD_ATTRIBUTES

? 调用

DeviceAttributes.Size = LenB(DeviceAttributes) Result = HidD_GetAttributes( _ HidDevice, _ ?由CreateFile函数返回 DeviceAttributes )

208 计算机高级接口实践 HidDevice是由 CreateFile函数所传回的设备句柄。如果CreateFile函数传回的是非零值,DeviceAttributes结构就会填写正确值。应用程序可以由DeviceAttributes结构取得厂商ID、产品ID以及产品的版本号码。

如果厂商与产品ID不是想查找的,应用程序应该使用CloseHandle函数来关闭该设备,然后移到下一个SetupDiEnumDeviceInterfaces所检测到的下一个HlD继续查找。当应用程序检测到指定的设备或是检测完全部HID,它应该调用

SetupDiDestroyDeviceInfoList函数来释放SetupDiGetClassDevs函数所保留的资源。

8.5.3 获得HID的能力

获得设备的能力是可以进一步了解HID的手段,但不是必须的。如果在查找设备时,如果通过厂商ID、产品ID和产品序列号可以确定特定的设备,一般是已知设备的细节信息了。如果不通过厂商ID、产品ID和产品序列号确定设备,另一个方法是通过获得设备能力来确定设备。

获得HID的能力的过程主要经过以下几个步骤:

? 先使用HidD_GetPreparsedData函数获得一个包含设备能力信息的缓冲区的指

针,调用HidP_GetCaps获得描述HID的能力的数据结构; ? 调用HidP_GetValueCaps取得描述能力的数值。 (1) 获得描述HID能力的数据结构

? 函数声明 Public Declare Function HidD_GetPreparsedData Lib \ ByVal HidDeviceObject As Long, _ ByRef PreparsedData As Long ) As Long ? 变量定义 Dim PreparsedData As Long ? 调用 Result = HidD_GetPreparsedData (HidDevice, _ ? 由CreateFile获得的设备句柄 PreparsedData _ ) PreparsedData是一个包含数据的缓冲区的指针。程序并不需要访问缓冲区内的数据,只需要将缓冲区的开始地址传递给其他的API函数。当应用程序不再需要PreparsedData时,它应该调用HidD_FreePreparsedData函数来释放系统资源。

接下来调用HidP_GetCaps,该函数传回一个结构,里面包含设备能力的信息,包括设备的Usage Page、Usage、报表长度以及按钮能力和数值能力等的数目。如果不使用厂商与产品ID来识另设备,HidP_GetCaps函数传回的设备能力信息可以帮助决定是否继续与此设备通信。

? 函数声明 Public Declare Function HidP_GetCaps Lib \ ByVal PreparsedData As Long, _ ByRef Capabilities As HIDP_CAPS ) As Long ? 结构定义 Public Type HIDP_CAPS 第8章 USB接口HID设备 209

Usage As Integer ? 用法 UsagePage As Integer ? 用法页 InputReportByteLength As Integer ? 输入报表长度 OutputReportByteLength As Integer ? 输出报表长度 FeatureReportByteLength As Integer ? 特征报表长度 Reserved(16) As Integer

NumberLinkCollectionNodes As Integer ? 由函数HidP_GetLinkCollectionNodes ? 返回的顶层集合连接数目 NumberInputButtonCaps As Integer ? 由函数HidP_GetButtonCaps返回的

? 包含输入按钮能力的结构HIDP_BUTTON_ ? CAPS的数目 NumberInputValueCaps As Integer ? 由函数HidP_GetValueCaps返回的

? 包含输入数值能力的结构HIDP_VALUE_ ‘ CAPS的数目 NumberInputDataIndices As Integer ? 在输入报表中有关按键和数值的数据

? 指示器(Data Indices)的数目 NumberOutputButtonCaps As Integer ? 由函数HidP_GetButtonCaps返回的

? 包含输出按钮能力的结构HIDP_BUTTON_ ? CAPS的数目 NumberOutputValueCaps As Integer ? 由函数HidP_GetValueCaps返回的

? 包含输出数值能力的结构HIDP_VALUE_ ‘ CAPS的数目 NumberOutputDataIndices As Integer ? 在输出报表中有关按键和数值的数据 ? 指示器(Data Indices)的数目 NumberFeatureButtonCaps As Integer ? 由函数HidP_GetButtonCaps返回的

? 包含特征按钮能力的结构HIDP_BUTTON_ ? CAPS的数目 NumberFeatureValueCaps As Integer ? 由函数HidP_GetValueCaps返回的

? 包含特征数值能力的结构HIDP_VALUE_ ‘ CAPS的数目 NumberFeatureDataIndices As Integer ? 在特征报表中有关按键和数值的数据 ? 指示器(Data Indices)的数目 End Type

? 变量定义

Dim Capabilities As HIDP_CAPS

? 调用

Result = HidP_GetCaps (_ PreparsedData, _ ? 由函数HidD_GetPreparsedData定义 Capabilities )

HidP_GetCaps函数填写Capabilities结构中的数据项,Capabilities结构成员说明了HID的基本信息。这些信息包括:

? 用法页和用法:UsagePage、Usage;

? 输入、输出和特征报表长度:InputReportByteLength、

OutputReportByteLength和 FeatureReportByteLength;

? 由函数HidP_GetLinkCollectionNodes返回的顶层集合连接数目

NumberLinkCollectionNodes

? 在输入、输出和特征报表的按钮、数值和数据指示器的的数目。

210 计算机高级接口实践

(2) 获得描述HID数值能力的数据结构

通过HidP_GetCaps获得的HID的基本能力信息不是能从设备得到全部信息,还可以调用另一个函数HidP_GetValueCap,该函数可以获得报表描述符中的数值和按钮的能力。HidP_GetValueCap返回的是包含了报表描述符中全部数值信息的结构的指针。

? 函数声明

Public Declare Function HidP_GetValueCaps Lib \ ByVal ReportType As Integer, _ ByRef ValueCaps As Byte, _ ByRef ValueCapsLength As Integer, _ ByVal PreparsedData As Long _ ) As Long

? ReportType常量定义

Public Const HidP_Input = 0 Public Const HidP_Output = 1 Public Const HidP_Feature = 2

Public Type HidP_Value_Caps UsagePage As Integer ReportID As Byte IsAlias As Long BitField As Integer LinkCollection As Integer LinkUsage As Integer LinkUsagePage As Integer IsRange As Long IsStringRange As Long IsDesignatorRange As Long IsAbsolute As Long HasNull As Long Reserved As Byte BitSize As Integer ReportCount As Integer Reserved2 As Integer Reserved3 As Integer Reserved4 As Integer Reserved5 As Integer Reserved6 As Integer LogicalMin As Long LogicalMax As Long PhysicalMin As Long PhysicalMax As Long UsageMin As Integer UsageMax As Integer StringMin As Integer StringMax As Integer DesignatorMin As Integer DesignatorMax As Integer DataIndexMin As Integer DataIndexMax As Integer End Type

? 变量定义

Dim ValueCaps(1023) As Byte ? 调用

Result = HidP_GetValueCaps (_ HidP_Input, _