Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/setupapi/devinst.c | 80 +++++++++++++++++++++++++++++++++++ dlls/setupapi/tests/devinst.c | 30 +++++++++++++ 2 files changed, 110 insertions(+)
diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index 8f826c30250..7ff3cb01eb6 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -690,6 +690,81 @@ static void delete_device_iface(struct device_iface *iface) heap_free(iface); }
+/* remove all interfaces associated with the device, including those not + * enumerated in the set */ +static void remove_all_device_ifaces(struct device *device) +{ + HKEY classes_key; + DWORD i, len; + LONG ret; + + if ((ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, DeviceClasses, 0, KEY_READ, &classes_key))) + { + ERR("Failed to open classes key, error %u.\n", ret); + return; + } + + for (i = 0; ; ++i) + { + WCHAR class_name[40]; + HKEY class_key; + DWORD j; + + len = ARRAY_SIZE(class_name); + if ((ret = RegEnumKeyExW(classes_key, i, class_name, &len, NULL, NULL, NULL, NULL))) + { + if (ret != ERROR_NO_MORE_ITEMS) ERR("Failed to enumerate classes, error %u.\n", ret); + break; + } + + if ((ret = RegOpenKeyExW(classes_key, class_name, 0, KEY_READ, &class_key))) + { + ERR("Failed to open class %s, error %u.\n", debugstr_w(class_name), ret); + continue; + } + + for (j = 0; ; ++j) + { + WCHAR iface_name[MAX_DEVICE_ID_LEN + 39], device_name[MAX_DEVICE_ID_LEN]; + HKEY iface_key; + + len = ARRAY_SIZE(iface_name); + if ((ret = RegEnumKeyExW(class_key, j, iface_name, &len, NULL, NULL, NULL, NULL))) + { + if (ret != ERROR_NO_MORE_ITEMS) ERR("Failed to enumerate interfaces, error %u.\n", ret); + break; + } + + if ((ret = RegOpenKeyExW(class_key, iface_name, 0, KEY_ALL_ACCESS, &iface_key))) + { + ERR("Failed to open interface %s, error %u.\n", debugstr_w(iface_name), ret); + continue; + } + + len = sizeof(device_name); + if ((ret = RegQueryValueExW(iface_key, L"DeviceInstance", NULL, NULL, (BYTE *)device_name, &len))) + { + ERR("Failed to query device instance, error %u.\n", ret); + RegCloseKey(iface_key); + continue; + } + + if (!wcsicmp(device_name, device->instanceId)) + { + if ((ret = RegDeleteTreeW(iface_key, NULL))) + ERR("Failed to delete interface %s subkeys, error %u.\n", debugstr_w(iface_name), ret); + if ((ret = RegDeleteKeyW(iface_key, L""))) + ERR("Failed to delete interface %s, error %u.\n", debugstr_w(iface_name), ret); + } + + RegCloseKey(iface_key); + } + RegCloseKey(class_key); + } + + RegCloseKey(classes_key); +} + static void remove_device(struct device *device) { WCHAR id[MAX_DEVICE_ID_LEN], *p; @@ -735,7 +810,10 @@ static void delete_device(struct device *device) SetupDiCallClassInstaller(DIF_DESTROYPRIVATEDATA, device->set, &device_data);
if (device->phantom) + { remove_device(device); + remove_all_device_ifaces(device); + }
RegCloseKey(device->key); heap_free(device->instanceId); @@ -1725,6 +1803,8 @@ BOOL WINAPI SetupDiRemoveDevice(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data) } CloseServiceHandle(manager);
+ remove_all_device_ifaces(device); + return TRUE; }
diff --git a/dlls/setupapi/tests/devinst.c b/dlls/setupapi/tests/devinst.c index 48b84c21e84..de302d21660 100644 --- a/dlls/setupapi/tests/devinst.c +++ b/dlls/setupapi/tests/devinst.c @@ -1448,6 +1448,7 @@ static void test_register_device_iface(void) 'E','n','u','m','\','R','o','o','t','\', 'L','E','G','A','C','Y','_','B','O','G','U','S',0}; SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)}; + SP_DEVINFO_DATA device2 = {sizeof(device2)}; SP_DEVINFO_DATA device = {sizeof(device)}; HDEVINFO set, set2; BOOL ret; @@ -1487,11 +1488,40 @@ static void test_register_device_iface(void) check_device_iface(set2, NULL, &guid, 1, 0, "\\?\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}\deleted"); check_device_iface(set2, NULL, &guid, 2, 0, NULL);
+ ret = SetupDiEnumDeviceInfo(set2, 0, &device2); + ok(ret, "Failed to enumerate devices, error %#x.\n", GetLastError()); + ret = SetupDiCreateDeviceInterfaceA(set2, &device2, &guid, "second", 0, NULL); + ok(ret, "Failed to create interface, error %#x.\n", GetLastError()); + ret = SetupDiRemoveDevice(set, &device); ok(ret, "Failed to remove device, error %#x.\n", GetLastError());
+ check_device_iface(set, NULL, &guid, 0, SPINT_REMOVED, "\\?\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}"); + check_device_iface(set, NULL, &guid, 1, SPINT_REMOVED, "\\?\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}\removed"); + check_device_iface(set, NULL, &guid, 2, 0, NULL); + + check_device_iface(set2, NULL, &guid, 0, 0, "\\?\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}"); + check_device_iface(set2, NULL, &guid, 1, 0, "\\?\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}\deleted"); + check_device_iface(set2, NULL, &guid, 2, 0, "\\?\root#legacy_bogus#0000#{6a55b5a4-3f65-11db-b704-0011955c2bdb}\second"); + check_device_iface(set2, NULL, &guid, 3, 0, NULL); + SetupDiDestroyDeviceInfoList(set); SetupDiDestroyDeviceInfoList(set2); + + /* make sure all interface keys are deleted when a device is removed */ + + set = SetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_DEVICEINTERFACE); + ok(set != INVALID_HANDLE_VALUE, "Failed to create device list, error %#x.\n", GetLastError()); + + ret = SetupDiCreateDeviceInfoA(set, "Root\LEGACY_BOGUS\0000", &guid, NULL, NULL, 0, &device); + ok(ret, "Failed to create device, error %#x.\n", GetLastError()); + + set2 = SetupDiGetClassDevsA(&guid, NULL, 0, DIGCF_DEVICEINTERFACE); + ok(set2 != INVALID_HANDLE_VALUE, "Failed to create device list, error %#x.\n", GetLastError()); + check_device_iface(set2, NULL, &guid, 0, 0, NULL); + SetupDiDestroyDeviceInfoList(set2); + + SetupDiDestroyDeviceInfoList(set); }
static void test_registry_property_a(void)