shell32/tests: Fix remaining failures on WinMe.
[wine] / dlls / setupapi / devinst.c
index 9ac5008..89e3cb6 100644 (file)
@@ -36,7 +36,6 @@
 #include "wine/list.h"
 #include "wine/unicode.h"
 #include "cfgmgr32.h"
-#include "initguid.h"
 #include "winioctl.h"
 #include "rpc.h"
 #include "rpcdce.h"
@@ -98,7 +97,13 @@ struct DeviceInfoSet
     GUID ClassGuid;
     HWND hwndParent;
     DWORD cDevices;
-    SP_DEVINFO_DATA *devices;
+    struct list devices;
+};
+
+struct DeviceInstance
+{
+    struct list entry;
+    SP_DEVINFO_DATA data;
 };
 
 /* Pointed to by SP_DEVICE_INTERFACE_DATA's Reserved member */
@@ -164,6 +169,7 @@ static void SETUPDI_FreeInterfaceInstances(struct InterfaceInstances *instances)
         }
         HeapFree(GetProcessHeap(), 0, ifaceInfo->referenceString);
         HeapFree(GetProcessHeap(), 0, ifaceInfo->symbolicLink);
+        HeapFree(GetProcessHeap(), 0, ifaceInfo);
     }
     HeapFree(GetProcessHeap(), 0, instances->instances);
 }
