HidD_* functions all fail due to an invalid HID handle (Windows HID C++ API)

I am having issues getting usage data from a Windows Precision Touchpad in my C++ desktop application. I have gotten the following working:

  • Registered for raw input
  • I am receiving WM_INPUT messages containing raw data
  • I can call GetRawInputData() to return a RAWINPUT structure

My next step has been trying to use the Hidpi.h utilities to determine which usages my touchpad support (HidP_GetCaps(), HidP_GetValueCaps(), etc...), and then get their values. To get things going, I am simply trying to print X, Y, tip switch, contact id, and max contact count).

In order to use the aforementioned utilities, I noticed from documentation that I generally need 2 things: Preparsed data (PHIDP_PREPARSED_DATA) and the actual Input or Feature Report.

This is where things started going wrong. Everything I have read said I should have been able to use HidD_GetPreparsedData() to get the first item. The HID device handle I'm passing is raw_data_buffer->header.hDevice, where raw_data_buffer is the PRAWINPUT type I populated from GetRawInputData(). Unfortunately, this fails. Calling GetLastError() returns ERROR_INVALID_HANDLE. I was unable to find any explanation...the handle wasn't NULL and matched the HID device I was trying to read from.

I found a different method to get the preparsed data:

...
preparsed_data_buffer = (PHIDP_PREPARSED_DATA)malloc( pp_data_buf_sz );
GetRawInputDeviceInfo( raw_data_buffer->header.hDevice, RIDI_PREPARSEDDATA, preparsed_data_buffer, &pp_data_buf_sz );
...

As far as I can tell, the data is correct. I was able to then able to use *_GetCaps() and _*GetValueCaps() to see supported usages.

11 Input Button Capabilites Found
Index:   0, IsRange: 0, UsagePage: 0X000D, Usage: 0X0042
Index:   1, IsRange: 0, UsagePage: 0X000D, Usage: 0X0047
Index:   2, IsRange: 0, UsagePage: 0X000D, Usage: 0X0042
Index:   3, IsRange: 0, UsagePage: 0X000D, Usage: 0X0047
Index:   4, IsRange: 0, UsagePage: 0X000D, Usage: 0X0042
Index:   5, IsRange: 0, UsagePage: 0X000D, Usage: 0X0047
Index:   6, IsRange: 0, UsagePage: 0X000D, Usage: 0X0042
Index:   7, IsRange: 0, UsagePage: 0X000D, Usage: 0X0047
Index:   8, IsRange: 0, UsagePage: 0X000D, Usage: 0X0042
Index:   9, IsRange: 0, UsagePage: 0X000D, Usage: 0X0047
Index:  10, IsRange: 0, UsagePage: 0X0009, Usage: 0X0001

17 Input Value Capabilites Found
Index:   0, IsRange: 0, UsagePage: 0X000D, Usage: 0X0051
Index:   1, IsRange: 0, UsagePage: 0X0001, Usage: 0X0030
Index:   2, IsRange: 0, UsagePage: 0X0001, Usage: 0X0031
Index:   3, IsRange: 0, UsagePage: 0X000D, Usage: 0X0051
Index:   4, IsRange: 0, UsagePage: 0X0001, Usage: 0X0030
Index:   5, IsRange: 0, UsagePage: 0X0001, Usage: 0X0031
Index:   6, IsRange: 0, UsagePage: 0X000D, Usage: 0X0051
Index:   7, IsRange: 0, UsagePage: 0X0001, Usage: 0X0030
Index:   8, IsRange: 0, UsagePage: 0X0001, Usage: 0X0031
Index:   9, IsRange: 0, UsagePage: 0X000D, Usage: 0X0051
Index:  10, IsRange: 0, UsagePage: 0X0001, Usage: 0X0030
Index:  11, IsRange: 0, UsagePage: 0X0001, Usage: 0X0031
Index:  12, IsRange: 0, UsagePage: 0X000D, Usage: 0X0051
Index:  13, IsRange: 0, UsagePage: 0X0001, Usage: 0X0030
Index:  14, IsRange: 0, UsagePage: 0X0001, Usage: 0X0031
Index:  15, IsRange: 0, UsagePage: 0X000D, Usage: 0X0056
Index:  16, IsRange: 0, UsagePage: 0X000D, Usage: 0X0054

3 Feature Value Capabilites Found
Index:   0, IsRange: 0, UsagePage: 0X000D, Usage: 0X0059
Index:   1, IsRange: 0, UsagePage: 0X000D, Usage: 0X0055
Index:   2, IsRange: 0, UsagePage: 0XFF00, Usage: 0X00C5

I found everything I expected. X (x1/x30), Y (x1/x31), and Contact ID (xD/x51) should be in my Input Report, the Tip Switch would be a button, and Max Contact Count (xD/x55) would be in my Feature Value Report.

Focusing on the Input/Feature reports next, I am running into my original problem. The 7th parameter to HidP_GetUsageValue() is a PCHAR to either the input or feature reports, but I don't know how to get them. HidD_GetInputReport() and HidD_GetFeature() both fail with the same invalid handle error I was seeing trying to get the preparsed data through that API.

After going through probably 10 threads or examples, I noticed somebody using their raw (unparsed) data to get input values as such:

