Windows动态库hid.dll
+ -

HID.DLL导出函数HidD_GetAttributes探究

2022-05-07 631 0

HidD_GetAttributes函数用于获取HID设备的基本信息,如设备的VendorID,ProductID和VersionNumber,对应于USB HID设备描述符的如下字段:

    WORD idVendor;           //厂商编号 
     WORD idProduct;         //产品编号 
     WORD bcdDevice;

HidD_GetAttributes函数原型

BOOLEAN HidD_GetAttributes(
  [in]  HANDLE           HidDeviceObject,
  [out] PHIDD_ATTRIBUTES Attributes
);

HidD_GetAttributes函数使用

  HIDD_ATTRIBUTES Attributes;
  ZeroMemory(&Attributes, sizeof(Attributes));
  Attributes.Size = sizeof(HIDD_ATTRIBUTES);
  if (!HidD_GetAttributes(tmp_DeviceHandle, &Attributes))
  {
      CloseHandle(tmp_DeviceHandle);
      continue;
  }

HidD_GetAttributes应用层实现

在Hid.dll导出函数与IOCTL对应大全http://www.usbzh.com/article/detail-929.html 一节,可知HidD_GetAttributes是通过IOCTL_HID_GET_COLLECTION_INFORMATION来实现的。

我们查看REACTOS的源代码hid.c中查看的HidD_GetAttributes源代码,路径位于:

E:\reactos\ReactOS-0.4.13-src-2020-0731\ReactOS-0.4.13\dll\win32\hid\hid.c

其具体的代码:

/*
 * HidD_GetAttributes                            EXPORTED
 *
 * @implemented
 */
HIDAPI
BOOLEAN WINAPI
HidD_GetAttributes(IN HANDLE HidDeviceObject,
                   OUT PHIDD_ATTRIBUTES Attributes)
{
  HID_COLLECTION_INFORMATION hci;
  DWORD RetLen;

  if(!DeviceIoControl(HidDeviceObject, IOCTL_HID_GET_COLLECTION_INFORMATION,
                                       NULL, 0,
                                       &hci, sizeof(HID_COLLECTION_INFORMATION),
                                       &RetLen, NULL))
  {
    return FALSE;
  }

  /* copy the fields */
  Attributes->Size = sizeof(HIDD_ATTRIBUTES);
  Attributes->VendorID = hci.VendorID;
  Attributes->ProductID = hci.ProductID;
  Attributes->VersionNumber = hci.VersionNumber;

  return TRUE;
}

可以看到,实际上是通过HID_COLLECTION_INFORMATION结构体来获取数据,最后再复制给HIDD_ATTRIBUTES Attributes结构体。

HID_COLLECTION_INFORMATION结构体的定义如下:

typedef struct _HID_COLLECTION_INFORMATION {

    //
    // DescriptorSize is the size of the input buffer required to accept
    // the collection descriptor returned by
    // IOCTL_HID_GET_COLLECTION_DESCRIPTOR.
    //

    ULONG   DescriptorSize;

    //
    // Polled is TRUE if this collection is a polled collection.
    //

    BOOLEAN Polled;

    //
    // Reserved1 must be set to zero.
    //

    UCHAR   Reserved1[ 1 ];

    //
    // Vendor ids of this hid device
    //
    USHORT  VendorID;
    USHORT  ProductID;
    USHORT  VersionNumber;

    //
    // Additional fields, if any, will be added at the end of this structure.
    //

} HID_COLLECTION_INFORMATION, *PHID_COLLECTION_INFORMATION;

HidD_GetAttributes内核层实现

通过HID.dll与整个HID驱动程序架构的关系揭密http://www.usbzh.com/article/detail-931.html 一节,可知,这个IOCTL请求是发给HIDCLASS.SYS的PDO的,由于HIDCLASS的PDO和FDO共用一套回调函数,故我们直接转到其IRP_MJ_DEVICE_CONTROL的回调函数HidClassDispatch中。

 DriverExtension->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HidClassDispatch;

实际的函数为HidClass_DeviceControl来处理的。

