Skip to content

Commit 7a55fd4

Browse files
author
Fredrik Orderud
committed
Switch to using SetupDi for enumerating HID devices
Done to more easily get access to HW IDs through the SPDRP_HARDWAREID property. The HW IDs are returned on a "HID\VID_0B0E&PID_0312&REV_0213&MI_03&Col02" format. WARNING: Instance information seem to be lacking in the HW IDs, so it's not possible to uniquely identify a given device based on the HW ID.
1 parent c2ab0bf commit 7a55fd4

File tree

1 file changed

+69
-14
lines changed

1 file changed

+69
-14
lines changed

HidUtil/HID.hpp

Lines changed: 69 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
#pragma once
22
#include <windows.h>
3-
#include <cfgmgr32.h> // for CM_Get_Device_Interface_List
43
#include <hidsdi.h>
4+
#include <SetupAPI.h>
55
#include <wrl/wrappers/corewrappers.h>
66

77
#include <cassert>
88
#include <string>
99
#include <vector>
1010

1111
#pragma comment(lib, "hid.lib")
12-
#pragma comment(lib, "mincore.lib")
12+
#pragma comment (lib, "Setupapi.lib")
1313

1414

1515
/** RAII wrapper of PHIDP_PREPARSED_DATA. */
@@ -63,28 +63,83 @@ class HID {
6363
GUID hidguid = {};
6464
HidD_GetHidGuid(&hidguid);
6565

66-
const ULONG searchScope = CM_GET_DEVICE_INTERFACE_LIST_PRESENT; // only currently 'live' device interfaces
67-
68-
ULONG deviceInterfaceListLength = 0;
69-
CONFIGRET cr = CM_Get_Device_Interface_List_SizeW(&deviceInterfaceListLength, &hidguid, NULL, searchScope);
70-
assert(cr == CR_SUCCESS);
71-
72-
// symbolic link name of interface instances
73-
std::wstring deviceInterfaceList(deviceInterfaceListLength, L'\0');
74-
cr = CM_Get_Device_Interface_ListW(&hidguid, NULL, const_cast<wchar_t*>(deviceInterfaceList.data()), deviceInterfaceListLength, searchScope);
75-
assert(cr == CR_SUCCESS);
66+
// Retrieve a list of all present USB devices with a device interface.
67+
HDEVINFO devInfoSet = SetupDiGetClassDevsW(&hidguid, NULL, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
68+
assert(devInfoSet != INVALID_HANDLE_VALUE);
7669

7770
std::vector<Match> results;
78-
for (const wchar_t * currentInterface = deviceInterfaceList.c_str(); *currentInterface; currentInterface += wcslen(currentInterface) + 1) {
79-
auto result = CheckDevice(currentInterface, query, verbose);
71+
for (DWORD devIdx = 0;; ++devIdx) {
72+
// get device information
73+
SP_DEVINFO_DATA devInfoData = {};
74+
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
75+
if (!SetupDiEnumDeviceInfo(devInfoSet, devIdx, &devInfoData))
76+
break;
77+
78+
// list of hardware IDs
79+
auto hw_id_list = GetHWIds(devInfoSet, &devInfoData);
80+
if (verbose) {
81+
for (const auto& hw_id : hw_id_list)
82+
printf(" HW ID: %ls\n", hw_id.c_str());
83+
}
84+
85+
// get device interfaces
86+
SP_DEVICE_INTERFACE_DATA devIfData = {};
87+
devIfData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
88+
BOOL ok = SetupDiEnumDeviceInterfaces(devInfoSet, NULL, &hidguid, devIdx, &devIfData);
89+
assert(ok);
90+
91+
std::vector<BYTE> devIfcDetailDataBuf;
92+
SP_DEVICE_INTERFACE_DETAIL_DATA_W* devIfcDetailData = nullptr;
93+
{
94+
DWORD size = 0;
95+
SetupDiGetDeviceInterfaceDetailW(devInfoSet, &devIfData, NULL, 0, &size, NULL); // expected to fail
96+
97+
devIfcDetailDataBuf.resize(size, (BYTE)0);
98+
devIfcDetailData = (SP_DEVICE_INTERFACE_DETAIL_DATA_W*)devIfcDetailDataBuf.data();
99+
devIfcDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
100+
101+
// get details about a device interface
102+
ok = SetupDiGetDeviceInterfaceDetailW(devInfoSet, &devIfData, devIfcDetailData, size, &size, NULL);
103+
assert(ok);
104+
}
105+
106+
auto result = CheckDevice(devIfcDetailData->DevicePath, query, verbose);
80107
if (!result.name.empty())
81108
results.push_back(std::move(result));
82109
}
83110

111+
SetupDiDestroyDeviceInfoList(devInfoSet);
112+
84113
return results;
85114
}
86115

87116
private:
117+
/** Get list of hardware IDs for a device. */
118+
static std::vector<std::wstring> GetHWIds(HDEVINFO devInfoSet, SP_DEVINFO_DATA* devInfoData) {
119+
// Get required size for device property
120+
DWORD type = 0;
121+
DWORD size = 0;
122+
SetupDiGetDeviceRegistryPropertyW(devInfoSet, devInfoData, SPDRP_HARDWAREID, &type, NULL, 0, &size); // expected to fail
123+
124+
// Get SPDRP_HARDWAREID device property in REG_MULTI_SZ string format
125+
std::vector<wchar_t> hw_ids(size/sizeof(wchar_t), L'\0');
126+
BOOL ok = SetupDiGetDeviceRegistryPropertyW(devInfoSet, devInfoData, SPDRP_HARDWAREID, &type, (BYTE*)hw_ids.data(), size, NULL);
127+
assert(ok);
128+
129+
return ParseMultiSz(hw_ids.data());
130+
}
131+
132+
/** Parse REG_MULTI_SZ string into a list of strings. */
133+
static std::vector<std::wstring> ParseMultiSz(const wchar_t* ptr) {
134+
std::vector<std::wstring> result;
135+
// parse list of zero-terminated strings that are terminated by a null-pointer
136+
while (*ptr) {
137+
result.emplace_back(ptr);
138+
ptr += lstrlenW(ptr) + 1; // advance to next string
139+
}
140+
return result;
141+
}
142+
88143
static Match CheckDevice(const wchar_t* deviceName, const Query& query, bool verbose) {
89144
FileHandle hid_dev(CreateFileW(deviceName,
90145
GENERIC_READ | GENERIC_WRITE,

0 commit comments

Comments
 (0)