[SETUPAPI] Implement SetupDiRestartDevices()
[reactos.git] / dll / win32 / setupapi / devinst.c
index b7eeeef..14a9a5f 100644 (file)
@@ -23,8 +23,6 @@
 
 /* Unicode constants */
 static const WCHAR BackSlash[] = {'\\',0};
-static const WCHAR ClassGUID[]  = {'C','l','a','s','s','G','U','I','D',0};
-static const WCHAR Class[]  = {'C','l','a','s','s',0};
 static const WCHAR DateFormat[]  = {'%','u','-','%','u','-','%','u',0};
 static const WCHAR DotCoInstallers[]  = {'.','C','o','I','n','s','t','a','l','l','e','r','s',0};
 static const WCHAR DotHW[]  = {'.','H','W',0};
@@ -459,21 +457,16 @@ SetupDiGetActualSectionToInstallExW(
             if (CurrentPlatform.cbSize != sizeof(SP_ALTPLATFORM_INFO))
             {
                 /* That's the first time we go here. We need to fill in the structure */
-                OSVERSIONINFOEX VersionInfo;
                 SYSTEM_INFO SystemInfo;
-                VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
-                ret = GetVersionExW((OSVERSIONINFO*)&VersionInfo);
-                if (!ret)
-                    goto done;
                 GetSystemInfo(&SystemInfo);
                 CurrentPlatform.cbSize = sizeof(SP_ALTPLATFORM_INFO);
-                CurrentPlatform.Platform = VersionInfo.dwPlatformId;
-                CurrentPlatform.MajorVersion = VersionInfo.dwMajorVersion;
-                CurrentPlatform.MinorVersion = VersionInfo.dwMinorVersion;
+                CurrentPlatform.Platform = OsVersionInfo.dwPlatformId;
+                CurrentPlatform.MajorVersion = OsVersionInfo.dwMajorVersion;
+                CurrentPlatform.MinorVersion = OsVersionInfo.dwMinorVersion;
                 CurrentPlatform.ProcessorArchitecture = SystemInfo.wProcessorArchitecture;
                 CurrentPlatform.Reserved = 0;
-                CurrentProductType = VersionInfo.wProductType;
-                CurrentSuiteMask = VersionInfo.wSuiteMask;
+                CurrentProductType = OsVersionInfo.wProductType;
+                CurrentSuiteMask = OsVersionInfo.wSuiteMask;
             }
             ProductType = CurrentProductType;
             SuiteMask = CurrentSuiteMask;
@@ -489,6 +482,7 @@ SetupDiGetActualSectionToInstallExW(
         CallbackInfo.BestScore4 = ULONG_MAX;
         CallbackInfo.BestScore5 = ULONG_MAX;
         strcpyW(CallbackInfo.BestSection, InfSectionName);
+        TRACE("EnumerateSectionsStartingWith(InfSectionName = %S)\n", InfSectionName);
         if (!EnumerateSectionsStartingWith(
             InfHandle,
             InfSectionName,
@@ -498,6 +492,7 @@ SetupDiGetActualSectionToInstallExW(
             SetLastError(ERROR_GEN_FAILURE);
             goto done;
         }
+        TRACE("CallbackInfo.BestSection = %S\n", CallbackInfo.BestSection);
 
         dwFullLength = lstrlenW(CallbackInfo.BestSection);
         if (RequiredSize != NULL)
@@ -602,6 +597,8 @@ DestroyDeviceInfo(struct DeviceInfo *deviceInfo)
             return FALSE;
     }
     DestroyClassInstallParams(&deviceInfo->ClassInstallParams);
+    if (deviceInfo->hmodDevicePropPageProvider)
+        FreeLibrary(deviceInfo->hmodDevicePropPageProvider);
     return HeapFree(GetProcessHeap(), 0, deviceInfo);
 }
 
@@ -622,6 +619,8 @@ DestroyDeviceInfoSet(struct DeviceInfoSet* list)
         RegCloseKey(list->HKLM);
     CM_Disconnect_Machine(list->hMachine);
     DestroyClassInstallParams(&list->ClassInstallParams);
+    if (list->hmodClassPropPageProvider)
+        FreeLibrary(list->hmodClassPropPageProvider);
     return HeapFree(GetProcessHeap(), 0, list);
 }
 
@@ -657,7 +656,7 @@ BOOL WINAPI SetupDiBuildClassInfoList(
  *              SetupDiBuildClassInfoListExA  (SETUPAPI.@)
  *
  * Returns a list of setup class GUIDs that identify the classes
- * that are installed on a local or remote macine.
+ * that are installed on a local or remote machine.
  *
  * PARAMS
  *   Flags [I] control exclusion of classes from the list.
@@ -704,7 +703,7 @@ BOOL WINAPI SetupDiBuildClassInfoListExA(
  *              SetupDiBuildClassInfoListExW  (SETUPAPI.@)
  *
  * Returns a list of setup class GUIDs that identify the classes
- * that are installed on a local or remote macine.
+ * that are installed on a local or remote machine.
  *
  * PARAMS
  *   Flags [I] control exclusion of classes from the list.
@@ -1007,7 +1006,7 @@ BOOL WINAPI SetupDiClassGuidsFromNameExW(
 
             dwLength = MAX_CLASS_NAME_LEN * sizeof(WCHAR);
             if (!RegQueryValueExW(hClassKey,
-                                  Class,
+                                  REGSTR_VAL_CLASS,
                                   NULL,
                                   NULL,
                                   (LPBYTE)szClassName,
@@ -1159,7 +1158,7 @@ BOOL WINAPI SetupDiClassNameFromGuidExW(
         return FALSE;
 
     /* Retrieve the class name data and close the key */
-    rc = QueryRegistryValue(hKey, Class, (LPBYTE *) &Buffer, &dwRegType, &dwLength);
+    rc = QueryRegistryValue(hKey, REGSTR_VAL_CLASS, (LPBYTE *) &Buffer, &dwRegType, &dwLength);
     RegCloseKey(hKey);
 
     /* Make sure we got the data */
@@ -1254,7 +1253,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
@@ -1413,18 +1412,10 @@ HKEY WINAPI SetupDiCreateDevRegKeyW(
         PCWSTR InfSectionName)
 {
     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfo *deviceInfo;
     HKEY key = INVALID_HANDLE_VALUE;
-    LPWSTR lpGuidString = NULL;
-    LPWSTR DriverKey = NULL; /* {GUID}\Index */
-    LPWSTR pDeviceInstance; /* Points into DriverKey, on the Index field */
-    DWORD Index; /* Index used in the DriverKey name */
-    DWORD dwSize;
-    DWORD Disposition;
     DWORD rc;
     HKEY hHWProfileKey = INVALID_HANDLE_VALUE;
-    HKEY hEnumKey = NULL;
-    HKEY hClassKey = NULL;
-    HKEY hDeviceKey = INVALID_HANDLE_VALUE;
     HKEY hKey = NULL;
     HKEY RootKey;
 
@@ -1468,6 +1459,8 @@ HKEY WINAPI SetupDiCreateDevRegKeyW(
         return INVALID_HANDLE_VALUE;
     }
 
+    deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
+
         if (Scope == DICS_FLAG_GLOBAL)
             RootKey = set->HKLM;
         else /* Scope == DICS_FLAG_CONFIGSPECIFIC */
@@ -1480,162 +1473,44 @@ HKEY WINAPI SetupDiCreateDevRegKeyW(
 
         if (KeyType == DIREG_DEV)
         {
-            struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
-
-            rc = RegCreateKeyExW(
-                RootKey,
-                REGSTR_PATH_SYSTEMENUM,
-                0,
-                NULL,
-                REG_OPTION_NON_VOLATILE,
-                KEY_CREATE_SUB_KEY,
-                NULL,
-                &hEnumKey,
-                NULL);
-            if (rc != ERROR_SUCCESS)
-            {
-                SetLastError(rc);
-                goto cleanup;
-            }
-            rc = RegCreateKeyExW(
-                hEnumKey,
-                deviceInfo->instanceId,
-                0,
-                NULL,
-                REG_OPTION_NON_VOLATILE,
 #if _WIN32_WINNT >= 0x502
-                KEY_READ | KEY_WRITE,
+            hKey = SETUPDI_CreateDevKey(RootKey, deviceInfo, KEY_READ | KEY_WRITE);
 #else
-                KEY_ALL_ACCESS,
+            hKey = SETUPDI_CreateDevKey(RootKey, deviceInfo, KEY_ALL_ACCESS);
 #endif
-                NULL,
-                &hKey,
-                NULL);
-            if (rc != ERROR_SUCCESS)
-            {
-                SetLastError(rc);
-                goto cleanup;
-            }
-        }
-        else /* KeyType == DIREG_DRV */
-        {
-            /* Open device key, to read Driver value */
-            hDeviceKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, Scope, HwProfile, DIREG_DEV, KEY_QUERY_VALUE | KEY_SET_VALUE);
-            if (hDeviceKey == INVALID_HANDLE_VALUE)
-                goto cleanup;
-
-            rc = RegOpenKeyExW(RootKey, REGSTR_PATH_CLASS_NT, 0, KEY_CREATE_SUB_KEY, &hClassKey);
-            if (rc != ERROR_SUCCESS)
-            {
-                SetLastError(rc);
+            if (hKey == INVALID_HANDLE_VALUE)
                 goto cleanup;
-            }
 
-            rc = RegQueryValueExW(hDeviceKey, REGSTR_VAL_DRIVER, NULL, NULL, NULL, &dwSize);
-            if (rc != ERROR_SUCCESS)
+            if (Scope == DICS_FLAG_GLOBAL)
             {
-                /* Create a new driver key */
-
-                if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) != RPC_S_OK)
-                    goto cleanup;
-
-                /* The driver key is in \System\CurrentControlSet\Control\Class\{GUID}\Index */
-                DriverKey = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpGuidString) + 7) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
-                if (!DriverKey)
-                {
-                    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-                    goto cleanup;
-                }
-
-                DriverKey[0] = '{';
-                strcpyW(&DriverKey[1], lpGuidString);
-                pDeviceInstance = &DriverKey[strlenW(DriverKey)];
-                *pDeviceInstance++ = '}';
-                *pDeviceInstance++ = '\\';
+                HKEY hTempKey = hKey;
 
-                /* Try all values for Index between 0 and 9999 */
-                Index = 0;
-                while (Index <= 9999)
-                {
-                    sprintfW(pDeviceInstance, InstanceKeyFormat, Index);
-                    rc = RegCreateKeyExW(hClassKey,
-                        DriverKey,
-                        0,
-                        NULL,
-                        REG_OPTION_NON_VOLATILE,
+                rc = RegCreateKeyExW(hTempKey,
+                                     L"Device Parameters",
+                                     0,
+                                     NULL,
+                                     REG_OPTION_NON_VOLATILE,
 #if _WIN32_WINNT >= 0x502
-                        KEY_READ | KEY_WRITE,
+                                     KEY_READ | KEY_WRITE,
 #else
-                        KEY_ALL_ACCESS,
+                                     KEY_ALL_ACCESS,
 #endif
-                        NULL,
-                        &hKey,
-                        &Disposition);
-                    if (rc != ERROR_SUCCESS)
-                    {
-                        SetLastError(rc);
-                        goto cleanup;
-                    }
-                    if (Disposition == REG_CREATED_NEW_KEY)
-                        break;
-                    RegCloseKey(hKey);
-                    hKey = NULL;
-                    Index++;
-                }
-
-                if (Index > 9999)
-                {
-                    /* Unable to create more than 9999 devices within the same class */
-                    SetLastError(ERROR_GEN_FAILURE);
-                    goto cleanup;
-                }
-
-                /* Write the new Driver value */
-                rc = RegSetValueExW(hDeviceKey, REGSTR_VAL_DRIVER, 0, REG_SZ, (const BYTE *)DriverKey, (strlenW(DriverKey) + 1) * sizeof(WCHAR));
-                if (rc != ERROR_SUCCESS)
-                {
-                    SetLastError(rc);
-                    goto cleanup;
-                }
-
+                                     NULL,
+                                     &hKey,
+                                     NULL);
+                if (rc == ERROR_SUCCESS)
+                    RegCloseKey(hTempKey);
             }
-            else
-            {
-                /* Open the existing driver key */
-
-                DriverKey = HeapAlloc(GetProcessHeap(), 0, dwSize);
-                if (!DriverKey)
-                {
-                    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-                    goto cleanup;
-                }
-
-                rc = RegQueryValueExW(hDeviceKey, REGSTR_VAL_DRIVER, NULL, NULL, (LPBYTE)DriverKey, &dwSize);
-                if (rc != ERROR_SUCCESS)
-                {
-                    SetLastError(rc);
-                    goto cleanup;
-                }
-
-                rc = RegCreateKeyExW(hClassKey,
-                    DriverKey,
-                    0,
-                    NULL,
-                    REG_OPTION_NON_VOLATILE,
+        }
+        else /* KeyType == DIREG_DRV */
+        {
 #if _WIN32_WINNT >= 0x502
-                    KEY_READ | KEY_WRITE,
+            hKey = SETUPDI_CreateDrvKey(RootKey, deviceInfo, (UUID*)&DeviceInfoData->ClassGuid, KEY_READ | KEY_WRITE);
 #else
-                    KEY_ALL_ACCESS,
+            hKey = SETUPDI_CreateDrvKey(RootKey, deviceInfo, (UUID*)&DeviceInfoData->ClassGuid, KEY_ALL_ACCESS);
 #endif
-                    NULL,
-                    &hKey,
-                    &Disposition);
-                if (rc != ERROR_SUCCESS)
-                {
-                    SetLastError(rc);
-                    goto cleanup;
-                }
-            }
+            if (hKey == INVALID_HANDLE_VALUE)
+                goto cleanup;
         }
 
         /* Do installation of the specified section */
@@ -1647,17 +1522,8 @@ HKEY WINAPI SetupDiCreateDevRegKeyW(
         key = hKey;
 
 cleanup:
-        if (lpGuidString)
-            RpcStringFreeW(&lpGuidString);
-        HeapFree(GetProcessHeap(), 0, DriverKey);
         if (hHWProfileKey != INVALID_HANDLE_VALUE)
             RegCloseKey(hHWProfileKey);
-        if (hEnumKey != NULL)
-            RegCloseKey(hEnumKey);
-        if (hClassKey != NULL)
-            RegCloseKey(hClassKey);
-        if (hDeviceKey != INVALID_HANDLE_VALUE)
-            RegCloseKey(hDeviceKey);
         if (hKey != NULL && hKey != key)
             RegCloseKey(hKey);
 
@@ -3369,9 +3235,11 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
         DWORD   PropertyBufferSize,
         PDWORD  RequiredSize)
 {
-    BOOL ret = FALSE;
     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
     struct DeviceInfo *devInfo;
+    CONFIGRET cr;
+    LONG lError = ERROR_SUCCESS;
+    DWORD size;
 
     TRACE("%p %p %d %p %p %d %p\n", DeviceInfoSet, DeviceInfoData,
         Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
@@ -3393,111 +3261,116 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
         SetLastError(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
+
+    if (Property >= SPDRP_MAXIMUM_PROPERTY)
+    {
+        SetLastError(ERROR_INVALID_REG_PROPERTY);
+        return FALSE;
+    }
+
     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
+
     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
         && PropertyMap[Property].nameW)
     {
-        DWORD size = PropertyBufferSize;
         HKEY hKey;
-        LONG l;
-        hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
+        size = PropertyBufferSize;
+        hKey = SETUPDI_OpenDevKey(set->HKLM, devInfo, KEY_QUERY_VALUE);
         if (hKey == INVALID_HANDLE_VALUE)
             return FALSE;
-        l = RegQueryValueExW(hKey, PropertyMap[Property].nameW,
-                NULL, PropertyRegDataType, PropertyBuffer, &size);
+        lError = RegQueryValueExW(hKey, PropertyMap[Property].nameW,
+                 NULL, PropertyRegDataType, PropertyBuffer, &size);
         RegCloseKey(hKey);
 
         if (RequiredSize)
             *RequiredSize = size;
-        switch(l) {
+
+        switch (lError)
+        {
             case ERROR_SUCCESS:
-                if (PropertyBuffer != NULL || size == 0)
-                    ret = TRUE;
-                else
-                    SetLastError(ERROR_INSUFFICIENT_BUFFER);
+                if (PropertyBuffer == NULL && size != 0)
+                    lError = ERROR_INSUFFICIENT_BUFFER;
                 break;
             case ERROR_MORE_DATA:
-                SetLastError(ERROR_INSUFFICIENT_BUFFER);
+                lError = ERROR_INSUFFICIENT_BUFFER;
                 break;
             default:
-                SetLastError(l);
+                break;
         }
     }
     else if (Property == SPDRP_PHYSICAL_DEVICE_OBJECT_NAME)
     {
-        DWORD required = (strlenW(devInfo->Data) + 1) * sizeof(WCHAR);
+        size = (strlenW(devInfo->Data) + 1) * sizeof(WCHAR);
 
         if (PropertyRegDataType)
             *PropertyRegDataType = REG_SZ;
         if (RequiredSize)
-            *RequiredSize = required;
-        if (PropertyBufferSize >= required)
+            *RequiredSize = size;
+        if (PropertyBufferSize >= size)
         {
             strcpyW((LPWSTR)PropertyBuffer, devInfo->Data);
-            ret = TRUE;
         }
         else
-            SetLastError(ERROR_INSUFFICIENT_BUFFER);
+            lError = ERROR_INSUFFICIENT_BUFFER;
     }
     else
     {
-        ERR("Property 0x%lx not implemented\n", Property);
-        SetLastError(ERROR_NOT_SUPPORTED);
-    }
-    return ret;
-}
+        size = PropertyBufferSize;
 
-/***********************************************************************
- *             SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
- */
-BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(
-        HDEVINFO DeviceInfoSet,
-        PSP_DEVINFO_DATA DeviceInfoData,
-        DWORD Property,
-        const BYTE *PropertyBuffer,
-        DWORD PropertyBufferSize)
-{
-    BOOL ret = FALSE;
-    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+        cr = CM_Get_DevNode_Registry_Property_ExW(devInfo->dnDevInst,
+                                                  Property + (CM_DRP_DEVICEDESC - SPDRP_DEVICEDESC),
+                                                  PropertyRegDataType,
+                                                  PropertyBuffer,
+                                                  &size,
+                                                  0,
+                                                  set->hMachine);
+        if ((cr == CR_SUCCESS) || (cr == CR_BUFFER_SMALL))
+        {
+            if (RequiredSize)
+                *RequiredSize = size;
+        }
 
-    TRACE("%p %p %d %p %d\n", DeviceInfoSet, DeviceInfoData, Property,
-        PropertyBuffer, PropertyBufferSize);
+        if (cr != CR_SUCCESS)
+        {
+            switch (cr)
+            {
+                case CR_INVALID_DEVINST:
+                    lError = ERROR_NO_SUCH_DEVINST;
+                    break;
 
-    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;
+                case CR_INVALID_PROPERTY:
+                    lError = ERROR_INVALID_REG_PROPERTY;
+                    break;
+
+                case CR_BUFFER_SMALL:
+                    lError = ERROR_INSUFFICIENT_BUFFER;
+                    break;
+
+                default :
+                    lError = ERROR_INVALID_DATA;
+                    break;
+            }
+        }
     }
 
-    FIXME("%p %p 0x%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
-        Property, PropertyBuffer, PropertyBufferSize);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return ret;
+    SetLastError(lError);
+    return (lError == ERROR_SUCCESS);
 }
 
 /***********************************************************************
- *             SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
+ *             Internal for SetupDiSetDeviceRegistryPropertyA/W
  */
-BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
+BOOL WINAPI IntSetupDiSetDeviceRegistryPropertyAW(
         HDEVINFO DeviceInfoSet,
         PSP_DEVINFO_DATA DeviceInfoData,
         DWORD Property,
         const BYTE *PropertyBuffer,
-        DWORD PropertyBufferSize)
+        DWORD PropertyBufferSize,
+        BOOL isAnsi)
 {
     BOOL ret = FALSE;
     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfo *deviceInfo;
 
     TRACE("%p %p %d %p %d\n", DeviceInfoSet, DeviceInfoData, Property,
         PropertyBuffer, PropertyBufferSize);
@@ -3518,19 +3391,33 @@ BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
         SetLastError(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
+
+    deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
+
     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
-        && PropertyMap[Property].nameW)
+        && PropertyMap[Property].nameW
+        && PropertyMap[Property].nameA)
     {
         HKEY hKey;
         LONG l;
-        hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE);
+        hKey = SETUPDI_OpenDevKey(set->HKLM, deviceInfo, KEY_SET_VALUE);
         if (hKey == INVALID_HANDLE_VALUE)
             return FALSE;
         /* Write new data */
-        l = RegSetValueExW(
-            hKey, PropertyMap[Property].nameW, 0,
-                PropertyMap[Property].regType, PropertyBuffer,
-                PropertyBufferSize);
+        if (isAnsi)
+        {
+            l = RegSetValueExA(
+                hKey, PropertyMap[Property].nameA, 0,
+                    PropertyMap[Property].regType, PropertyBuffer,
+                    PropertyBufferSize);
+        } 
+        else
+        {
+            l = RegSetValueExW(
+                hKey, PropertyMap[Property].nameW, 0,
+                    PropertyMap[Property].regType, PropertyBuffer,
+                    PropertyBufferSize);
+        }
         if (!l)
             ret = TRUE;
         else
@@ -3546,6 +3433,41 @@ BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
     TRACE("Returning %d\n", ret);
     return ret;
 }
+/***********************************************************************
+ *             SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
+ */
+BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(
+        HDEVINFO DeviceInfoSet,
+        PSP_DEVINFO_DATA DeviceInfoData,
+        DWORD Property,
+        const BYTE *PropertyBuffer,
+        DWORD PropertyBufferSize)
+{
+    return IntSetupDiSetDeviceRegistryPropertyAW(DeviceInfoSet,
+                                                 DeviceInfoData,
+                                                 Property,
+                                                 PropertyBuffer,
+                                                 PropertyBufferSize,
+                                                 TRUE);
+}
+
+/***********************************************************************
+ *             SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
+        HDEVINFO DeviceInfoSet,
+        PSP_DEVINFO_DATA DeviceInfoData,
+        DWORD Property,
+        const BYTE *PropertyBuffer,
+        DWORD PropertyBufferSize)
+{
+    return IntSetupDiSetDeviceRegistryPropertyAW(DeviceInfoSet,
+                                                 DeviceInfoData,
+                                                 Property,
+                                                 PropertyBuffer,
+                                                 PropertyBufferSize,
+                                                 FALSE);
+}
 
 /***********************************************************************
  *             SetupDiInstallClassA (SETUPAPI.@)
@@ -3600,60 +3522,74 @@ SetupDiInstallClassExA(
 
 HKEY SETUP_CreateClassKey(HINF hInf)
 {
-    static const WCHAR slash[] = { '\\',0 };
     WCHAR FullBuffer[MAX_PATH];
     WCHAR Buffer[MAX_PATH];
     DWORD RequiredSize;
     HKEY hClassKey;
+    DWORD Disposition;
 
+    /* Obtain the Class GUID for this class */
     if (!SetupGetLineTextW(NULL,
                            hInf,
                            Version,
-                           ClassGUID,
+                           REGSTR_VAL_CLASSGUID,
                            Buffer,
-                           MAX_PATH,
+                           sizeof(Buffer) / sizeof(WCHAR),
                            &RequiredSize))
     {
         return INVALID_HANDLE_VALUE;
     }
 
+    /* Build the corresponding registry key name */
     lstrcpyW(FullBuffer, REGSTR_PATH_CLASS_NT);
-    lstrcatW(FullBuffer, slash);
+    lstrcatW(FullBuffer, BackSlash);
     lstrcatW(FullBuffer, Buffer);
 
+    /* Obtain the Class name for this class */
+    if (!SetupGetLineTextW(NULL,
+                           hInf,
+                           Version,
+                           REGSTR_VAL_CLASS,
+                           Buffer,
+                           sizeof(Buffer) / sizeof(WCHAR),
+                           &RequiredSize))
+    {
+        return INVALID_HANDLE_VALUE;
+    }
+
+    /* Try to open or create the registry key */
+    TRACE("Opening class key %s\n", debugstr_w(FullBuffer));
+#if 0 // I keep this for reference...
     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
                       FullBuffer,
                       0,
                       KEY_SET_VALUE,
                       &hClassKey))
     {
-        if (!SetupGetLineTextW(NULL,
-                               hInf,
-                               Version,
-                               Class,
-                               Buffer,
-                               MAX_PATH,
-                               &RequiredSize))
-        {
-            return INVALID_HANDLE_VALUE;
-        }
-
-        if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
-                            FullBuffer,
-                            0,
-                            NULL,
-                            REG_OPTION_NON_VOLATILE,
-                            KEY_SET_VALUE,
-                            NULL,
-                            &hClassKey,
-                            NULL))
-        {
-            return INVALID_HANDLE_VALUE;
-        }
+        /* Use RegCreateKeyExW */
+    }
+#endif
+    if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
+                        FullBuffer,
+                        0,
+                        NULL,
+                        REG_OPTION_NON_VOLATILE,
+                        KEY_SET_VALUE,
+                        NULL,
+                        &hClassKey,
+                        &Disposition))
+    {
+        ERR("RegCreateKeyExW(%s) failed\n", debugstr_w(FullBuffer));
+        return INVALID_HANDLE_VALUE;
     }