在ReactOS hidclass.c源代码中,对应IOCTL_HID_GET_COLLECTION_INFORMATION的处理如下:

  case IOCTL_HID_GET_COLLECTION_INFORMATION:
        {
            //
            // check if output buffer is big enough
            //
            if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(HID_COLLECTION_INFORMATION))
            {
                //
                // invalid buffer size
                //
                Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
                IoCompleteRequest(Irp, IO_NO_INCREMENT);
                return STATUS_INVALID_BUFFER_SIZE;
            }

            //
            // get output buffer
            //
            CollectionInformation = Irp->AssociatedIrp.SystemBuffer;
            ASSERT(CollectionInformation);

            //
            // get collection description
            //
            CollectionDescription = HidClassPDO_GetCollectionDescription(&CommonDeviceExtension->DeviceDescription,
                                                                         PDODeviceExtension->CollectionNumber);
            ASSERT(CollectionDescription);

            //
            // init result buffer
            //
            CollectionInformation->DescriptorSize = CollectionDescription->PreparsedDataLength;
            CollectionInformation->Polled = CommonDeviceExtension->DriverExtension->DevicesArePolled;
            CollectionInformation->VendorID = CommonDeviceExtension->Attributes.VendorID;
            CollectionInformation->ProductID = CommonDeviceExtension->Attributes.ProductID;
            CollectionInformation->VersionNumber = CommonDeviceExtension->Attributes.VersionNumber;

            //
            // complete request
            //
            Irp->IoStatus.Information = sizeof(HID_COLLECTION_INFORMATION);
            Irp->IoStatus.Status = STATUS_SUCCESS;
            IoCompleteRequest(Irp, IO_NO_INCREMENT);
            return STATUS_SUCCESS;
        }

可以看到,这里有一个重要的数据PreparsedDataLength,不过在HidD_GetAttributes中是不需要的,另外关于VendorID,ProductID和VersionNumber的获取,是直接通过Attributes来获取的。
而Attributes的内容来源于hidclass的fdo在IRP_MN_START_DEVICE时获取的描述符时获取的。
具体的调用关系为:
IRP_MJ_PNP.IRP_MN_START_DEVICE -> HidClassFDO_StartDevice ->HidClassFDO_GetDescriptors
而在HidClassFDO_GetDescriptors中是通过发送一个IOCTL_HID_GET_DEVICE_ATTRIBUTES到HIDUSB驱动中获取的。

NTSTATUS
HidClassFDO_GetDescriptors(
    IN PDEVICE_OBJECT DeviceObject)
{
    ...
    IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_DEVICE_ATTRIBUTES;
    IoStack->Parameters.DeviceIoControl.OutputBufferLength = sizeof(HID_DEVICE_ATTRIBUTES);
    Irp->UserBuffer = &FDODeviceExtension->Common.Attributes;
    Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
    ...
}

最终hidusb的代码如下:

 case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
        {
            if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(HID_DEVICE_ATTRIBUTES))
            {
                //
                // invalid request
                //
                Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
                DPRINT1("[HIDUSB] IOCTL_HID_GET_DEVICE_ATTRIBUTES invalid buffer\n");
                IoCompleteRequest(Irp, IO_NO_INCREMENT);
                return STATUS_INVALID_BUFFER_SIZE;
            }
            //
            // store result
            //
            DPRINT("[HIDUSB] IOCTL_HID_GET_DEVICE_ATTRIBUTES\n");
            ASSERT(HidDeviceExtension->DeviceDescriptor);
            Irp->IoStatus.Information = sizeof(HID_DESCRIPTOR);
            Attributes = Irp->UserBuffer;
            Attributes->Size = sizeof(HID_DEVICE_ATTRIBUTES);
            Attributes->VendorID = HidDeviceExtension->DeviceDescriptor->idVendor;
            Attributes->ProductID = HidDeviceExtension->DeviceDescriptor->idProduct;
            Attributes->VersionNumber = HidDeviceExtension->DeviceDescriptor->bcdDevice;

可以看到,这就获取的是设备描述符中相应的字段。

注:以上的源代码来自于REACTOS的源代码实现,而并非真实的windows源代码。不过实际的过程一致,只是代码细节上有所差异。

HID人机交互QQ群:564808376    UAC音频QQ群:218581009    UVC相机QQ群:331552032    BOT&UASP大容量存储QQ群:258159197    STC-USB单片机QQ群:315457461    USB技术交流QQ群2:580684376    USB技术交流QQ群:952873936   

0 篇笔记 写笔记

