USB HID协议中文版 - USB接口HID设备 - 图文 联系客服

发布时间 : 星期日 文章USB HID协议中文版 - USB接口HID设备 - 图文更新完毕开始阅读2c2ecd2fccbff121dd368396

第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 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