Tracking from #790 / #674.
Contract (documented in #790)
The device->next pointer is always NULL. Each callback invocation describes exactly one device; compound or composite devices that expose multiple interfaces produce multiple callback invocations (typically delivered in quick succession).
Current state
Backends invoke the user callback with a hid_device_info* whose next field still points into the backend-internal enumeration list. Example: libusb/hid.c:1123 already carries a `TODO` for this:
```c
/* TODO: possibly make the `next` field NULL to match the behavior on other systems */
```
The other backends are similarly inconsistent.
Proposed fix
Before dispatching the callback, copy the `hid_device_info` into a local struct on the dispatcher's stack with `.next = NULL`, then pass a pointer to that local struct into the callback. Do not deep-copy the string fields — they are still owned by HIDAPI and remain valid for the duration of the callback.
This avoids exposing the internal list layout to user code and gives one consistent cross-backend contract.
Backends to touch
Related
Tracking from #790 / #674.
Contract (documented in #790)
Current state
Backends invoke the user callback with a
hid_device_info*whosenextfield still points into the backend-internal enumeration list. Example: libusb/hid.c:1123 already carries a `TODO` for this:```c
/* TODO: possibly make the `next` field NULL to match the behavior on other systems */
```
The other backends are similarly inconsistent.
Proposed fix
Before dispatching the callback, copy the `hid_device_info` into a local struct on the dispatcher's stack with `.next = NULL`, then pass a pointer to that local struct into the callback. Do not deep-copy the string fields — they are still owned by HIDAPI and remain valid for the duration of the callback.
This avoids exposing the internal list layout to user code and gives one consistent cross-backend contract.
Backends to touch
Related