HID.dll报告描述符解析数据PreparsedData
前面我们提到了Hid.dll使用HidD_GetPreparsedData来获取一个不透明的报告描述符数据,使用该数据可以解析出很多关于HID设备的有用信息。如我们可以通过HidP_GetCaps来解析出HIDP_CAPS。hid.dll是HidD_GetPreparsedData函数通过IOCT......
Windows服务HidServ及Hid.dll工作原理
在Windows操作系统下,使用自定义HID接口通讯时,离不开hid.dll,就算你使用的是hidapi等第三方HID库,它的底层也是HID.dll这个库。而我们使用系统原生的hid.dll库时,也一般是这样引用的。#include#pragma comment(......
Hid.dll导出函数与IOCTL对应大全
Windows封装的HID相关系列API函数,其本质是通过WIN32 API函数DeviceIoControl函数来与内核进行通讯的,而DeviceIoControl中一个重要的参数就是dwIoControlCode,代表了该次通讯的功能。BOOLWINAPIDeviceIoControl(......
Hid.dll导出函数大全
可以通过Depends.exe查看c:/windows/system32/hid.dll导出的所有函数HidD_FlushQueueHidD_FreePreparsedDataHidD_GetAttributesHidD_GetConfigurationHidD_GetFeatureHi......
HID.dll与整个HID驱动程序架构的关系揭密
这里我们首先回顾一下HID相关驱动之间的调用关系图。USB HID设备主要由包括以下几个驱动:HidClass.sys 这个驱动是HID驱动的类驱动,其实就是一个DLL,用于处理USB HID驱动通用功能。HIDUSB.sys 这个驱动是HID驱动的miniPort驱动,即我们常说的迷你小端口......
HID.DLL导出函数HidD_GetAttributes探究
HidD_GetAttributes函数用于获取HID设备的基本信息,如设备的VendorID,ProductID和VersionNumber,对应于USB HID设备描述符的如下字段: WORD idVendor; //厂商编号 WORD idProduct......
HID.DLL导出函数HidD_GetInputReport探究
HidD_GetInputReport的功能HidD_GetInputReport用于获取输入报告(input report)。说明:不过微软关于此函数有一个特别的说明,就是只能获取当前的输入报告,不能连续的获取,因为可能会丢数据。所以如果要连续的获取输入报告,需要使用ReadFile函数。同时,......
Hid.dll导出函数HidD_GetPreparsedData
Hid.dll导出函数HidD_GetPreparsedData可以通过IOCTL获取一个PHIDP_PREPARSED_DATA的不透明数据结构。通过这个数据结构可以出报告描述符的相关信息。如本人在开发HID调试工具HidTool.exe的代码如下:do{ ... PHID......
Hid.dll获取字符串函数实现
Hid.dll中获取字符串的函数包括以下:HidD_GetProductStringHidD_GetManufacturerStringHidD_GetSerialNumberStringHidD_GetIndexedString这些函数分别通过不同的IOCTL来与HIDCLAS.SYS进行通......
Hid.dll报告缓存数量的设置与获取
HidD_GetNumInputBuffers和HidD_SetNumInputBuffers分别用于从HID设备中读取的报告内容的最大缓冲数量.BOOLEAN HidD_GetNumInputBuffers( [in] HANDLE HidDeviceObject, [out] PUL......
HID.DLL函数HidD_GetMsGenreDescriptor与IOCTL_HID_GET_MS_GENRE_DESCRIPTOR
HID.DLL导出HidD_GetMsGenreDescriptor函数,其使用IOCTL_HID_GET_MS_GENRE_DESCRIPTOR与HIDCLASS.SYS通讯。而HIDCLASS.SYS将此请求下发给设备,用于获取设备的类型信息。而在HIDUSB.SYS中,通过下发Functio......
hid.dll导出函数HidD_GetPhysicalDescriptor与IOCTL_GET_PHYSICAL_DESCRIPTOR
hid.dll导出函数HidD_GetPhysicalDescriptor用于获取HID物理描述符,其通过IOCTL_GET_PHYSICAL_DESCRIPTOR发送给HIDCLASS.SYS。HIDCLASS创建一个主功能号为IRP_MJ_INTERNAL_DEVICE_CONTROL,IOCT......
关注公众号
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!