Windows动态库hid.dll
+ -

HID.DLL导出函数HidD_GetAttributes探究

2022-05-07 48 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源代码。不过实际的过程一致,只是代码细节上有所差异。

0 篇笔记 写笔记

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......
作者信息
USB中文网
B站搜索 站长漫谈 看视频。
pnpon内核开网,USB中文网,
busrom硬核技术网站长
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

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

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