Repository navigation
fix(discovery): resolve USB location via parent node for HID devices - #296
Conversation
WindowsUsbLocationProvider queried DEVPKEY_Device_LocationInfo directly on
the PnP node HidDevicePathParser resolves a HID device interface path to
(the HID collection's own node) -- but that node never carries the
property; only the physical USB device node one level up in the device
tree does. Confirmed on real bootloader hardware: a bootloader's HID node
returns no LocationInfo at all via WMI, while its DEVPKEY_Device_Parent
node returns the exact same value the same physical port reports in
serial/CDC mode. This silently broke location-key resolution for every
real HID device (always null, no exception), defeating the cross-mode
correlation daqifi-desktop#655 depends on.
- New LocationParentWalker: pure, WMI-independent walk-up logic (bounded to
4 hops), unit tested with a fake query function.
- WindowsUsbLocationProvider now walks to DEVPKEY_Device_Parent and
retries when the direct lookup is empty.
- Two related bugs found and fixed along the way:
- WMI's GetDeviceProperties throws ManagementException("Not found") when
reading a property key it couldn't resolve on a given node (only
surfaced once two keys were requested together) -- property reads are
now defensive per-entry.
- DEVPKEY_Device_Parent values come back with lowercase hex segments,
which fails the uppercase-only instance-ID validation regex unless
normalized before the next hop's query.
Bench-validated: the same physical device's location key now resolves to
the identical "Port_#0001.Hub_#0001" in both serial mode and HID bootloader
mode.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
PR Summary by QodoFix Windows HID USB location resolution by walking parent PnP nodes
AI Description
Diagram
High-Level Assessment
Files changed (3)
|
Code Review by Qodo
1.
|
Address Qodo review feedback on PR #296: QueryLocationByCaption passed the first WMI-returned DeviceID straight into the parent-walk without the InstanceIdRegex validation the HID-device-path flow already enforces, even though that value gets interpolated into a WQL string literal. Now validated the same way both paths use, plus single-quote escaping in the WQL literal as defense-in-depth. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Summary
WindowsUsbLocationProvider(added in #290) queriesDEVPKEY_Device_LocationInfodirectly on the PnP nodeHidDevicePathParserresolves a HID device interface path to — but that node (the HID collection's own PnP node) never carries the property. Only the physical USB device node one level up in the device tree does.Confirmed on real bootloader hardware (a DAQiFi device forced into PIC32 HID bootloader mode): the bootloader's HID node returns no
LocationInfoat all via WMI (not an exception — the property is simply absent), while querying itsDEVPKEY_Device_Parentnode returns the exact same value (Port_#0001.Hub_#0001) the same physical port reports in serial/CDC mode.This silently broke location-key resolution for every real HID device — always
null, no exception, no visible failure — which defeats the entire point of the cross-mode correlation daqifi-desktop#655 depends on (PR 692 there is the consumer). #290's own test plan explicitly flagged this exact case as unverified on real Windows hardware; this PR closes that gap.Changes
LocationParentWalker: pure, WMI-independent walk-up logic (bounded to 4 hops to guard against a pathological/cyclic parent chain), unit tested with a fake query function — following the same "extract the pure logic" patternHidDevicePathParseralready uses.WindowsUsbLocationProvidernow walks toDEVPKEY_Device_Parentand retries when the direct lookup on a node comes back empty.GetDevicePropertiesthrowsManagementException("Not found")when reading a property key it couldn't resolve on a given node — only surfaced once two keys (LocationInfo+Parent) were requested in the same call. Property reads are now defensive per-entry (TryGetStringProperty).DEVPKEY_Device_Parentvalues come back from WMI with lowercase hex segments (e.g.5&2c705bfe&0&1), which failsInstanceIdRegex(uppercase-only, by design, to safely interpolate into WQL) unless normalized before the next hop's query — without this the walk silently stopped one hop too early even with the parent-walk fix in place.Test plan
dotnet build Daqifi.Core.sln -c Release— 0 warnings/errorsdotnet test Daqifi.Core.sln -c Release— 1391/1392 passed (1 pre-existing unrelated flake inContinuousDeviceFinderTests, reproduces identically onmainwithout this change)LocationParentWalkerunit tests (7 cases: immediate resolution, one-hop walk, lowercase-parent normalization, empty-string-treated-as-not-found, no-parent termination, malformed-parent termination, cyclic-chain bounded termination)Daqifi.Core.dll, loaded it via reflection against the realWindowsUsbLocationProvidertype, and confirmed the same physical DAQiFi device's location key resolves to the identicalPort_#0001.Hub_#0001in both serial mode (GetLocationKey("COM3")) and HID bootloader mode (GetLocationKey(rawHidDevicePath)) — before this fix, the HID-mode call always returnednull.🤖 Generated with Claude Code