Reputation: 331
I want to read a HID feature report from a USB device, I have the VendorID and the DeviceID, and it's guaranteed that there will be only one device matching that description.
This shouldn't be difficult, but I feel so confused reading the MSDN documentation.
I got it working on linux in a couple hours, thanks to libudev :). But I need a native windows implementation (preferably VC++, and likely using Hidsdi.h and or Setupapi.h)
Can anyone please point me in the right direction.
Upvotes: 1
Views: 4871
Reputation: 331
Got it working with native windows libraries, it's probably not the right way to accomplish this task, but it works. I'd advice against using this code directly, since it's terrible, but feel free to read it for anything useful.
It finds the HID with device ID: 0021 and vendor ID: 2833 then reads the feature report 0x0F;
#include <Windows.h>
#include <iostream>
#include <Setupapi.h>
#include <Hidsdi.h>
using namespace std;
// returns true if full_string contains the substring
BOOL findSubstring(WCHAR *full_string, const char *substring){
unsigned int c = 0, d = 0;
while (true) {
if (substring[d] == '\0')
return true;
if (full_string[c] == '\0')
return false;
d = (full_string[c] == substring[d]) ? d + 1 : 0;
if (c++ > MAX_PATH)
return false;
}
}
int main()
{
GUID guid;
HDEVINFO hDeviceInfo;
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceDetail;
DWORD i = 0;
WCHAR *devicePath = NULL;
// Obtain a handle to the connected HID devices
HidD_GetHidGuid(&guid);
hDeviceInfo = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hDeviceInfo == INVALID_HANDLE_VALUE) {
cerr << "Failed to get Device Handle" << endl;
return 1;
}
i = 0;
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
// Enumerate through all the HID devices
while (SetupDiEnumDeviceInterfaces(hDeviceInfo, NULL, &guid, i++, &deviceInterfaceData)) {
ULONG requiredSize;
// Get the details with null values to get the required size of the buffer
SetupDiGetDeviceInterfaceDetail(hDeviceInfo, &deviceInterfaceData, NULL, 0, &requiredSize, 0);
deviceDetail = (PSP_INTERFACE_DEVICE_DETAIL_DATA)malloc(requiredSize);
deviceDetail->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
// Fill the buffer with the device details
if (!SetupDiGetDeviceInterfaceDetail(hDeviceInfo, &deviceInterfaceData, deviceDetail, requiredSize, &requiredSize, NULL)) {
cerr << "Could not obtain the HID device for some reason" << endl;
SetupDiDestroyDeviceInfoList(hDeviceInfo);
free(deviceDetail);
return 1;
}
// Check that the device path contains two strings, which are our vendorID and pathID.
if (findSubstring(deviceDetail->DevicePath, "vid_2833") && findSubstring(deviceDetail->DevicePath, "pid_0021")) {
devicePath = deviceDetail->DevicePath;
}
}
if (devicePath != NULL) {
// Open the HID
HANDLE HIDfile = CreateFile(devicePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD err = GetLastError();
if (err != 0) {
cerr << "unable to obtain read permissions for the HID device, error: " << err << endl;
} else {
// Allocate buffer for the feature report
BYTE buffer[30];
memset(buffer, 0, sizeof(buffer[0]));
buffer[0] = 0x0FU; // Feature report 0x0F
if (!HidD_GetFeature(HIDfile, buffer, sizeof(buffer))){
cout << "Feature report failed" << endl;
}
else {
cout << "Feature report successful" << endl;
for (int i = 0; i < 30; i++)
cout << hex << (int)buffer[i];
}
cout << endl;
}
}
// probably small memory leak
// free(deviceDetail);
SetupDiDestroyDeviceInfoList(hDeviceInfo);
return 0;
}
Upvotes: 4