@@ -174,7 +180,7 @@ static void SETUPDI_FreeInterfaceInstances(struct InterfaceInstances *instances)
  * Returns FALSE if not found.
  */
 static BOOL SETUPDI_FindInterface(const struct DeviceInfo *devInfo,
-        const GUID *InterfaceClassGuid, struct InterfaceInstances **interface)
+        const GUID *InterfaceClassGuid, struct InterfaceInstances **iface_ret)
 {
     BOOL found = FALSE;
     struct InterfaceInstances *iface;
@@ -186,12 +192,12 @@ static BOOL SETUPDI_FindInterface(const struct DeviceInfo *devInfo,
     {
         if (IsEqualGUID(&iface->guid, InterfaceClassGuid))
         {
-            *interface = iface;
+            *iface_ret = iface;
             found = TRUE;
             break;
         }
     }
-    TRACE("returning %d (%p)\n", found, found ? *interface : NULL);
+    TRACE("returning %d (%p)\n", found, found ? *iface_ret : NULL);
     return found;
 }
 
@@ -243,7 +249,7 @@ static LPWSTR SETUPDI_CreateSymbolicLinkPath(LPCWSTR instanceId,
     /* omit length of format specifiers, but include NULL terminator: */
     len = lstrlenW(fmt) - 4 + 1;
     len += lstrlenW(instanceId) + lstrlenW(guidStr);
-    if (ReferenceString)
+    if (ReferenceString && *ReferenceString)
     {
         /* space for a hash between string and reference string: */
         len += lstrlenW(ReferenceString) + 1;
@@ -257,10 +263,10 @@ static LPWSTR SETUPDI_CreateSymbolicLinkPath(LPCWSTR instanceId,
         /* replace '\\' with '#' after the "\\\\?\\" beginning */
         for (ptr = strchrW(ret + 4, '\\'); ptr; ptr = strchrW(ptr + 1, '\\'))
             *ptr = '#';
-        if (ReferenceString)
+        if (ReferenceString && *ReferenceString)
         {
-            ret[printed - 1] = '\\';
-            lstrcpyW(ret + printed, ReferenceString);
+            ret[printed] = '\\';
+            lstrcpyW(ret + printed + 1, ReferenceString);
         }
     }
     return ret;
@@ -351,13 +357,11 @@ static BOOL SETUPDI_AddInterfaceInstance(PSP_DEVINFO_DATA DeviceInfoData,
                         iface->cInstances++;
                         instance->cbSize =
                             sizeof(SP_DEVICE_INTERFACE_DATA);
-                        memcpy(&instance->InterfaceClassGuid,
-                                InterfaceClassGuid, sizeof(GUID));
+                        instance->InterfaceClassGuid = *InterfaceClassGuid;
                         instance->Flags = SPINT_ACTIVE; /* FIXME */
                         instance->Reserved = (ULONG_PTR)ifaceInfo;
                         if (newInterface)
-                            memcpy(&iface->guid, InterfaceClassGuid,
-                                    sizeof(GUID));
+                            iface->guid = *InterfaceClassGuid;
                         key = SetupDiCreateDeviceInterfaceRegKeyW(devInfo->set,
                                 instance, 0, KEY_WRITE, NULL, NULL);
                         if (key != INVALID_HANDLE_VALUE)
@@ -439,8 +443,8 @@ static HKEY SETUPDI_CreateDrvKey(struct DeviceInfo *devInfo)
             KEY_ALL_ACCESS, NULL, &classKey, NULL);
     if (!l)
     {
-        static const WCHAR fmt[] = { '%','0','4','d',0 };
-        WCHAR devId[5];
+        static const WCHAR fmt[] = { '%','0','4','u',0 };
+        WCHAR devId[10];
 
         sprintfW(devId, fmt, devInfo->devId);
         RegCreateKeyExW(classKey, devId, 0, NULL, 0, KEY_READ | KEY_WRITE,
@@ -453,13 +457,16 @@ static HKEY SETUPDI_CreateDrvKey(struct DeviceInfo *devInfo)
 static struct DeviceInfo *SETUPDI_AllocateDeviceInfo(struct DeviceInfoSet *set,
         DWORD devId, LPCWSTR instanceId, BOOL phantom)
 {
-    struct DeviceInfo *devInfo = HeapAlloc(GetProcessHeap(), 0,
-            sizeof(struct DeviceInfo));
+    struct DeviceInfo *devInfo = NULL;
+    HANDLE devInst = GlobalAlloc(GMEM_FIXED, sizeof(struct DeviceInfo));
+    if (devInst)
+        devInfo = GlobalLock(devInst);
 
     if (devInfo)
     {
         devInfo->set = set;
-        devInfo->devId = devId;
+        devInfo->devId = (DWORD)devInst;
+
         devInfo->instanceId = HeapAlloc(GetProcessHeap(), 0,
                 (lstrlenW(instanceId) + 1) * sizeof(WCHAR));
         if (devInfo->instanceId)
@@ -476,10 +483,12 @@ static struct DeviceInfo *SETUPDI_AllocateDeviceInfo(struct DeviceInfoSet *set,
                             (LPBYTE)&phantom, sizeof(phantom));
             }
             list_init(&devInfo->interfaces);
+            GlobalUnlock(devInst);
         }
         else
         {
-            HeapFree(GetProcessHeap(), 0, devInfo);
+            GlobalUnlock(devInst);
+            GlobalFree(devInst);
             devInfo = NULL;
         }
     }
@@ -513,7 +522,7 @@ static void SETUPDI_FreeDeviceInfo(struct DeviceInfo *devInfo)
         SETUPDI_FreeInterfaceInstances(iface);
         HeapFree(GetProcessHeap(), 0, iface);
     }
-    HeapFree(GetProcessHeap(), 0, devInfo);
+    GlobalFree((HANDLE)devInfo->devId);
 }
 
 /* Adds a device with GUID guid and identifer devInst to set.  Allocates a
@@ -537,27 +546,24 @@ static BOOL SETUPDI_AddDeviceToSet(struct DeviceInfoSet *set,
 
     if (devInfo)
     {
-        if (set->devices)
-            set->devices = HeapReAlloc(GetProcessHeap(), 0, set->devices,
-                    (set->cDevices + 1) * sizeof(SP_DEVINFO_DATA));
-        else
-            set->devices = HeapAlloc(GetProcessHeap(), 0,
-                    sizeof(SP_DEVINFO_DATA));
-        if (set->devices)
+        struct DeviceInstance *devInst =
+                HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInstance));
+
+        if (devInst)
         {
             WCHAR classGuidStr[39];
-            SP_DEVINFO_DATA *DeviceInfoData = &set->devices[set->cDevices++];
 
-            DeviceInfoData->cbSize = sizeof(SP_DEVINFO_DATA);
-            memcpy(&DeviceInfoData->ClassGuid, guid, sizeof(GUID));
-            DeviceInfoData->DevInst = devInst;
-            DeviceInfoData->Reserved = (ULONG_PTR)devInfo;
+            list_add_tail(&set->devices, &devInst->entry);
+            set->cDevices++;
+            devInst->data.cbSize = sizeof(SP_DEVINFO_DATA);
+            devInst->data.ClassGuid = *guid;
+            devInst->data.DevInst = devInfo->devId;
+            devInst->data.Reserved = (ULONG_PTR)devInfo;
             SETUPDI_GuidToString(guid, classGuidStr);
-            SetupDiSetDeviceRegistryPropertyW((HDEVINFO)set,
-                DeviceInfoData, SPDRP_CLASSGUID, (const BYTE *)classGuidStr,
+            SetupDiSetDeviceRegistryPropertyW(set, &devInst->data,
+                SPDRP_CLASSGUID, (const BYTE *)classGuidStr,
                 lstrlenW(classGuidStr) * sizeof(WCHAR));
-            if (dev)
-                *dev = DeviceInfoData;
+            if (dev) *dev = &devInst->data;
             ret = TRUE;
         }
         else
@@ -1115,7 +1121,7 @@ SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
     {
         MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
         if (MachineNameW == NULL)
-            return (HDEVINFO)INVALID_HANDLE_VALUE;
+            return INVALID_HANDLE_VALUE;
     }
 
     hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
@@ -1132,7 +1138,7 @@ SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
  * Create an empty DeviceInfoSet list.
  *
  * PARAMS
- *   ClassGuid [I] if not NULL only devices with GUID ClcassGuid are associated
+ *   ClassGuid [I] if not NULL only devices with GUID ClassGuid are associated
  *                 with this list.
  *   hwndParent [I] hwnd needed for interface related actions.
  *   MachineName [I] name of machine to create emtpy DeviceInfoSet list, if NULL
@@ -1159,20 +1165,20 @@ SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
     {
         FIXME("remote support is not implemented\n");
         SetLastError(ERROR_INVALID_MACHINENAME);
-        return (HDEVINFO)INVALID_HANDLE_VALUE;
+        return INVALID_HANDLE_VALUE;
     }
 
     if (Reserved != NULL)
     {
         SetLastError(ERROR_INVALID_PARAMETER);
-        return (HDEVINFO)INVALID_HANDLE_VALUE;
+        return INVALID_HANDLE_VALUE;
     }
 
     list = HeapAlloc(GetProcessHeap(), 0, size);
     if (!list)
     {
         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-        return (HDEVINFO)INVALID_HANDLE_VALUE;
+        return INVALID_HANDLE_VALUE;
     }
 
     list->magic = SETUP_DEVICE_INFO_SET_MAGIC;
@@ -1181,9 +1187,9 @@ SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
             ClassGuid ? ClassGuid : &GUID_NULL,
             sizeof(list->ClassGuid));
     list->cDevices = 0;
-    list->devices = NULL;
+    list_init(&list->devices);
 
-    return (HDEVINFO)list;
+    return list;
 }
 
 /***********************************************************************
@@ -1235,14 +1241,14 @@ HKEY WINAPI SetupDiCreateDevRegKeyW(
         HINF InfHandle,
         PCWSTR InfSectionName)
 {
-    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfoSet *set = DeviceInfoSet;
     struct DeviceInfo *devInfo;
     HKEY key = INVALID_HANDLE_VALUE;
 
     TRACE("%p %p %d %d %d %p %s\n", DeviceInfoSet, DeviceInfoData, Scope,
             HwProfile, KeyType, InfHandle, debugstr_w(InfSectionName));
 
-    if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
+    if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
     {
         SetLastError(ERROR_INVALID_HANDLE);
         return INVALID_HANDLE_VALUE;
@@ -1264,6 +1270,16 @@ HKEY WINAPI SetupDiCreateDevRegKeyW(
         SetLastError(ERROR_INVALID_PARAMETER);
         return INVALID_HANDLE_VALUE;
     }
+    if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
+    {
+        SetLastError(ERROR_INVALID_FLAGS);
+        return INVALID_HANDLE_VALUE;
+    }
+    if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
+    {
+        SetLastError(ERROR_INVALID_FLAGS);
+        return INVALID_HANDLE_VALUE;
+    }
     if (devInfo->phantom)
     {
         SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
@@ -1332,7 +1348,8 @@ BOOL WINAPI SetupDiCreateDeviceInfoA(
 static DWORD SETUPDI_DevNameToDevID(LPCWSTR devName)
 {
     LPCWSTR ptr;
-    DWORD devNameLen = lstrlenW(devName), devInst = 0;
+    int devNameLen = lstrlenW(devName);
+    DWORD devInst = 0;
     BOOL valid = TRUE;
 
     TRACE("%s\n", debugstr_w(devName));
@@ -1363,7 +1380,7 @@ BOOL WINAPI SetupDiCreateDeviceInfoW(
        DWORD CreationFlags,
        PSP_DEVINFO_DATA DeviceInfoData)
 {
-    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfoSet *set = DeviceInfoSet;
     BOOL ret = FALSE, allocatedInstanceId = FALSE;
     LPCWSTR instanceId = NULL;
 
@@ -1376,7 +1393,7 @@ BOOL WINAPI SetupDiCreateDeviceInfoW(
         SetLastError(ERROR_INVALID_DEVINST_NAME);
         return FALSE;
     }
-    if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
+    if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
     {
         SetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
@@ -1409,12 +1426,12 @@ BOOL WINAPI SetupDiCreateDeviceInfoW(
 
             if (set->cDevices)
             {
-                DWORD i, highestDevID = 0;
+                DWORD highestDevID = 0;
+                struct DeviceInstance *devInst;
 
-                for (i = 0; i < set->cDevices; i++)
+                LIST_FOR_EACH_ENTRY(devInst, &set->devices, struct DeviceInstance, entry)
                 {
-                    struct DeviceInfo *devInfo =
-                        (struct DeviceInfo *)set->devices[i].Reserved;
+                    struct DeviceInfo *devInfo = (struct DeviceInfo *)devInst->data.Reserved;
                     LPCWSTR devName = strrchrW(devInfo->instanceId, '\\');
                     DWORD id;
 
@@ -1446,14 +1463,13 @@ BOOL WINAPI SetupDiCreateDeviceInfoW(
     }
     else
     {
-        DWORD i;
+        struct DeviceInstance *devInst;
 
         ret = TRUE;
         instanceId = DeviceName;
-        for (i = 0; ret && i < set->cDevices; i++)
+        LIST_FOR_EACH_ENTRY(devInst, &set->devices, struct DeviceInstance, entry)
         {
-            struct DeviceInfo *devInfo =
-                (struct DeviceInfo *)set->devices[i].Reserved;
+            struct DeviceInfo *devInfo = (struct DeviceInfo *)devInst->data.Reserved;
 
             if (!lstrcmpiW(DeviceName, devInfo->instanceId))
             {
@@ -1482,7 +1498,7 @@ BOOL WINAPI SetupDiCreateDeviceInfoW(
                     ret = FALSE;
                 }
                 else
-                    memcpy(DeviceInfoData, dev, sizeof(SP_DEVINFO_DATA));
+                    *DeviceInfoData = *dev;
             }
         }
     }
@@ -1503,13 +1519,13 @@ BOOL WINAPI SetupDiRegisterDeviceInfo(
         PVOID CompareContext,
         PSP_DEVINFO_DATA DupDeviceInfoData)
 {
-    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfoSet *set = DeviceInfoSet;
     struct DeviceInfo *devInfo;
 
     TRACE("%p %p %08x %p %p %p\n", DeviceInfoSet, DeviceInfoData, Flags,
             CompareProc, CompareContext, DupDeviceInfoData);
 
-    if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
+    if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
     {
         SetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
@@ -1556,16 +1572,27 @@ BOOL WINAPI SetupDiEnumDeviceInfo(
         SetLastError(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
-    if (devinfo && devinfo != (HDEVINFO)INVALID_HANDLE_VALUE)
+    if (devinfo && devinfo != INVALID_HANDLE_VALUE)
     {
-        struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
+        struct DeviceInfoSet *list = devinfo;
         if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
         {
             if (index < list->cDevices)
             {
                 if (info->cbSize == sizeof(SP_DEVINFO_DATA))
                 {
-                    memcpy(info, &list->devices[index], info->cbSize);
+                    struct DeviceInstance *devInst;
+                    DWORD i = 0;
+
+                    LIST_FOR_EACH_ENTRY(devInst, &list->devices,
+                            struct DeviceInstance, entry)
+                    {
+                        if (i++ == index)
+                        {
+                            *info = devInst->data;
+                            break;
+                        }
+                    }
                     ret = TRUE;
                 }
                 else
@@ -1648,7 +1675,7 @@ BOOL WINAPI SetupDiGetDeviceInstanceIdW(
        DWORD DeviceInstanceIdSize,
        PDWORD RequiredSize)
 {
-    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfoSet *set = DeviceInfoSet;
     struct DeviceInfo *devInfo;
 
     TRACE("%p %p %p %d %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstanceId,
@@ -1677,7 +1704,7 @@ BOOL WINAPI SetupDiGetDeviceInstanceIdW(
         return FALSE;
     }
     TRACE("instance ID: %s\n", debugstr_w(devInfo->instanceId));
-    if (DeviceInstanceIdSize < lstrlenW(devInfo->instanceId) + 1)
+    if (DeviceInstanceIdSize < strlenW(devInfo->instanceId) + 1)
     {
         SetLastError(ERROR_INSUFFICIENT_BUFFER);
         if (RequiredSize)
@@ -1896,7 +1923,7 @@ HDEVINFO WINAPI SetupDiGetClassDevsA(
         enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
         if (!enumstrW)
         {
-            ret = (HDEVINFO)INVALID_HANDLE_VALUE;
+            ret = INVALID_HANDLE_VALUE;
             goto end;
         }
         MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
@@ -1930,7 +1957,7 @@ HDEVINFO WINAPI SetupDiGetClassDevsExA(
         enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
         if (!enumstrW)
         {
-            ret = (HDEVINFO)INVALID_HANDLE_VALUE;
+            ret = INVALID_HANDLE_VALUE;
             goto end;
         }
         MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
@@ -1942,7 +1969,7 @@ HDEVINFO WINAPI SetupDiGetClassDevsExA(
         if (!machineW)
         {
             HeapFree(GetProcessHeap(), 0, enumstrW);
-            ret = (HDEVINFO)INVALID_HANDLE_VALUE;
+            ret = INVALID_HANDLE_VALUE;
             goto end;
         }
         MultiByteToWideChar(CP_ACP, 0, machine, -1, machineW, len);
@@ -1957,7 +1984,7 @@ end:
 }
 
 static void SETUPDI_AddDeviceInterfaces(SP_DEVINFO_DATA *dev, HKEY key,
-        const GUID *interface)
+        const GUID *guid)
 {
     DWORD i, len;
     WCHAR subKeyName[MAX_PATH];
@@ -1972,31 +1999,35 @@ static void SETUPDI_AddDeviceInterfaces(SP_DEVINFO_DATA *dev, HKEY key,
             HKEY subKey;
             SP_DEVICE_INTERFACE_DATA *iface = NULL;
 
-            /* The subkey name is the reference string, with a '#' prepended */
-            SETUPDI_AddInterfaceInstance(dev, interface, subKeyName + 1,
-                    &iface);
-            l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
-            if (!l)
+            if (*subKeyName == '#')
             {
-                WCHAR symbolicLink[MAX_PATH];
-                DWORD dataType;
-
-                len = sizeof(symbolicLink);
-                l = RegQueryValueExW(subKey, SymbolicLink, NULL, &dataType,
-                        (BYTE *)symbolicLink, &len);
-                if (!l && dataType == REG_SZ)
-                    SETUPDI_SetInterfaceSymbolicLink(iface, symbolicLink);
-                RegCloseKey(subKey);
+                /* The subkey name is the reference string, with a '#' prepended */
+                SETUPDI_AddInterfaceInstance(dev, guid, subKeyName + 1, &iface);
+                l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
+                if (!l)
+                {
+                    WCHAR symbolicLink[MAX_PATH];
+                    DWORD dataType;
+
+                    len = sizeof(symbolicLink);
+                    l = RegQueryValueExW(subKey, SymbolicLink, NULL, &dataType,
+                            (BYTE *)symbolicLink, &len);
+                    if (!l && dataType == REG_SZ)
+                        SETUPDI_SetInterfaceSymbolicLink(iface, symbolicLink);
+                    RegCloseKey(subKey);
+                }
             }
+            /* Allow enumeration to continue */
+            l = ERROR_SUCCESS;
         }
     }
     /* FIXME: find and add all the device's interfaces to the device */
 }
 
 static void SETUPDI_EnumerateMatchingInterfaces(HDEVINFO DeviceInfoSet,
-        HKEY key, const GUID *interface, LPCWSTR enumstr)
+        HKEY key, const GUID *guid, LPCWSTR enumstr)
 {
-    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfoSet *set = DeviceInfoSet;
     DWORD i, len;
     WCHAR subKeyName[MAX_PATH];
     LONG l;
@@ -2052,8 +2083,7 @@ static void SETUPDI_EnumerateMatchingInterfaces(HDEVINFO DeviceInfoSet,
                                 if (SETUPDI_AddDeviceToSet(set, &deviceClass,
                                         0 /* FIXME: DevInst */, deviceInst,
                                         FALSE, &dev))
-                                    SETUPDI_AddDeviceInterfaces(dev, subKey,
-                                            interface);
+                                    SETUPDI_AddDeviceInterfaces(dev, subKey, guid);
                             }
                             RegCloseKey(deviceKey);
                         }