HidP_GetUsageValue( HidP_Input, usages[ usage_idx ].page, 0, usages[ usage_idx ].usage, &val,
                    preparsed_data, (PCHAR)raw_data_buffer->data.hid.bRawData, hid_capabilities.InputReportByteLength );

This worked. I can get x, y, and contact ids from the input report...I guess because the raw input report must be the first block of raw data. However, I still can't get the feature report using HidP_GetUsageValue( HidP_Feature... because I don't know where that report is in the raw input.

I have spent over 10 hours researching for possible causes and workarounds, and have come up with nothing. For the purposes of my application I might be able to get away with just the Input Report values, but there has to be something I'm missing.

6/14 UPDATE: @RbMm @psmears Thank you for your comments. I didn't realize that the return from GetRawInputDeviceInfo(), using RIDI_DEVICENAME, was the symbolic path needed to create a file for my device. I didn't need to use SetupApi or cfgmgr32 to go through all the device interfaces. I'm still unable to create a file for my device though. Since I can see the path I'm looking for while enumerating all of the device interfaces, I decided to test by creating a new file for each one to rule out path format/encoding issues. Here was my output:

CM_Get_Device_Interface_List() found device #1.
Path: \\?\HID#VID_1FD2&PID_6103&MI_00&Col02#9&885ad2f&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030}
CrateFile() worked.

CM_Get_Device_Interface_List() found device #2.
Path: \\?\HID#VID_046D&PID_C077#6&b39df8e&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
CreateFile() failed with error: 0x5

CM_Get_Device_Interface_List() found device #3.
Path: \\?\HID#VID_B404&PID_0101&MI_01&Col01#7&22822429&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
CreateFile() failed with error: 0x20

CM_Get_Device_Interface_List() found device #4.
Path: \\?\HID#VID_B404&PID_0101&MI_01&Col02#7&22822429&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030}
CreateFile() failed with error: 0x20

CM_Get_Device_Interface_List() found device #5.
Path: \\?\HID#VID_1FD2&PID_6103&MI_01#9&20493974&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
CrateFile() worked.

CM_Get_Device_Interface_List() found device #6.
Path: \\?\HID#VID_0424&PID_274C&MI_01#8&2d3dcce0&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
CrateFile() worked.

CM_Get_Device_Interface_List() found device #7.
Path: \\?\HID#VID_B404&PID_0101&MI_01&Col03#7&22822429&0&0002#{4d1e55b2-f16f-11cf-88cb-001111000030}\KBD
CreateFile() failed with error: 0x5

CM_Get_Device_Interface_List() found device #8.
Path: \\?\HID#VID_B404&PID_0101&MI_00#7&3a45b06e&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}\KBD
CreateFile() failed with error: 0x5

CM_Get_Device_Interface_List() found device #9.
Path: \\?\HID#VID_1FD2&PID_6103&MI_00&Col01#9&885ad2f&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
CreateFile() failed with error: 0x20

CM_Get_Device_Interface_List() found device #10.
Path: \\?\HID#VID_05AC&PID_0265&MI_00&Col01#8&7741f1a&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
CrateFile() worked.

CM_Get_Device_Interface_List() found device #11.
Path: \\?\HID#VID_05AC&PID_0265&MI_00&Col02#8&7741f1a&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030}
CrateFile() worked.

CM_Get_Device_Interface_List() found device #12.
Path: \\?\HID#VID_05AC&PID_0265&MI_01&Col02#8&1f37ab5f&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030}
CrateFile() worked.

CM_Get_Device_Interface_List() found device #13.
Path: \\?\HID#VID_05AC&PID_0265&MI_01&Col03#8&1f37ab5f&0&0002#{4d1e55b2-f16f-11cf-88cb-001111000030}
CrateFile() worked.

CM_Get_Device_Interface_List() found device #14.
Path: \\?\HID#VID_05AC&PID_0265&MI_02#8&36fb37a4&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
CrateFile() worked.

CM_Get_Device_Interface_List() found device #15.
Path: \\?\HID#VID_05AC&PID_0265&MI_03#8&1323f9e2&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
CrateFile() worked.

CM_Get_Device_Interface_List() found device #16.
Path: \\?\HID#VID_05AC&PID_0265&MI_01&Col01#8&1f37ab5f&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
THIS is the device we want a file handle for. Path matches what we expect.
CreateFile() failed with error: 0x20

The device I'm wanting to connect to (#16 here) is the touchpad. The last several interfaces are associated with the same Apple Trackpad device, and creating a file for them works. The error "ERROR_FILE_NOT_FOUND (0x2)" doesn't make any sense to me.

Here is how I'm creating the file:

file_handle = CreateFile( comp_hid_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );

According to the MS documentation for OPEN_ALWAYS: "If the specified file does not exist and is a valid path to a writable location, the function creates a file and the last-error code is set to zero." That implies that this isn't a valid, writable location, but it definitely shows up when enumerating my interfaces.

Am I unable to open a file to the device since it was just sent raw input using WM_INPUT message?



Read more here: https://stackoverflow.com/questions/67925174/hidd-functions-all-fail-due-to-an-invalid-hid-handle-windows-hid-c-api

Content Attribution

This content was originally published by Danny Lovell at Recent Questions - Stack Overflow, and is syndicated here via their RSS feed. You can read the original post over there.

%d bloggers like this: