On Thu Apr 9 14:02:42 2026 +0000, Connor McAdams wrote:
Because there might be entries in the registry that aren't yet in the local cache -because populated by another process- and also not physically present anymore but that we still want to keep for when the devices are plugged back again? I'm not sure I am following this, but maybe I'm not understanding something. My understanding of the registry entries here, and I think the tests show this, is that they're essentially GUIDs that map to `VID/PID/index` for a particular device. One `guidInstance` (which comes from the registry) can represent a different device depending on which controllers are plugged in at the time `EnumDevices()` is called. There shouldn't be an issue with race conditions between processes, the registry access is locked behind a mutex. The only thing that should be done in the registry is, finding an entry for a `VID/PID/IDX` pairing. If one does not exist, it is created, and along with it a new `guidInstance` value to represent the pairing. If one already exists, the `GUID` value from the registry is used for `guidInstance`. I don't see how another process doing an enumeration would break this. I think the test here shows this behavior:
/*
* Stop devices 0 and 2. After enumeration, their guidInstance values will
* be assigned to devices 1 and 3.
*/
hid_device_stop( &descs[0], 1 );
hid_device_stop( &descs[2], 1 );
/* Stopped devices should return E_FAIL. */
hr = dinput_create_device( &di, &instances[0], &device );
ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr );
hr = dinput_create_device( &di, &instances[2], &device );
ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr );
The local cache was populated by `EnumDevices()` when devices 0 and 2 were present. At that time, the devices were: - device 0, `0x1209/0x0001/0`. - device 1, `0x1209/0x0001/1`. - device 2, `0x1209/0x0002/0`. - device 3, `0x1209/0x0002/1`. After stopping devices 0 and 2, attempting to use those `guidInstance` values will fail. However, after calling `EnumDevices()` again, the local cache changes: ``` /* After calling EnumDevices(), guidInstance values will be reassigned. */ instances_end = instances; hr = dinput_enum_devices( &di, find_test_device_instances, &instances_end ); ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); ok( instances_end == instances + 2, "Unexpected count %Iu.\n", instances_end - instances ); for (UINT i = 0; i < instances_end - instances; i++) { const unsigned int expected_joystick = !i ? 1 : 3; winetest_push_context( "device %d", i ); ok( IsEqualGUID( &expect_instances[expected_joystick - 1], &instances[i] ), "Unexpected instance %s.\n", debugstr_guid( &instances[i] ) ); hr = dinput_create_device( &di, &instances[i], &device ); ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); check_device_hid_serial( device, descs[expected_joystick].serial_str ); IDirectInputDevice8_Release( device ); winetest_pop_context(); } ``` Now the local cache looks like: - device 1, `0x1209/0x0001/0`. - device 3, `0x1209/0x0002/0`. Attempting to use the `guidInstance` values representing `0x1209/0x0001/1` or `0x1209/0x0001/1` no longer works. When devices 0 and 2 are started again, they do get their old `guidInstance` value back, but that's only because the enumeration order stays consistent based on when a particular `DeviceInstance` was first created. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10364#note_135695