@@ -2061,6 +2091,8 @@ static void SETUPDI_EnumerateMatchingInterfaces(HDEVINFO DeviceInfoSet,
                 }
                 RegCloseKey(subKey);
             }
+            /* Allow enumeration to continue */
+            l = ERROR_SUCCESS;
         }
     }
     if (enumKey != INVALID_HANDLE_VALUE)
@@ -2068,12 +2100,12 @@ static void SETUPDI_EnumerateMatchingInterfaces(HDEVINFO DeviceInfoSet,
 }
 
 static void SETUPDI_EnumerateInterfaces(HDEVINFO DeviceInfoSet,
-        const GUID *interface, LPCWSTR enumstr, DWORD flags)
+        const GUID *guid, LPCWSTR enumstr, DWORD flags)
 {
-    HKEY interfacesKey = SetupDiOpenClassRegKeyExW(interface, KEY_READ,
+    HKEY interfacesKey = SetupDiOpenClassRegKeyExW(guid, KEY_READ,
             DIOCR_INTERFACE, NULL, NULL);
 
-    TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(interface),
+    TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(guid),
             debugstr_w(enumstr), flags);
 
     if (interfacesKey != INVALID_HANDLE_VALUE)
@@ -2117,31 +2149,32 @@ static void SETUPDI_EnumerateInterfaces(HDEVINFO DeviceInfoSet,
              * interface's key, so just pass that long
              */
             SETUPDI_EnumerateMatchingInterfaces(DeviceInfoSet,
-                    interfacesKey, interface, enumstr);
+                    interfacesKey, guid, enumstr);
         }
         RegCloseKey(interfacesKey);
     }
 }
 