+    if (Disposition == REG_CREATED_NEW_KEY)
+        TRACE("The class key %s was successfully created\n", debugstr_w(FullBuffer));
+    else
+        TRACE("The class key %s was successfully opened\n", debugstr_w(FullBuffer));
 
+    TRACE( "setting value %s to %s\n", debugstr_w(REGSTR_VAL_CLASS), debugstr_w(Buffer) );
     if (RegSetValueExW(hClassKey,
-                       Class,
+                       REGSTR_VAL_CLASS,
                        0,
                        REG_SZ,
                        (LPBYTE)Buffer,
@@ -4223,7 +4159,7 @@ BOOL WINAPI SetupDiCallClassInstaller(
 
             if (CanHandle & DEVICE_COINSTALLER)
             {
-                hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
+                hKey = SETUPDI_OpenDrvKey(((struct DeviceInfoSet *)DeviceInfoSet)->HKLM, (struct DeviceInfo *)DeviceInfoData->Reserved, KEY_QUERY_VALUE);
                 if (hKey != INVALID_HANDLE_VALUE)
                 {
                     rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, &dwRegType, NULL, &dwLength);
@@ -4267,16 +4203,16 @@ BOOL WINAPI SetupDiCallClassInstaller(
                     &hKey);
                 if (rc == ERROR_SUCCESS)
                 {
-                    LPWSTR lpGuidString;
-                    if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) == RPC_S_OK)
+                    WCHAR szGuidString[40];
+                    if (pSetupStringFromGuid(&DeviceInfoData->ClassGuid, szGuidString, ARRAYSIZE(szGuidString)) == ERROR_SUCCESS)
                     {
-                        rc = RegQueryValueExW(hKey, lpGuidString, NULL, &dwRegType, NULL, &dwLength);
+                        rc = RegQueryValueExW(hKey, szGuidString, NULL, &dwRegType, NULL, &dwLength);
                         if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
                         {
                             LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
                             if (KeyBuffer != NULL)
                             {
-                                rc = RegQueryValueExW(hKey, lpGuidString, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
+                                rc = RegQueryValueExW(hKey, szGuidString, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
                                 if (rc == ERROR_SUCCESS)
                                 {
                                     LPWSTR ptr;
@@ -4298,7 +4234,6 @@ BOOL WINAPI SetupDiCallClassInstaller(
                                 HeapFree(GetProcessHeap(), 0, KeyBuffer);
                             }
                         }
-                        RpcStringFreeW(&lpGuidString);
                     }
                     RegCloseKey(hKey);
                 }
@@ -4505,7 +4440,7 @@ SetupDiGetDeviceInfoListClass(
         SetLastError(ERROR_NO_ASSOCIATED_CLASS);
     else
     {
-        memcpy(&ClassGuid, &list->ClassGuid, sizeof(GUID));
+        *ClassGuid = list->ClassGuid;
 
         ret = TRUE;
     }
@@ -4715,7 +4650,7 @@ OpenHardwareProfileKey(
     rc = RegOpenKeyExW(HKLM,
                        REGSTR_PATH_HWPROFILES,
                        0,
-                       0,
+                       READ_CONTROL,
                        &hHWProfilesKey);
     if (rc != ERROR_SUCCESS)
     {
@@ -4905,7 +4840,7 @@ SetupDiOpenDeviceInfoW(
                 list->HKLM,
                 REGSTR_PATH_SYSTEMENUM,
                 0, /* Options */
-                0,
+                READ_CONTROL,
                 &hEnumKey);
             if (rc != ERROR_SUCCESS)
             {
@@ -5126,8 +5061,10 @@ SetupDiChangeState(
         IN HDEVINFO DeviceInfoSet,
         IN OUT PSP_DEVINFO_DATA DeviceInfoData)
 {
+    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
     PSP_PROPCHANGE_PARAMS PropChange;
-    HKEY hKey = INVALID_HANDLE_VALUE;
+    HKEY hRootKey = INVALID_HANDLE_VALUE, hKey = INVALID_HANDLE_VALUE;
     LPCWSTR RegistryValueName;
     DWORD dwConfigFlags, dwLength, dwRegType;
     LONG rc;
@@ -5155,10 +5092,19 @@ SetupDiChangeState(
         case DICS_ENABLE:
         case DICS_DISABLE:
         {
+            if (PropChange->Scope == DICS_FLAG_GLOBAL)
+                hRootKey = set->HKLM;
+            else /* PropChange->Scope == DICS_FLAG_CONFIGSPECIFIC */
+            {
+                hRootKey = OpenHardwareProfileKey(set->HKLM, PropChange->HwProfile, KEY_CREATE_SUB_KEY);
+                if (hRootKey == INVALID_HANDLE_VALUE)
+                    goto cleanup;
+            }
+
             /* Enable/disable device in registry */
-            hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, PropChange->Scope, PropChange->HwProfile, DIREG_DEV, KEY_QUERY_VALUE | KEY_SET_VALUE);
+            hKey = SETUPDI_OpenDrvKey(hRootKey, deviceInfo, KEY_QUERY_VALUE | KEY_SET_VALUE);
             if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
-                hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, PropChange->Scope, PropChange->HwProfile, DIREG_DEV, NULL, NULL);
+                hKey = SETUPDI_CreateDevKey(hRootKey, deviceInfo, KEY_QUERY_VALUE | KEY_SET_VALUE);
             if (hKey == INVALID_HANDLE_VALUE)
                 break;
             dwLength = sizeof(DWORD);
@@ -5223,6 +5169,9 @@ SetupDiChangeState(
     }
 
 cleanup:
+    if (hRootKey != INVALID_HANDLE_VALUE && hRootKey != set->HKLM)
+        RegCloseKey(hRootKey);
+
     if (hKey != INVALID_HANDLE_VALUE)
         RegCloseKey(hKey);
 
@@ -5252,6 +5201,8 @@ SetupDiRegisterCoDeviceInstallers(
         IN HDEVINFO DeviceInfoSet,
         IN PSP_DEVINFO_DATA DeviceInfoData)
 {
+    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfo *deviceInfo;
     BOOL ret = FALSE; /* Return value */
 
     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
@@ -5282,7 +5233,7 @@ SetupDiRegisterCoDeviceInstallers(
         if (!Result)
             goto cleanup;
 
-        SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
+        SelectedDriver = (struct DriverInfoElement *)InstallParams.ClassInstallReserved;
         if (SelectedDriver == NULL)
         {
             SetLastError(ERROR_NO_DRIVER_SELECTED);
@@ -5298,14 +5249,20 @@ SetupDiRegisterCoDeviceInstallers(
             goto cleanup;
         lstrcatW(SectionName, DotCoInstallers);
 
+        deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
+
         /* Open/Create driver key information */
 #if _WIN32_WINNT >= 0x502
-        hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE);
+        hKey = SETUPDI_OpenDrvKey(set->HKLM, deviceInfo, KEY_READ | KEY_WRITE);
 #else
-        hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
+        hKey = SETUPDI_OpenDrvKey(set->HKLM, deviceInfo, KEY_ALL_ACCESS);
 #endif
         if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
-            hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
+#if _WIN32_WINNT >= 0x502
+            hKey = SETUPDI_CreateDrvKey(set->HKLM, deviceInfo, (UUID*)&DeviceInfoData->ClassGuid, KEY_READ | KEY_WRITE);
+#else
+            hKey = SETUPDI_CreateDrvKey(set->HKLM, deviceInfo, (UUID*)&DeviceInfoData->ClassGuid, KEY_ALL_ACCESS);
+#endif
         if (hKey == INVALID_HANDLE_VALUE)
             goto cleanup;
 
@@ -5398,6 +5355,8 @@ SetupDiInstallDevice(
         IN HDEVINFO DeviceInfoSet,
         IN OUT PSP_DEVINFO_DATA DeviceInfoData)
 {
+    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfo *deviceInfo;
     SP_DEVINSTALL_PARAMS_W InstallParams;
     struct DriverInfoElement *SelectedDriver;
     SYSTEMTIME DriverDate;
@@ -5477,7 +5436,7 @@ SetupDiInstallDevice(
         goto cleanup;
     }
 
-    SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
+    SelectedDriver = (struct DriverInfoElement *)InstallParams.ClassInstallReserved;
     if (SelectedDriver == NULL)
     {
         SetLastError(ERROR_NO_DRIVER_SELECTED);
@@ -5541,14 +5500,20 @@ SetupDiInstallDevice(
         strcpyW(SelectedDriver->Details.InfFileName, NewFileName);
     }
 
+    deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
+
     /* Open/Create driver key information */
 #if _WIN32_WINNT >= 0x502
-    hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE);
+    hKey = SETUPDI_OpenDrvKey(set->HKLM, deviceInfo, KEY_READ | KEY_WRITE);
 #else
-    hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
+    hKey = SETUPDI_OpenDrvKey(set->HKLM, deviceInfo, KEY_ALL_ACCESS);
 #endif
     if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
-        hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
+#if _WIN32_WINNT >= 0x502
+        hKey = SETUPDI_CreateDrvKey(set->HKLM, deviceInfo, (UUID*)&DeviceInfoData->ClassGuid, KEY_READ | KEY_WRITE);
+#else
+        hKey = SETUPDI_CreateDrvKey(set->HKLM, deviceInfo, (UUID*)&DeviceInfoData->ClassGuid, KEY_ALL_ACCESS);
+#endif
     if (hKey == INVALID_HANDLE_VALUE)
         goto cleanup;
 
@@ -5633,7 +5598,7 @@ SetupDiInstallDevice(
         RebootRequired = TRUE;
 
     /* Open device registry key */
-    hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE);
+    hKey = SETUPDI_OpenDevKey(((struct DeviceInfoSet *)DeviceInfoSet)->HKLM, (struct DeviceInfo *)DeviceInfoData->Reserved, KEY_SET_VALUE);
     if (hKey == INVALID_HANDLE_VALUE)
         goto cleanup;
 
@@ -5688,12 +5653,182 @@ cleanup:
     return ret;
 }
 
-static HKEY SETUPDI_OpenDevKey(HKEY RootKey, struct DeviceInfo *devInfo, REGSAM samDesired)
+HKEY SETUPDI_CreateDevKey(HKEY RootKey, struct DeviceInfo *devInfo, REGSAM samDesired)
+{
+    HKEY enumKey, key = INVALID_HANDLE_VALUE;
+    LONG l;
+
+    l = RegCreateKeyExW(RootKey, REGSTR_PATH_SYSTEMENUM, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_CREATE_SUB_KEY, NULL, &enumKey, NULL);
+    if (!l)
+    {
+        l = RegCreateKeyExW(enumKey, devInfo->instanceId, 0, NULL, REG_OPTION_NON_VOLATILE, samDesired, NULL, &key, NULL);
+        RegCloseKey(enumKey);
+    }
+    if (l)
+        SetLastError(l);
+    return key;
+}
+
+HKEY SETUPDI_CreateDrvKey(HKEY RootKey, struct DeviceInfo *devInfo, UUID *ClassGuid, REGSAM samDesired)
+{
+    HKEY key = INVALID_HANDLE_VALUE;
+    LPWSTR lpGuidString = NULL;
+    LPWSTR DriverKey = NULL; /* {GUID}\Index */
+    LPWSTR pDeviceInstance; /* Points into DriverKey, on the Index field */
+    DWORD Index; /* Index used in the DriverKey name */
+    DWORD dwSize;
+    DWORD Disposition;
+    DWORD rc;
+    HKEY hHWProfileKey = INVALID_HANDLE_VALUE;
+    HKEY hEnumKey = NULL;
+    HKEY hClassKey = NULL;
+    HKEY hDeviceKey = INVALID_HANDLE_VALUE;
+    HKEY hKey = NULL;
+
+    /* Open device key, to read Driver value */
+    hDeviceKey = SETUPDI_OpenDevKey(RootKey, devInfo, KEY_QUERY_VALUE | KEY_SET_VALUE);
+    if (hDeviceKey == INVALID_HANDLE_VALUE)
+        goto cleanup;
+
+    rc = RegOpenKeyExW(RootKey, REGSTR_PATH_CLASS_NT, 0, KEY_CREATE_SUB_KEY, &hClassKey);
+    if (rc != ERROR_SUCCESS)
+    {
+        SetLastError(rc);
+        goto cleanup;
+    }
+
+    rc = RegQueryValueExW(hDeviceKey, REGSTR_VAL_DRIVER, NULL, NULL, NULL, &dwSize);
+    if (rc != ERROR_SUCCESS)
+    {
+        /* Create a new driver key */
+
+        if (UuidToStringW(ClassGuid, &lpGuidString) != RPC_S_OK)
+            goto cleanup;
+
+        /* The driver key is in \System\CurrentControlSet\Control\Class\{GUID}\Index */
+        DriverKey = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpGuidString) + 7) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
+        if (!DriverKey)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            goto cleanup;
+        }
+
+        DriverKey[0] = '{';
+        strcpyW(&DriverKey[1], lpGuidString);
+        pDeviceInstance = &DriverKey[strlenW(DriverKey)];
+        *pDeviceInstance++ = '}';
+        *pDeviceInstance++ = '\\';
+
+        /* Try all values for Index between 0 and 9999 */
+        Index = 0;
+        while (Index <= 9999)
+        {
+            sprintfW(pDeviceInstance, InstanceKeyFormat, Index);
+            rc = RegCreateKeyExW(hClassKey,
+                DriverKey,
+                0,
+                NULL,
+                REG_OPTION_NON_VOLATILE,
+#if _WIN32_WINNT >= 0x502
+                KEY_READ | KEY_WRITE,
+#else
+                KEY_ALL_ACCESS,
+#endif
+                NULL,
+                &hKey,
+                &Disposition);
+            if (rc != ERROR_SUCCESS)
+            {
+                SetLastError(rc);
+                goto cleanup;
+            }
+            if (Disposition == REG_CREATED_NEW_KEY)
+                break;
+            RegCloseKey(hKey);
+            hKey = NULL;
+            Index++;
+        }
+
+        if (Index > 9999)
+        {
+            /* Unable to create more than 9999 devices within the same class */
+            SetLastError(ERROR_GEN_FAILURE);
+            goto cleanup;
+        }
+
+        /* Write the new Driver value */
+        rc = RegSetValueExW(hDeviceKey, REGSTR_VAL_DRIVER, 0, REG_SZ, (const BYTE *)DriverKey, (strlenW(DriverKey) + 1) * sizeof(WCHAR));
+        if (rc != ERROR_SUCCESS)
+        {
+            SetLastError(rc);
+            goto cleanup;
+        }
+    }
+    else
+    {
+        /* Open the existing driver key */
+
+        DriverKey = HeapAlloc(GetProcessHeap(), 0, dwSize);
+        if (!DriverKey)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            goto cleanup;
+        }
+
+        rc = RegQueryValueExW(hDeviceKey, REGSTR_VAL_DRIVER, NULL, NULL, (LPBYTE)DriverKey, &dwSize);
+        if (rc != ERROR_SUCCESS)
+        {
+            SetLastError(rc);
+            goto cleanup;
+        }
+
+        rc = RegCreateKeyExW(hClassKey,
+            DriverKey,
+            0,
+            NULL,
+            REG_OPTION_NON_VOLATILE,
+#if _WIN32_WINNT >= 0x502
+            KEY_READ | KEY_WRITE,
+#else
+            KEY_ALL_ACCESS,
+#endif
+            NULL,
+            &hKey,
+            &Disposition);
+        if (rc != ERROR_SUCCESS)
+        {
+            SetLastError(rc);
+            goto cleanup;
+        }
+    }
+
+    key = hKey;
+
+cleanup:
+        if (lpGuidString)
+            RpcStringFreeW(&lpGuidString);
+        HeapFree(GetProcessHeap(), 0, DriverKey);
+        if (hHWProfileKey != INVALID_HANDLE_VALUE)
+            RegCloseKey(hHWProfileKey);
+        if (hEnumKey != NULL)
+            RegCloseKey(hEnumKey);
+        if (hClassKey != NULL)
+            RegCloseKey(hClassKey);
+        if (hDeviceKey != INVALID_HANDLE_VALUE)
+            RegCloseKey(hDeviceKey);
+        if (hKey != NULL && hKey != key)
+            RegCloseKey(hKey);
+
+    TRACE("Returning 0x%p\n", hKey);
+    return hKey;
+}
+
+HKEY SETUPDI_OpenDevKey(HKEY RootKey, struct DeviceInfo *devInfo, REGSAM samDesired)
 {
     HKEY enumKey, key = INVALID_HANDLE_VALUE;
     LONG l;
 
-    l = RegOpenKeyExW(RootKey, REGSTR_PATH_SYSTEMENUM, 0, 0, &enumKey);
+    l = RegOpenKeyExW(RootKey, REGSTR_PATH_SYSTEMENUM, 0, READ_CONTROL, &enumKey);
     if (!l)
     {
         l = RegOpenKeyExW(enumKey, devInfo->instanceId, 0, samDesired, &key);
@@ -5704,7 +5839,7 @@ static HKEY SETUPDI_OpenDevKey(HKEY RootKey, struct DeviceInfo *devInfo, REGSAM
     return key;
 }
 
-static HKEY SETUPDI_OpenDrvKey(HKEY RootKey, struct DeviceInfo *devInfo, REGSAM samDesired)
+HKEY SETUPDI_OpenDrvKey(HKEY RootKey, struct DeviceInfo *devInfo, REGSAM samDesired)
 {
     LPWSTR DriverKey = NULL;
     DWORD dwLength = 0;
@@ -5748,7 +5883,7 @@ static HKEY SETUPDI_OpenDrvKey(HKEY RootKey, struct DeviceInfo *devInfo, REGSAM
         RootKey,
         REGSTR_PATH_CLASS_NT,
         0, /* Options */
-        0,
+        READ_CONTROL,
         &hEnumKey);
     if (rc != ERROR_SUCCESS)
     {
@@ -5773,6 +5908,8 @@ cleanup:
         RegCloseKey(hEnumKey);
     if (hKey != NULL && hKey != key)
         RegCloseKey(hKey);
+    if (DriverKey)
+        HeapFree(GetProcessHeap(), 0, DriverKey);
     return key;
 }
 
@@ -5839,6 +5976,18 @@ HKEY WINAPI SetupDiOpenDevRegKey(
     {
         case DIREG_DEV:
             key = SETUPDI_OpenDevKey(RootKey, devInfo, samDesired);
+            if (Scope == DICS_FLAG_GLOBAL)
+            {
+                LONG rc;
+                HKEY hTempKey = key;
+                rc = RegOpenKeyExW(hTempKey,
+                                   L"Device Parameters",
+                                   0,
+                                   samDesired,
+                                   &key);
+                if (rc == ERROR_SUCCESS)
+                    RegCloseKey(hTempKey);
+            }
             break;
         case DIREG_DRV:
             key = SETUPDI_OpenDrvKey(RootKey, devInfo, samDesired);
@@ -5941,3 +6090,48 @@ BOOL WINAPI SetupDiDeleteDevRegKey(
         RegCloseKey(RootKey);
     return ret;
 }
+
+/***********************************************************************
+ *             SetupDiRestartDevices (SETUPAPI.@)
+ */
+BOOL
+WINAPI
+SetupDiRestartDevices(
+    HDEVINFO DeviceInfoSet,
+    PSP_DEVINFO_DATA DeviceInfoData)
+{
+    struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
+    struct DeviceInfo *devInfo;
+    CONFIGRET cr;
+
+    TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
+
+    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;
+    }
+
+    devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
+
+    cr = CM_Enable_DevNode_Ex(devInfo->dnDevInst, 0, set->hMachine);
+    if (cr != CR_SUCCESS)
+    {
+        SetLastError(GetErrorCodeFromCrCode(cr));
+        return FALSE;
+    }
+
+    return TRUE;
+}