[PATCH v2 4/5] setupapi: Remove all device interfaces in SetupDiRemoveDevice().

Zebediah Figura z.figura12 at gmail.com
Wed Apr 7 23:56:44 CDT 2021


Signed-off-by: Zebediah Figura <z.figura12 at 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)
-- 
2.30.2




More information about the wine-devel mailing list