-static void SETUPDI_EnumerateMatchingDevices(HDEVINFO DeviceInfoSet,
-        LPCWSTR parent, HKEY key, const GUID *class, DWORD flags)
+static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set,
+        LPCWSTR enumerator, LPCWSTR deviceName, HKEY deviceKey,
+        const GUID *class, DWORD flags)
 {
-    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
     DWORD i, len;
-    WCHAR subKeyName[MAX_PATH];
+    WCHAR deviceInstance[MAX_PATH];
     LONG l = ERROR_SUCCESS;
 
-    TRACE("%s\n", debugstr_w(parent));
+    TRACE("%s %s\n", debugstr_w(enumerator), debugstr_w(deviceName));
 
     for (i = 0; !l; i++)
     {
-        len = sizeof(subKeyName) / sizeof(subKeyName[0]);
-        l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
+        len = sizeof(deviceInstance) / sizeof(deviceInstance[0]);
+        l = RegEnumKeyExW(deviceKey, i, deviceInstance, &len, NULL, NULL, NULL,
+                NULL);
         if (!l)
         {
             HKEY subKey;
 
-            l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
+            l = RegOpenKeyExW(deviceKey, deviceInstance, 0, KEY_READ, &subKey);
             if (!l)
             {
                 WCHAR classGuid[40];
@@ -2161,15 +2194,17 @@ static void SETUPDI_EnumerateMatchingDevices(HDEVINFO DeviceInfoSet,
                         if ((flags & DIGCF_ALLCLASSES) ||
                                 IsEqualGUID(class, &deviceClass))
                         {
-                            static const WCHAR fmt[] = {'%','s','\\','%','s',0};
+                            static const WCHAR fmt[] =
+                             {'%','s','\\','%','s','\\','%','s',0};
                             LPWSTR instanceId;
 
                             instanceId = HeapAlloc(GetProcessHeap(), 0,
-                                (lstrlenW(parent) + lstrlenW(subKeyName) + 2)
-                                * sizeof(WCHAR));
+                                (lstrlenW(enumerator) + lstrlenW(deviceName) +
+                                lstrlenW(deviceInstance) + 3) * sizeof(WCHAR));
                             if (instanceId)
                             {
-                                sprintfW(instanceId, fmt, parent, subKeyName);
+                                sprintfW(instanceId, fmt, enumerator,
+                                        deviceName, deviceInstance);
                                 SETUPDI_AddDeviceToSet(set, &deviceClass,
                                         0 /* FIXME: DevInst */, instanceId,
                                         FALSE, NULL);
@@ -2180,6 +2215,40 @@ static void SETUPDI_EnumerateMatchingDevices(HDEVINFO DeviceInfoSet,
                 }
                 RegCloseKey(subKey);
             }
+            /* Allow enumeration to continue */
+            l = ERROR_SUCCESS;
+        }
+    }
+}
+
+static void SETUPDI_EnumerateMatchingDevices(HDEVINFO DeviceInfoSet,
+        LPCWSTR parent, HKEY key, const GUID *class, DWORD flags)
+{
+    struct DeviceInfoSet *set = DeviceInfoSet;
+    DWORD i, len;
+    WCHAR subKeyName[MAX_PATH];
+    LONG l = ERROR_SUCCESS;
+
+    TRACE("%s\n", debugstr_w(parent));
+
+    for (i = 0; !l; i++)
+    {
+        len = sizeof(subKeyName) / sizeof(subKeyName[0]);
+        l = RegEnumKeyExW(key, i, subKeyName, &len, NULL, NULL, NULL, NULL);
+        if (!l)
+        {
+            HKEY subKey;
+
+            l = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
+            if (!l)
+            {
+                TRACE("%s\n", debugstr_w(subKeyName));
+                SETUPDI_EnumerateMatchingDeviceInstances(set, parent,
+                        subKeyName, subKey, class, flags);
+                RegCloseKey(subKey);
+            }
+            /* Allow enumeration to continue */
+            l = ERROR_SUCCESS;
         }
     }
 }
@@ -2187,43 +2256,45 @@ static void SETUPDI_EnumerateMatchingDevices(HDEVINFO DeviceInfoSet,
 static void SETUPDI_EnumerateDevices(HDEVINFO DeviceInfoSet, const GUID *class,
         LPCWSTR enumstr, DWORD flags)
 {
-    HKEY classesKey = SetupDiOpenClassRegKeyExW(class, KEY_READ,
-            DIOCR_INSTALLER, NULL, NULL);
+    HKEY enumKey;
+    LONG l;
 
     TRACE("%p, %s, %s, %08x\n", DeviceInfoSet, debugstr_guid(class),
             debugstr_w(enumstr), flags);
 
-    if (classesKey != INVALID_HANDLE_VALUE)
+    l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL,
+            &enumKey, NULL);
+    if (enumKey != INVALID_HANDLE_VALUE)
     {
         if (enumstr)
         {
-            HKEY enumKey;
-            LONG l = RegOpenKeyExW(classesKey, enumstr, 0, KEY_READ,
-                    &enumKey);
+            HKEY enumStrKey;
 
+            l = RegOpenKeyExW(enumKey, enumstr, 0, KEY_READ,
+                    &enumStrKey);
             if (!l)
             {
                 SETUPDI_EnumerateMatchingDevices(DeviceInfoSet, enumstr,
-                        enumKey, class, flags);
-                RegCloseKey(enumKey);
+                        enumStrKey, class, flags);
+                RegCloseKey(enumStrKey);
             }
         }
         else
         {
             DWORD i, len;
             WCHAR subKeyName[MAX_PATH];
-            LONG l = ERROR_SUCCESS;
 
+            l = ERROR_SUCCESS;
             for (i = 0; !l; i++)
             {
                 len = sizeof(subKeyName) / sizeof(subKeyName[0]);
-                l = RegEnumKeyExW(classesKey, i, subKeyName, &len, NULL,
+                l = RegEnumKeyExW(enumKey, i, subKeyName, &len, NULL,
                         NULL, NULL, NULL);
                 if (!l)
                 {
                     HKEY subKey;
 
-                    l = RegOpenKeyExW(classesKey, subKeyName, 0, KEY_READ,
+                    l = RegOpenKeyExW(enumKey, subKeyName, 0, KEY_READ,
                             &subKey);
                     if (!l)
                     {
@@ -2231,10 +2302,12 @@ static void SETUPDI_EnumerateDevices(HDEVINFO DeviceInfoSet, const GUID *class,
                                 subKeyName, subKey, class, flags);
                         RegCloseKey(subKey);
                     }
+                    /* Allow enumeration to continue */
+                    l = ERROR_SUCCESS;
                 }
             }
         }
-        RegCloseKey(classesKey);
+        RegCloseKey(enumKey);
     }
 }
 
@@ -2302,11 +2375,11 @@ BOOL WINAPI SetupDiGetDeviceInfoListDetailA(
         HDEVINFO DeviceInfoSet,
         PSP_DEVINFO_LIST_DETAIL_DATA_A DevInfoData )
 {
-    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfoSet *set = DeviceInfoSet;
 
     TRACE("%p %p\n", DeviceInfoSet, DevInfoData);
 
-    if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
+    if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
     {
         SetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
@@ -2322,7 +2395,7 @@ BOOL WINAPI SetupDiGetDeviceInfoListDetailA(
         SetLastError(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
-    memcpy(&DevInfoData->ClassGuid, &set->ClassGuid, sizeof(GUID));
+    DevInfoData->ClassGuid = set->ClassGuid;
     DevInfoData->RemoteMachineHandle = NULL;
     DevInfoData->RemoteMachineName[0] = '\0';
     return TRUE;
@@ -2335,11 +2408,11 @@ BOOL WINAPI SetupDiGetDeviceInfoListDetailW(
         HDEVINFO DeviceInfoSet,
         PSP_DEVINFO_LIST_DETAIL_DATA_W DevInfoData )
 {
-    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfoSet *set = DeviceInfoSet;
 
     TRACE("%p %p\n", DeviceInfoSet, DevInfoData);
 
-    if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
+    if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
     {
         SetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
@@ -2355,7 +2428,7 @@ BOOL WINAPI SetupDiGetDeviceInfoListDetailW(
         SetLastError(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
-    memcpy(&DevInfoData->ClassGuid, &set->ClassGuid, sizeof(GUID));
+    DevInfoData->ClassGuid = set->ClassGuid;
     DevInfoData->RemoteMachineHandle = NULL;
     DevInfoData->RemoteMachineName[0] = '\0';
     return TRUE;
@@ -2405,7 +2478,7 @@ BOOL WINAPI SetupDiCreateDeviceInterfaceW(
         DWORD CreationFlags,
         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
 {
-    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfoSet *set = DeviceInfoSet;
     struct DeviceInfo *devInfo;
     SP_DEVICE_INTERFACE_DATA *iface = NULL;
     BOOL ret;
@@ -2414,7 +2487,7 @@ BOOL WINAPI SetupDiCreateDeviceInterfaceW(
             debugstr_guid(InterfaceClassGuid), debugstr_w(ReferenceString),
             CreationFlags, DeviceInterfaceData);
 
-    if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
+    if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
     {
         SetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
@@ -2452,7 +2525,7 @@ BOOL WINAPI SetupDiCreateDeviceInterfaceW(
                 ret = FALSE;
             }
             else
-                memcpy(DeviceInterfaceData, iface, sizeof(*iface));
+                *DeviceInterfaceData = *iface;
         }
     }
     return ret;
@@ -2530,14 +2603,14 @@ HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyW(
         HINF InfHandle,
         PCWSTR InfSectionName)
 {
-    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfoSet *set = DeviceInfoSet;
     HKEY key = INVALID_HANDLE_VALUE, interfacesKey;
     LONG l;
 
     TRACE("%p %p %d %08x %p %p\n", DeviceInfoSet, DeviceInterfaceData, Reserved,
             samDesired, InfHandle, InfSectionName);
 
-    if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE ||
+    if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
     {
         SetLastError(ERROR_INVALID_HANDLE);
@@ -2569,21 +2642,55 @@ HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyW(
             struct InterfaceInfo *ifaceInfo =
                 (struct InterfaceInfo *)DeviceInterfaceData->Reserved;
             PWSTR instancePath = SETUPDI_GetInstancePath(ifaceInfo);
+            PWSTR interfKeyName = HeapAlloc(GetProcessHeap(), 0,
+                    (lstrlenW(ifaceInfo->symbolicLink) + 1) * sizeof(WCHAR));
+            HKEY interfKey;
+            WCHAR *ptr;
 
-            if (instancePath)
+            lstrcpyW(interfKeyName, ifaceInfo->symbolicLink);
+            if (lstrlenW(ifaceInfo->symbolicLink) > 3)
+            {
+                interfKeyName[0] = '#';
+                interfKeyName[1] = '#';
+                interfKeyName[3] = '#';
+            }
+            ptr = strchrW(interfKeyName, '\\');
+            if (ptr)
+                *ptr = 0;
+            l = RegCreateKeyExW(parent, interfKeyName, 0, NULL, 0,
+                    samDesired, NULL, &interfKey, NULL);
+            if (!l)
             {
-                LONG l;
+                struct DeviceInfo *devInfo =
+                        (struct DeviceInfo *)ifaceInfo->device->Reserved;
 
-                l = RegCreateKeyExW(parent, instancePath, 0, NULL, 0,
-                        samDesired, NULL, &key, NULL);
-                if (l)
+                l = RegSetValueExW(interfKey, DeviceInstance, 0, REG_SZ,
+                        (BYTE *)devInfo->instanceId,
+                        (lstrlenW(devInfo->instanceId) + 1) * sizeof(WCHAR));
+                if (!l)
                 {
-                    SetLastError(l);
-                    key = INVALID_HANDLE_VALUE;
+                    if (instancePath)
+                    {
+                        LONG l;
+
+                        l = RegCreateKeyExW(interfKey, instancePath, 0, NULL, 0,
+                                samDesired, NULL, &key, NULL);
+                        if (l)
+                        {
+                            SetLastError(l);
+                            key = INVALID_HANDLE_VALUE;
+                        }
+                        else if (InfHandle)
+                            FIXME("INF section installation unsupported\n");
+                    }
                 }
-                else if (InfHandle)
-                    FIXME("INF section installation unsupported\n");
+                else
+                    SetLastError(l);
+                RegCloseKey(interfKey);
             }
+            else
+                SetLastError(l);
+            HeapFree(GetProcessHeap(), 0, interfKeyName);
             HeapFree(GetProcessHeap(), 0, instancePath);
             RegCloseKey(parent);
         }
@@ -2604,13 +2711,13 @@ BOOL WINAPI SetupDiDeleteDeviceInterfaceRegKey(
         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
         DWORD Reserved)
 {
-    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfoSet *set = DeviceInfoSet;
     HKEY parent;
     BOOL ret = FALSE;
 
     TRACE("%p %p %d\n", DeviceInfoSet, DeviceInterfaceData, Reserved);
 
-    if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE ||
+    if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
     {
         SetLastError(ERROR_INVALID_HANDLE);
@@ -2676,13 +2783,13 @@ BOOL WINAPI SetupDiEnumDeviceInterfaces(
        DWORD MemberIndex,
        PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
 {
-    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfoSet *set = DeviceInfoSet;
     BOOL ret = FALSE;
 
     TRACE("%p, %p, %s, %d, %p\n", DeviceInfoSet, DeviceInfoData,
      debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData);
 
-    if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE ||
+    if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
     {
         SetLastError(ERROR_INVALID_HANDLE);
@@ -2709,8 +2816,7 @@ BOOL WINAPI SetupDiEnumDeviceInterfaces(
         if ((ret = SETUPDI_FindInterface(devInfo, InterfaceClassGuid, &iface)))
         {
             if (MemberIndex < iface->cInstances)
-                memcpy(DeviceInterfaceData, &iface->instances[MemberIndex],
-                    sizeof(SP_DEVICE_INTERFACE_DATA));
+                *DeviceInterfaceData = iface->instances[MemberIndex];
             else
             {
                 SetLastError(ERROR_NO_MORE_ITEMS);
@@ -2722,16 +2828,17 @@ BOOL WINAPI SetupDiEnumDeviceInterfaces(
     }
     else
     {
-        DWORD i, cEnumerated = 0;
+        struct DeviceInstance *devInst;
+        DWORD cEnumerated = 0;
         BOOL found = FALSE;
 
-        for (i = 0; !found && cEnumerated < MemberIndex + 1 &&
-                i < set->cDevices; i++)
+        LIST_FOR_EACH_ENTRY(devInst, &set->devices, struct DeviceInstance, entry)
         {
-            struct DeviceInfo *devInfo =
-                (struct DeviceInfo *)set->devices[i].Reserved;
+            struct DeviceInfo *devInfo = (struct DeviceInfo *)devInst->data.Reserved;
             struct InterfaceInstances *iface;
 
+            if (found || cEnumerated >= MemberIndex + 1)
+                break;
             if (SETUPDI_FindInterface(devInfo, InterfaceClassGuid, &iface))
             {
                 if (cEnumerated + iface->cInstances < MemberIndex + 1)
@@ -2740,9 +2847,7 @@ BOOL WINAPI SetupDiEnumDeviceInterfaces(
                 {
                     DWORD instanceIndex = MemberIndex - cEnumerated;
 
-                    memcpy(DeviceInterfaceData,
-                            &iface->instances[instanceIndex],
-                            sizeof(SP_DEVICE_INTERFACE_DATA));
+                    *DeviceInterfaceData = iface->instances[instanceIndex];
                     cEnumerated += instanceIndex + 1;
                     found = TRUE;
                     ret = TRUE;
@@ -2772,18 +2877,21 @@ BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
     BOOL ret = FALSE;
 
     TRACE("%p\n", devinfo);
-    if (devinfo && devinfo != (HDEVINFO)INVALID_HANDLE_VALUE)
+    if (devinfo && devinfo != INVALID_HANDLE_VALUE)
     {
-        struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
+        struct DeviceInfoSet *list = devinfo;
 
         if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
         {
-            DWORD i;
+            struct DeviceInstance *devInst, *devInst2;
 
-            for (i = 0; i < list->cDevices; i++)
-                SETUPDI_FreeDeviceInfo(
-                        (struct DeviceInfo *)list->devices[i].Reserved);
-            HeapFree(GetProcessHeap(), 0, list->devices);
+            LIST_FOR_EACH_ENTRY_SAFE(devInst, devInst2, &list->devices,
+                    struct DeviceInstance, entry)
+            {
+                SETUPDI_FreeDeviceInfo( (struct DeviceInfo *)devInst->data.Reserved );
+                list_remove(&devInst->entry);
+                HeapFree(GetProcessHeap(), 0, devInst);
+            }
             HeapFree(GetProcessHeap(), 0, list);
             ret = TRUE;
         }
@@ -2806,17 +2914,16 @@ BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(
       PDWORD RequiredSize,
       PSP_DEVINFO_DATA DeviceInfoData)
 {
-    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfoSet *set = DeviceInfoSet;
     struct InterfaceInfo *info;
-    DWORD bytesNeeded = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath)
-        + 1;
+    DWORD bytesNeeded = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath[1]);
     BOOL ret = FALSE;
 
     TRACE("(%p, %p, %p, %d, %p, %p)\n", DeviceInfoSet,
      DeviceInterfaceData, DeviceInterfaceDetailData,
      DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
 
-    if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE ||
+    if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
     {
         SetLastError(ERROR_INVALID_HANDLE);
@@ -2829,9 +2936,8 @@ BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(
         SetLastError(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
-    if (DeviceInterfaceDetailData && (DeviceInterfaceDetailData->cbSize <
-            offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + sizeof(char) ||
-            DeviceInterfaceDetailData->cbSize > sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A)))
+    if (DeviceInterfaceDetailData &&
+        DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A))
     {
         SetLastError(ERROR_INVALID_USER_BUFFER);
         return FALSE;
@@ -2856,7 +2962,7 @@ BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(
         else
             DeviceInterfaceDetailData->DevicePath[0] = '\0';
         if (DeviceInfoData && DeviceInfoData->cbSize == sizeof(SP_DEVINFO_DATA))
-            memcpy(DeviceInfoData, info->device, sizeof(SP_DEVINFO_DATA));
+            *DeviceInfoData = *info->device;
         ret = TRUE;
     }
     else
@@ -2879,7 +2985,7 @@ BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
       PDWORD RequiredSize,
       PSP_DEVINFO_DATA DeviceInfoData)
 {
-    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfoSet *set = DeviceInfoSet;
     struct InterfaceInfo *info;
     DWORD bytesNeeded = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
         + sizeof(WCHAR); /* include NULL terminator */
@@ -2889,7 +2995,7 @@ BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
      DeviceInterfaceData, DeviceInterfaceDetailData,
      DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
 
-    if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE ||
+    if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
     {
         SetLastError(ERROR_INVALID_HANDLE);
@@ -2916,7 +3022,7 @@ BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
     }
     info = (struct InterfaceInfo *)DeviceInterfaceData->Reserved;
     if (info->symbolicLink)
-        bytesNeeded += lstrlenW(info->symbolicLink);
+        bytesNeeded += sizeof(WCHAR)*lstrlenW(info->symbolicLink);
     if (DeviceInterfaceDetailDataSize >= bytesNeeded)
     {
         if (info->symbolicLink)
@@ -2924,7 +3030,7 @@ BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
         else
             DeviceInterfaceDetailData->DevicePath[0] = '\0';
         if (DeviceInfoData && DeviceInfoData->cbSize == sizeof(SP_DEVINFO_DATA))
-            memcpy(DeviceInfoData, info->device, sizeof(SP_DEVINFO_DATA));
+            *DeviceInfoData = *info->device;
         ret = TRUE;
     }
     else
@@ -2943,7 +3049,7 @@ struct PropertyMapEntry
     LPCWSTR nameW;
 };
 
-static struct PropertyMapEntry PropertyMap[] = {
+static const struct PropertyMapEntry PropertyMap[] = {
     { REG_SZ, "DeviceDesc", DeviceDesc },
     { REG_MULTI_SZ, "HardwareId", HardwareId },
     { REG_MULTI_SZ, "CompatibleIDs", CompatibleIDs },
@@ -2978,7 +3084,7 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(
         PDWORD  RequiredSize)
 {
     BOOL ret = FALSE;
-    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfoSet *set = DeviceInfoSet;
     struct DeviceInfo *devInfo;
 
     TRACE("%04x %p %d %p %p %d %p\n", (DWORD)DeviceInfoSet, DeviceInfoData,
@@ -3001,6 +3107,11 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(
         SetLastError(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
+    if (PropertyBufferSize && PropertyBuffer == NULL)
+    {
+        SetLastError(ERROR_INVALID_DATA);
+        return FALSE;
+    }
     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
         && PropertyMap[Property].nameA)
@@ -3009,12 +3120,14 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(
         LONG l = RegQueryValueExA(devInfo->key, PropertyMap[Property].nameA,
                 NULL, PropertyRegDataType, PropertyBuffer, &size);
 
-        if (RequiredSize)
-            *RequiredSize = size;
-        if (!l)
+        if (l == ERROR_MORE_DATA || !PropertyBufferSize)
+            SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        else if (!l)
             ret = TRUE;
         else
             SetLastError(l);
+        if (RequiredSize)
+            *RequiredSize = size;
     }
     return ret;
 }
@@ -3032,7 +3145,7 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
         PDWORD  RequiredSize)
 {
     BOOL ret = FALSE;
-    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfoSet *set = DeviceInfoSet;
     struct DeviceInfo *devInfo;
 
     TRACE("%04x %p %d %p %p %d %p\n", (DWORD)DeviceInfoSet, DeviceInfoData,
@@ -3055,6 +3168,11 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
         SetLastError(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
+    if (PropertyBufferSize && PropertyBuffer == NULL)
+    {
+        SetLastError(ERROR_INVALID_DATA);
+        return FALSE;
+    }
     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
         && PropertyMap[Property].nameW)
@@ -3063,12 +3181,14 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
         LONG l = RegQueryValueExW(devInfo->key, PropertyMap[Property].nameW,
                 NULL, PropertyRegDataType, PropertyBuffer, &size);
 
-        if (RequiredSize)
-            *RequiredSize = size;
-        if (!l)
+        if (l == ERROR_MORE_DATA || !PropertyBufferSize)
+            SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        else if (!l)
             ret = TRUE;
         else
             SetLastError(l);
+        if (RequiredSize)
+            *RequiredSize = size;
     }
     return ret;
 }
@@ -3084,7 +3204,7 @@ BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(
        DWORD PropertyBufferSize)
 {
     BOOL ret = FALSE;
-    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfoSet *set = DeviceInfoSet;
     struct DeviceInfo *devInfo;
 
     TRACE("%p %p %d %p %d\n", DeviceInfoSet, DeviceInfoData, Property,
@@ -3132,7 +3252,7 @@ BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
        DWORD PropertyBufferSize)
 {
     BOOL ret = FALSE;
-    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfoSet *set = DeviceInfoSet;
     struct DeviceInfo *devInfo;
 
     TRACE("%p %p %d %p %d\n", DeviceInfoSet, DeviceInfoData, Property,
@@ -3609,14 +3729,14 @@ HKEY WINAPI SetupDiOpenDevRegKey(
        DWORD KeyType,
        REGSAM samDesired)
 {
-    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfoSet *set = DeviceInfoSet;
     struct DeviceInfo *devInfo;
     HKEY key = INVALID_HANDLE_VALUE;
 
     TRACE("%p %p %d %d %d %x\n", DeviceInfoSet, DeviceInfoData,
           Scope, HwProfile, KeyType, samDesired);
 
-    if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
+    if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
     {
         SetLastError(ERROR_INVALID_HANDLE);
         return INVALID_HANDLE_VALUE;
@@ -3668,3 +3788,187 @@ HKEY WINAPI SetupDiOpenDevRegKey(
     }
     return key;
 }
+
+static BOOL SETUPDI_DeleteDevKey(struct DeviceInfo *devInfo)
+{
+    HKEY enumKey;
+    BOOL ret = FALSE;
+    LONG l;
+
+    l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_ALL_ACCESS,
+            NULL, &enumKey, NULL);
+    if (!l)
+    {
+        ret = RegDeleteTreeW(enumKey, devInfo->instanceId);
+        RegCloseKey(enumKey);
+    }
+    else
+        SetLastError(l);
+    return ret;
+}
+
+static BOOL SETUPDI_DeleteDrvKey(struct DeviceInfo *devInfo)
+{
+    static const WCHAR slash[] = { '\\',0 };
+    WCHAR classKeyPath[MAX_PATH];
+    HKEY classKey;
+    LONG l;
+    BOOL ret = FALSE;
+
+    lstrcpyW(classKeyPath, ControlClass);
+    lstrcatW(classKeyPath, slash);
+    SETUPDI_GuidToString(&devInfo->set->ClassGuid,
+            classKeyPath + lstrlenW(classKeyPath));
+    l = RegCreateKeyExW(HKEY_LOCAL_MACHINE, classKeyPath, 0, NULL, 0,
+            KEY_ALL_ACCESS, NULL, &classKey, NULL);
+    if (!l)
+    {
+        static const WCHAR fmt[] = { '%','0','4','u',0 };
+        WCHAR devId[10];
+
+        sprintfW(devId, fmt, devInfo->devId);
+        ret = RegDeleteTreeW(classKey, devId);
+        RegCloseKey(classKey);
+    }
+    else
+        SetLastError(l);
+    return ret;
+}
+
+/***********************************************************************
+ *             SetupDiOpenDevRegKey (SETUPAPI.@)
+ */
+BOOL WINAPI SetupDiDeleteDevRegKey(
+       HDEVINFO DeviceInfoSet,
+       PSP_DEVINFO_DATA DeviceInfoData,
+       DWORD Scope,
+       DWORD HwProfile,
+       DWORD KeyType)
+{
+    struct DeviceInfoSet *set = DeviceInfoSet;
+    struct DeviceInfo *devInfo;
+    BOOL ret = FALSE;
+
+    TRACE("%p %p %d %d %d\n", DeviceInfoSet, DeviceInfoData, Scope, HwProfile,
+            KeyType);
+
+    if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
+    if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
+    if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
+            || !DeviceInfoData->Reserved)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+    if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
+    {
+        SetLastError(ERROR_INVALID_FLAGS);
+        return FALSE;
+    }
+    if (KeyType != DIREG_DEV && KeyType != DIREG_DRV && KeyType != DIREG_BOTH)
+    {
+        SetLastError(ERROR_INVALID_FLAGS);
+        return FALSE;
+    }
+    devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
+    if (devInfo->set != set)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+    if (devInfo->phantom)
+    {
+        SetLastError(ERROR_DEVINFO_NOT_REGISTERED);
+        return FALSE;
+    }
+    if (Scope != DICS_FLAG_GLOBAL)
+        FIXME("unimplemented for scope %d\n", Scope);
+    switch (KeyType)
+    {
+        case DIREG_DEV:
+            ret = SETUPDI_DeleteDevKey(devInfo);
+            break;
+        case DIREG_DRV:
+            ret = SETUPDI_DeleteDrvKey(devInfo);
+            break;
+        case DIREG_BOTH:
+            ret = SETUPDI_DeleteDevKey(devInfo);
+            if (ret)
+                ret = SETUPDI_DeleteDrvKey(devInfo);
+            break;
+        default:
+            WARN("unknown KeyType %d\n", KeyType);
+    }
+    return ret;
+}
+
+/***********************************************************************
+ *              CM_Get_Device_IDA  (SETUPAPI.@)
+ */
+CONFIGRET WINAPI CM_Get_Device_IDA( DEVINST dnDevInst, PSTR Buffer,
+                                   ULONG  BufferLen, ULONG  ulFlags)
+{
+    struct DeviceInfo *devInfo = GlobalLock((HANDLE)dnDevInst);
+
+    TRACE("%x->%p, %p, %u %u\n", dnDevInst, devInfo, Buffer, BufferLen, ulFlags);
+
+    if (!devInfo)
+        return CR_NO_SUCH_DEVINST;
+
+    WideCharToMultiByte(CP_ACP, 0, devInfo->instanceId, -1, Buffer, BufferLen, 0, 0);
+    TRACE("Returning %s\n", debugstr_a(Buffer));
+    return CR_SUCCESS;
+}
+
+/***********************************************************************
+ *              CM_Get_Device_IDW  (SETUPAPI.@)
+ */
+CONFIGRET WINAPI CM_Get_Device_IDW( DEVINST dnDevInst, LPWSTR Buffer,
+                                   ULONG  BufferLen, ULONG  ulFlags)
+{
+    struct DeviceInfo *devInfo = GlobalLock((HANDLE)dnDevInst);
+
+    TRACE("%x->%p, %p, %u %u\n", dnDevInst, devInfo, Buffer, BufferLen, ulFlags);
+
+    if (!devInfo)
+    {
+        WARN("dev instance %d not found!\n", dnDevInst);
+        return CR_NO_SUCH_DEVINST;
+    }
+
+    lstrcpynW(Buffer, devInfo->instanceId, BufferLen);
+    TRACE("Returning %s\n", debugstr_w(Buffer));
+    GlobalUnlock((HANDLE)dnDevInst);
+    return CR_SUCCESS;
+}
+
+
+
+/***********************************************************************
+ *              CM_Get_Device_ID_Size  (SETUPAPI.@)
+ */
+CONFIGRET WINAPI CM_Get_Device_ID_Size( PULONG  pulLen, DEVINST dnDevInst,
+                                        ULONG  ulFlags)
+{
+    struct DeviceInfo *ppdevInfo = GlobalLock((HANDLE)dnDevInst);
+
+    TRACE("%x->%p, %p, %u\n", dnDevInst, ppdevInfo, pulLen, ulFlags);
+
+    if (!ppdevInfo)
+    {
+        WARN("dev instance %d not found!\n", dnDevInst);
+        return CR_NO_SUCH_DEVINST;
+    }
+
+    *pulLen = lstrlenW(ppdevInfo->instanceId);
+    GlobalUnlock((HANDLE)dnDevInst);
+    return CR_SUCCESS;
+}