Handle DIF_ADDPROPERTYPAGE_ADVANCED in SetupDiCallClassInstaller (needed by r20358)
[reactos.git] / reactos / lib / setupapi / devinst.c
index 6515b51..2fb9465 100644 (file)
@@ -28,32 +28,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
 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 ClassInstall32[]  = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
+static const WCHAR Control[]  = {'C','o','n','t','r','o','l',0};
 static const WCHAR DeviceInstance[]  = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
+static const WCHAR DotCoInstallers[]  = {'.','C','o','I','n','s','t','a','l','l','e','r','s',0};
+static const WCHAR DotServices[]  = {'.','S','e','r','v','i','c','e','s',0};
 static const WCHAR InterfaceInstall32[]  = {'I','n','t','e','r','f','a','c','e','I','n','s','t','a','l','l','3','2',0};
-static const WCHAR NoDisplayClass[]  = {'N','o','D','i','s','p','l','a','y','C','l','a','s','s',0};
-static const WCHAR NoInstallClass[]  = {'N','o','I','s','t','a','l','l','C','l','a','s','s',0};
-static const WCHAR NoUseClass[]  = {'N','o','U','s','e','C','l','a','s','s',0};
-static const WCHAR NtExtension[]  = {'.','N','T',0};
-static const WCHAR NtPlatformExtension[]  = {'.','N','T','x','8','6',0};
+static const WCHAR Linked[]  = {'L','i','n','k','e','d',0};
 static const WCHAR SymbolicLink[]  = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
 static const WCHAR Version[]  = {'V','e','r','s','i','o','n',0};
-static const WCHAR WinExtension[]  = {'.','W','i','n',0};
-
-/* Registry key and value names */
-static const WCHAR ControlClass[] = {'S','y','s','t','e','m','\\',
-                                  'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
-                                  'C','o','n','t','r','o','l','\\',
-                                  'C','l','a','s','s',0};
-
-static const WCHAR DeviceClasses[] = {'S','y','s','t','e','m','\\',
-                                  'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
-                                  'C','o','n','t','r','o','l','\\',
-                                  'D','e','v','i','c','e','C','l','a','s','s','e','s',0};
-
-static const WCHAR EnumKeyName[] = {'S','y','s','t','e','m','\\',
-                                  'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
-                                  'E','n','u','m',0};
-
 
 /* FIXME: header mess */
 DEFINE_GUID(GUID_NULL,
@@ -256,7 +238,7 @@ BOOL WINAPI SetupDiBuildClassInfoListExW(
            }
 
            if (!RegQueryValueExW(hClassKey,
-                                 NoUseClass,
+                                 REGSTR_VAL_NOUSECLASS,
                                  NULL,
                                  NULL,
                                  NULL,
@@ -269,7 +251,7 @@ BOOL WINAPI SetupDiBuildClassInfoListExW(
 
            if ((Flags & DIBCI_NOINSTALLCLASS) &&
                (!RegQueryValueExW(hClassKey,
-                                  NoInstallClass,
+                                  REGSTR_VAL_NOINSTALLCLASS,
                                   NULL,
                                   NULL,
                                   NULL,
@@ -282,7 +264,7 @@ BOOL WINAPI SetupDiBuildClassInfoListExW(
 
            if ((Flags & DIBCI_NODISPLAYCLASS) &&
                (!RegQueryValueExW(hClassKey,
-                                  NoDisplayClass,
+                                  REGSTR_VAL_NODISPLAYCLASS,
                                   NULL,
                                   NULL,
                                   NULL,
@@ -841,16 +823,53 @@ BOOL WINAPI SetupDiEnumDeviceInfo(
 /***********************************************************************
  *             SetupDiGetActualSectionToInstallA (SETUPAPI.@)
  */
-BOOL WINAPI SetupDiGetActualSectionToInstallA(
-        HINF InfHandle,
-        PCSTR InfSectionName,
-        PSTR InfSectionWithExt,
-        DWORD InfSectionWithExtSize,
-        PDWORD RequiredSize,
-        PSTR *Extension)
+BOOL WINAPI
+SetupDiGetActualSectionToInstallA(
+        IN HINF InfHandle,
+        IN PCSTR InfSectionName,
+        OUT PSTR InfSectionWithExt OPTIONAL,
+        IN DWORD InfSectionWithExtSize,
+        OUT PDWORD RequiredSize OPTIONAL,
+        OUT PSTR *Extension OPTIONAL)
+{
+    return SetupDiGetActualSectionToInstallExA(InfHandle, InfSectionName,
+        NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize,
+        Extension, NULL);
+}
+
+/***********************************************************************
+ *             SetupDiGetActualSectionToInstallW (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiGetActualSectionToInstallW(
+        IN HINF InfHandle,
+        IN PCWSTR InfSectionName,
+        OUT PWSTR InfSectionWithExt OPTIONAL,
+        IN DWORD InfSectionWithExtSize,
+        OUT PDWORD RequiredSize OPTIONAL,
+        OUT PWSTR *Extension OPTIONAL)
+{
+    return SetupDiGetActualSectionToInstallExW(InfHandle, InfSectionName,
+        NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize,
+        Extension, NULL);
+}
+
+/***********************************************************************
+ *             SetupDiGetActualSectionToInstallExA  (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiGetActualSectionToInstallExA(
+        IN HINF InfHandle,
+        IN PCSTR InfSectionName,
+        IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL,
+        OUT PSTR InfSectionWithExt OPTIONAL,
+        IN DWORD InfSectionWithExtSize,
+        OUT PDWORD RequiredSize OPTIONAL,
+        OUT PSTR* Extension OPTIONAL,
+        IN PVOID Reserved)
 {
     LPWSTR InfSectionNameW = NULL;
-    PWSTR InfSectionWithExtW = NULL;
+    LPWSTR InfSectionWithExtW = NULL;
     PWSTR ExtensionW;
     BOOL bResult = FALSE;
 
@@ -859,18 +878,23 @@ BOOL WINAPI SetupDiGetActualSectionToInstallA(
     if (InfSectionName)
     {
         InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
-        if (InfSectionNameW == NULL) goto end;
+        if (InfSectionNameW == NULL)
+            goto cleanup;
     }
     if (InfSectionWithExt)
     {
-        InfSectionWithExtW = HeapAlloc(GetProcessHeap(), 0, InfSectionWithExtSize * sizeof(WCHAR));
-        if (InfSectionWithExtW == NULL) goto end;
+        InfSectionWithExtW = MyMalloc(InfSectionWithExtSize * sizeof(WCHAR));
+        if (InfSectionWithExtW == NULL)
+            goto cleanup;
     }
 
-    bResult = SetupDiGetActualSectionToInstallW(InfHandle, InfSectionNameW,
-                                                InfSectionWithExt ? InfSectionNameW : NULL,
-                                                InfSectionWithExtSize, RequiredSize,
-                                                Extension ? &ExtensionW : NULL);
+    bResult = SetupDiGetActualSectionToInstallExW(
+        InfHandle, InfSectionNameW, AlternatePlatformInfo,
+        InfSectionWithExt ? InfSectionWithExtW : NULL,
+        InfSectionWithExtSize,
+        RequiredSize,
+        Extension ? &ExtensionW : NULL,
+        Reserved);
 
     if (bResult && InfSectionWithExt)
     {
@@ -885,93 +909,188 @@ BOOL WINAPI SetupDiGetActualSectionToInstallA(
             *Extension = &InfSectionWithExt[ExtensionW - InfSectionWithExtW];
     }
 
-end:
-    if (InfSectionNameW) MyFree(InfSectionNameW);
-    if (InfSectionWithExtW) HeapFree(GetProcessHeap(), 0, InfSectionWithExtW);
+cleanup:
+    MyFree(InfSectionNameW);
+    MyFree(InfSectionWithExtW);
 
     return bResult;
 }
 
 /***********************************************************************
- *             SetupDiGetActualSectionToInstallW (SETUPAPI.@)
+ *             SetupDiGetActualSectionToInstallExW (SETUPAPI.@)
  */
-BOOL WINAPI SetupDiGetActualSectionToInstallW(
-        HINF InfHandle,
-        PCWSTR InfSectionName,
-        PWSTR InfSectionWithExt,
-        DWORD InfSectionWithExtSize,
-        PDWORD RequiredSize,
-        PWSTR *Extension)
+BOOL WINAPI
+SetupDiGetActualSectionToInstallExW(
+        IN HINF InfHandle,
+        IN PCWSTR InfSectionName,
+        IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL,
+        OUT PWSTR InfSectionWithExt OPTIONAL,
+        IN DWORD InfSectionWithExtSize,
+        OUT PDWORD RequiredSize OPTIONAL,
+        OUT PWSTR* Extension OPTIONAL,
+        IN PVOID Reserved)
 {
-    WCHAR szBuffer[MAX_PATH];
-    DWORD dwLength;
-    DWORD dwFullLength;
-    LONG lLineCount = -1;
-
-    TRACE("%p %s %p %lu %p %p\n", InfHandle, debugstr_w(InfSectionName),
-        InfSectionWithExt, InfSectionWithExtSize, RequiredSize, Extension);
-
-    lstrcpyW(szBuffer, InfSectionName);
-    dwLength = lstrlenW(szBuffer);
+    BOOL ret = FALSE;
 
-    if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
-    {
-       /* Test section name with '.NTx86' extension */
-       lstrcpyW(&szBuffer[dwLength], NtPlatformExtension);
-       lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
+    TRACE("%p %s %p %p %lu %p %p %p\n", InfHandle, debugstr_w(InfSectionName),
+        AlternatePlatformInfo, InfSectionWithExt, InfSectionWithExtSize,
+        RequiredSize, Extension, Reserved);
 
-       if (lLineCount == -1)
-       {
-           /* Test section name with '.NT' extension */
-           lstrcpyW(&szBuffer[dwLength], NtExtension);
-           lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
-       }
-    }
+    if (!InfHandle || InfHandle == (HINF)INVALID_HANDLE_VALUE)
+        SetLastError(ERROR_INVALID_HANDLE);
+    else if (!InfSectionName)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (AlternatePlatformInfo && AlternatePlatformInfo->cbSize != sizeof(SP_ALTPLATFORM_INFO))
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else if (Reserved != NULL)
+        SetLastError(ERROR_INVALID_PARAMETER);
     else
     {
-       /* Test section name with '.Win' extension */
-       lstrcpyW(&szBuffer[dwLength], WinExtension);
-       lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
-    }
+        static SP_ALTPLATFORM_INFO CurrentPlatform = { 0, };
+        PSP_ALTPLATFORM_INFO pPlatformInfo = &CurrentPlatform;
+        LPCWSTR pExtensionPlatform, pExtensionArchitecture;
+        WCHAR SectionName[LINE_LEN + 1];
+        LONG lLineCount = -1;
+        DWORD dwFullLength;
+
+        /* Fill platform info if needed */
+        if (AlternatePlatformInfo)
+            pPlatformInfo = AlternatePlatformInfo;
+        else if (CurrentPlatform.cbSize != sizeof(SP_ALTPLATFORM_INFO))
+        {
+            /* That's the first time we go here. We need to fill in the structure */
+            OSVERSIONINFO VersionInfo;
+            SYSTEM_INFO SystemInfo;
+            VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+            ret = GetVersionEx(&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.ProcessorArchitecture = SystemInfo.wProcessorArchitecture;
+            CurrentPlatform.Reserved = 0;
+        }
 
-    if (lLineCount == -1)
-    {
-       /* Test section name without extension */
-       szBuffer[dwLength] = 0;
-       lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
-    }
+static const WCHAR ExtensionPlatformNone[]  = {'.',0};
+static const WCHAR ExtensionPlatformNT[]  = {'.','N','T',0};
+static const WCHAR ExtensionPlatformWindows[]  = {'.','W','i','n',0};
 
-    if (lLineCount == -1)
-    {
-       SetLastError(ERROR_INVALID_PARAMETER);
-       return FALSE;
-    }
+static const WCHAR ExtensionArchitectureNone[]  = {0};
+static const WCHAR ExtensionArchitectureamd64[]  = {'a','m','d','6','4',0};
+static const WCHAR ExtensionArchitectureppc[]  = {'p','p','c',0};
+static const WCHAR ExtensionArchitecturex86[]  = {'x','8','6',0};
+
+        /* Set various extensions values */
+        switch (pPlatformInfo->Platform)
+        {
+            case VER_PLATFORM_WIN32_WINDOWS:
+                pExtensionPlatform = ExtensionPlatformWindows;
+                break;
+            case VER_PLATFORM_WIN32_NT:
+                pExtensionPlatform = ExtensionPlatformNT;
+                break;
+            default:
+                pExtensionPlatform = ExtensionPlatformNone;
+                break;
+        }
+        switch (pPlatformInfo->ProcessorArchitecture)
+        {
+            case PROCESSOR_ARCHITECTURE_AMD64:
+                pExtensionArchitecture = ExtensionArchitectureamd64;
+                break;
+            case PROCESSOR_ARCHITECTURE_INTEL:
+                pExtensionArchitecture = ExtensionArchitecturex86;
+                break;
+            case PROCESSOR_ARCHITECTURE_PPC:
+                pExtensionArchitecture = ExtensionArchitectureppc;
+                break;
+            default:
+                ERR("Unknown processor architecture 0x%x\n", pPlatformInfo->ProcessorArchitecture);
+            case PROCESSOR_ARCHITECTURE_UNKNOWN:
+                pExtensionArchitecture = ExtensionArchitectureNone;
+                break;
+        }
 
-    dwFullLength = lstrlenW(szBuffer);
+        SectionName[LINE_LEN] = UNICODE_NULL;
+
+        /* Test with platform.architecture.major.minor extension */
+        snprintfW(SectionName, LINE_LEN, L"%s%s%s.%lu.%lu", InfSectionName,
+            pExtensionPlatform, pExtensionArchitecture, pPlatformInfo->MajorVersion, pPlatformInfo->MinorVersion);
+        lLineCount = SetupGetLineCountW(InfHandle, SectionName);
+        if (lLineCount != -1) goto sectionfound;
+
+        /* Test with platform.major.minor extension */
+        snprintfW(SectionName, LINE_LEN, L"%s%s.%lu.%lu", InfSectionName,
+            pExtensionPlatform, pPlatformInfo->MajorVersion, pPlatformInfo->MinorVersion);
+        lLineCount = SetupGetLineCountW(InfHandle, SectionName);
+        if (lLineCount != -1) goto sectionfound;
+
+        /* Test with platform.architecture.major extension */
+        snprintfW(SectionName, LINE_LEN, L"%s%s%s.%lu", InfSectionName,
+            pExtensionPlatform, pExtensionArchitecture, pPlatformInfo->MajorVersion);
+        lLineCount = SetupGetLineCountW(InfHandle, SectionName);
+        if (lLineCount != -1) goto sectionfound;
+
+        /* Test with platform.major extension */
+        snprintfW(SectionName, LINE_LEN, L"%s%s.%lu", InfSectionName,
+            pExtensionPlatform, pPlatformInfo->MajorVersion);
+        lLineCount = SetupGetLineCountW(InfHandle, SectionName);
+        if (lLineCount != -1) goto sectionfound;
+
+        /* Test with platform.architecture extension */
+        snprintfW(SectionName, LINE_LEN, L"%s%s%s", InfSectionName,
+            pExtensionPlatform, pExtensionArchitecture);
+        lLineCount = SetupGetLineCountW(InfHandle, SectionName);
+        if (lLineCount != -1) goto sectionfound;
+
+        /* Test with platform extension */
+        snprintfW(SectionName, LINE_LEN, L"%s%s", InfSectionName,
+            pExtensionPlatform);
+        lLineCount = SetupGetLineCountW(InfHandle, SectionName);
+        if (lLineCount != -1) goto sectionfound;
+
+        /* Test without extension */
+        snprintfW(SectionName, LINE_LEN, L"%s", InfSectionName);
+        lLineCount = SetupGetLineCountW(InfHandle, SectionName);
+        if (lLineCount != -1) goto sectionfound;
+
+        /* No appropriate section found */
+        SetLastError(ERROR_INVALID_PARAMETER);
+        goto done;
 
-    if (InfSectionWithExt != NULL && InfSectionWithExtSize != 0)
-    {
-       if (InfSectionWithExtSize < (dwFullLength + 1))
-       {
-           SetLastError(ERROR_INSUFFICIENT_BUFFER);
-           return FALSE;
-       }
+sectionfound:
+        dwFullLength = lstrlenW(SectionName);
+        if (InfSectionWithExt != NULL && InfSectionWithExtSize != 0)
+        {
+            if (InfSectionWithExtSize < (dwFullLength + 1))
+            {
+                SetLastError(ERROR_INSUFFICIENT_BUFFER);
+                goto done;
+            }
 
-       lstrcpyW(InfSectionWithExt, szBuffer);
-       if (Extension != NULL)
-       {
-           *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
-       }
-    }
+            lstrcpyW(InfSectionWithExt, SectionName);
+            if (Extension != NULL)
+            {
+                DWORD dwLength = lstrlenW(SectionName);
+                *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
+            }
+        }
 
-    if (RequiredSize != NULL)
-    {
-       *RequiredSize = dwFullLength + 1;
+        if (RequiredSize != NULL)
+            *RequiredSize = dwFullLength + 1;
+
+        ret = TRUE;
     }
 
-    return TRUE;
+done:
+    TRACE("Returning %d\n", ret);
+    return ret;
 }
 
+
 /***********************************************************************
  *             SetupDiGetClassDescriptionA  (SETUPAPI.@)
  */
@@ -1401,7 +1520,7 @@ static LONG SETUP_CreateDevList(
         HKLM = HKEY_LOCAL_MACHINE;
 
     rc = RegOpenKeyExW(HKLM,
-        EnumKeyName,
+        REGSTR_PATH_SYSTEMENUM,
         0,
         KEY_ENUMERATE_SUB_KEYS,
         &hEnumKey);
@@ -1535,6 +1654,7 @@ static LONG SETUP_CreateSerialDeviceList(
                     HeapFree(GetProcessHeap(), 0, devices);
                 return GetLastError();
             }
+            interfaceInfo->Flags |= SPINT_ACTIVE | SPINT_DEFAULT;
             InsertTailList(&deviceInfo->InterfaceListHead, &interfaceInfo->ListEntry);
         }
     }
@@ -1554,6 +1674,7 @@ static LONG SETUP_CreateInterfaceList(
     HKEY hInterfaceKey;      /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
     HKEY hDeviceInstanceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath} */
     HKEY hReferenceKey;      /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath}\#{ReferenceString} */
+    HKEY hControlKey;        /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath}\#{ReferenceString}\Control */
     HKEY hEnumKey;           /* HKLM\SYSTEM\CurrentControlSet\Enum */
     HKEY hKey;               /* HKLM\SYSTEM\CurrentControlSet\Enum\{Instance\Path} */
     LONG rc;
@@ -1562,6 +1683,7 @@ static LONG SETUP_CreateInterfaceList(
     DWORD i, j;
     DWORD dwLength, dwInstancePathLength;
     DWORD dwRegType;
+    DWORD LinkedValue;
     GUID ClassGuid;
     struct DeviceInfoElement *deviceInfo;
 
@@ -1638,10 +1760,10 @@ static LONG SETUP_CreateInterfaceList(
 
         /* Find class GUID associated to the device instance */
         rc = RegOpenKeyExW(
-            HKEY_LOCAL_MACHINE,
-            EnumKeyName,
+            list->HKLM,
+            REGSTR_PATH_SYSTEMENUM,
             0, /* Options */
-            KEY_ENUMERATE_SUB_KEYS,
+            0,
             &hEnumKey);
         if (rc != ERROR_SUCCESS)
         {
@@ -1780,6 +1902,22 @@ static LONG SETUP_CreateInterfaceList(
                 RegCloseKey(hInterfaceKey);
                 return GetLastError();
             }
+
+            /* Step 3. Update flags */
+            if (KeyBuffer[1] == '\0')
+                interfaceInfo->Flags |= SPINT_DEFAULT;
+            rc = RegOpenKeyExW(hReferenceKey, Control, 0, KEY_QUERY_VALUE, &hControlKey);
+            if (!rc)
+                interfaceInfo->Flags |= SPINT_REMOVED;
+            else
+            {
+                dwLength = sizeof(DWORD);
+                if (RegQueryValueExW(hControlKey, Linked, NULL, &dwRegType, (LPBYTE)&LinkedValue, &dwLength)
+                    && dwRegType == REG_DWORD && LinkedValue)
+                    interfaceInfo->Flags |= SPINT_ACTIVE;
+                RegCloseKey(hControlKey);
+            }
+
             TRACE("Adding interface %s to list\n", debugstr_w(pSymbolicLink));
             HeapFree(GetProcessHeap(), 0, pSymbolicLink);
             InsertTailList(&deviceInfo->InterfaceListHead, &interfaceInfo->ListEntry);
@@ -1914,8 +2052,8 @@ static BOOL GetIconIndex(
     LONG rc;
     BOOL ret = FALSE;
 
-    /* Read "Icon" registry key */
-    rc = RegQueryValueExW(hClassKey, L"Icon", NULL, &dwRegType, NULL, &dwLength);
+    /* Read icon registry key */
+    rc = RegQueryValueExW(hClassKey, REGSTR_VAL_INSICON, NULL, &dwRegType, NULL, &dwLength);
     if (rc != ERROR_SUCCESS)
     {
         SetLastError(rc);
@@ -1931,7 +2069,7 @@ static BOOL GetIconIndex(
         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
         goto cleanup;
     }
-    rc = RegQueryValueExW(hClassKey, L"Icon", NULL, NULL, (LPBYTE)Buffer, &dwLength);
+    rc = RegQueryValueExW(hClassKey, REGSTR_VAL_INSICON, NULL, NULL, (LPBYTE)Buffer, &dwLength);
     if (rc != ERROR_SUCCESS)
     {
         SetLastError(rc);
@@ -1940,7 +2078,7 @@ static BOOL GetIconIndex(
     /* make sure the returned buffer is NULL-terminated */
     Buffer[dwLength / sizeof(WCHAR)] = 0;
 
-    /* Transform "Icon" value to a INT */
+    /* Transform icon value to a INT */
     *ImageIndex = atoiW(Buffer);
     ret = TRUE;
 
@@ -2122,7 +2260,7 @@ BOOL WINAPI SetupDiLoadClassIcon(
             PWCHAR Comma;
             LONG rc;
             DWORD dwRegType, dwLength;
-            rc = RegQueryValueExW(hKey, L"Installer32", NULL, &dwRegType, NULL, &dwLength);
+            rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength);
             if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
             {
                 Buffer = MyMalloc(dwLength + sizeof(WCHAR));
@@ -2131,7 +2269,7 @@ BOOL WINAPI SetupDiLoadClassIcon(
                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
                     goto cleanup;
                 }
-                rc = RegQueryValueExW(hKey, L"Installer32", NULL, NULL, (LPBYTE)Buffer, &dwLength);
+                rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)Buffer, &dwLength);
                 if (rc != ERROR_SUCCESS)
                 {
                     SetLastError(rc);
@@ -2141,7 +2279,7 @@ BOOL WINAPI SetupDiLoadClassIcon(
                 Buffer[dwLength / sizeof(WCHAR)] = 0;
             }
             else if
-                (ERROR_SUCCESS == (rc = RegQueryValueExW(hKey, L"EnumPropPages32", NULL, &dwRegType, NULL, &dwLength))
+                (ERROR_SUCCESS == (rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, &dwRegType, NULL, &dwLength))
                 && dwRegType == REG_SZ)
             {
                 Buffer = MyMalloc(dwLength + sizeof(WCHAR));
@@ -2150,7 +2288,7 @@ BOOL WINAPI SetupDiLoadClassIcon(
                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
                     goto cleanup;
                 }
-                rc = RegQueryValueExW(hKey, L"EnumPropPages32", NULL, NULL, (LPBYTE)Buffer, &dwLength);
+                rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, NULL, (LPBYTE)Buffer, &dwLength);
                 if (rc != ERROR_SUCCESS)
                 {
                     SetLastError(rc);
@@ -2256,7 +2394,7 @@ BOOL WINAPI SetupDiEnumDeviceInterfaces(
                         memcpy(&DeviceInterfaceData->InterfaceClassGuid,
                             &DevItf->InterfaceClassGuid,
                             sizeof(GUID));
-                        DeviceInterfaceData->Flags = 0; /* FIXME */
+                        DeviceInterfaceData->Flags = DevItf->Flags;
                         DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
                         Found = TRUE;
                     }
@@ -2646,39 +2784,39 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
                 switch (Property)
                 {
                     case SPDRP_CAPABILITIES:
-                        RegistryPropertyName = L"Capabilities"; break;
+                        RegistryPropertyName = REGSTR_VAL_CAPABILITIES; break;
                     case SPDRP_CLASS:
-                        RegistryPropertyName = L"Class"; break;
+                        RegistryPropertyName = REGSTR_VAL_CLASS; break;
                     case SPDRP_CLASSGUID:
-                        RegistryPropertyName = L"ClassGUID"; break;
+                        RegistryPropertyName = REGSTR_VAL_CLASSGUID; break;
                     case SPDRP_COMPATIBLEIDS:
-                        RegistryPropertyName = L"CompatibleIDs"; break;
+                        RegistryPropertyName = REGSTR_VAL_COMPATIBLEIDS; break;
                     case SPDRP_CONFIGFLAGS:
-                        RegistryPropertyName = L"ConfigFlags"; break;
+                        RegistryPropertyName = REGSTR_VAL_CONFIGFLAGS; break;
                     case SPDRP_DEVICEDESC:
-                        RegistryPropertyName = L"DeviceDesc"; break;
+                        RegistryPropertyName = REGSTR_VAL_DEVDESC; break;
                     case SPDRP_DRIVER:
-                        RegistryPropertyName = L"Driver"; break;
+                        RegistryPropertyName = REGSTR_VAL_DRIVER; break;
                     case SPDRP_FRIENDLYNAME:
-                        RegistryPropertyName = L"FriendlyName"; break;
+                        RegistryPropertyName = REGSTR_VAL_FRIENDLYNAME; break;
                     case SPDRP_HARDWAREID:
-                        RegistryPropertyName = L"HardwareID"; break;
+                        RegistryPropertyName = REGSTR_VAL_HARDWAREID; break;
                     case SPDRP_LOCATION_INFORMATION:
-                        RegistryPropertyName = L"LocationInformation"; break;
+                        RegistryPropertyName = REGSTR_VAL_LOCATION_INFORMATION; break;
                     case SPDRP_LOWERFILTERS:
-                        RegistryPropertyName = L"LowerFilters"; break;
+                        RegistryPropertyName = REGSTR_VAL_LOWERFILTERS; break;
                     case SPDRP_MFG:
-                        RegistryPropertyName = L"Mfg"; break;
+                        RegistryPropertyName = REGSTR_VAL_MFG; break;
                     case SPDRP_SECURITY:
                         RegistryPropertyName = L"Security"; break;
                     case SPDRP_SERVICE:
-                        RegistryPropertyName = L"Service"; break;
+                        RegistryPropertyName = REGSTR_VAL_SERVICE; break;
                     case SPDRP_UI_NUMBER:
-                        RegistryPropertyName = L"UINumber"; break;
+                        RegistryPropertyName = REGSTR_VAL_UI_NUMBER; break;
                     case SPDRP_UI_NUMBER_DESC_FORMAT:
                         RegistryPropertyName = L"UINumberDescFormat"; break;
                     case SPDRP_UPPERFILTERS:
-                        RegistryPropertyName = L"UpperFilters"; break;
+                        RegistryPropertyName = REGSTR_VAL_UPPERFILTERS; break;
                     default:
                         /* Should not happen */
                         RegistryPropertyName = NULL; break;
@@ -2687,9 +2825,9 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
                 /* Open registry key name */
                 rc = RegOpenKeyExW(
                     list->HKLM,
-                    EnumKeyName,
+                    REGSTR_PATH_SYSTEMENUM,
                     0, /* Options */
-                    KEY_ENUMERATE_SUB_KEYS,
+                    0,
                     &hEnumKey);
                 if (rc != ERROR_SUCCESS)
                 {
@@ -2846,27 +2984,27 @@ BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
                 switch (Property)
                 {
                     case SPDRP_COMPATIBLEIDS:
-                        RegistryPropertyName = L"CompatibleIDs";
+                        RegistryPropertyName = REGSTR_VAL_COMPATIBLEIDS;
                         RegistryDataType = REG_MULTI_SZ;
                         break;
                     case SPDRP_CONFIGFLAGS:
-                        RegistryPropertyName = L"ConfigFlags";
+                        RegistryPropertyName = REGSTR_VAL_CONFIGFLAGS;
                         RegistryDataType = REG_DWORD;
                         break;
                     case SPDRP_FRIENDLYNAME:
-                        RegistryPropertyName = L"FriendlyName";
+                        RegistryPropertyName = REGSTR_VAL_FRIENDLYNAME;
                         RegistryDataType = REG_SZ;
                         break;
                     case SPDRP_HARDWAREID:
-                        RegistryPropertyName = L"HardwareID";
+                        RegistryPropertyName = REGSTR_VAL_HARDWAREID;
                         RegistryDataType = REG_MULTI_SZ;
                         break;
                     case SPDRP_LOCATION_INFORMATION:
-                        RegistryPropertyName = L"LocationInformation";
+                        RegistryPropertyName = REGSTR_VAL_LOCATION_INFORMATION;
                         RegistryDataType = REG_SZ;
                         break;
                     case SPDRP_LOWERFILTERS:
-                        RegistryPropertyName = L"LowerFilters";
+                        RegistryPropertyName = REGSTR_VAL_LOWERFILTERS;
                         RegistryDataType = REG_MULTI_SZ;
                         break;
                     case SPDRP_SECURITY:
@@ -2874,7 +3012,7 @@ BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
                         RegistryDataType = REG_BINARY;
                         break;
                     case SPDRP_SERVICE:
-                        RegistryPropertyName = L"Service";
+                        RegistryPropertyName = REGSTR_VAL_SERVICE;
                         RegistryDataType = REG_SZ;
                         break;
                     case SPDRP_UI_NUMBER_DESC_FORMAT:
@@ -2882,7 +3020,7 @@ BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
                         RegistryDataType = REG_SZ;
                         break;
                     case SPDRP_UPPERFILTERS:
-                        RegistryPropertyName = L"UpperFilters";
+                        RegistryPropertyName = REGSTR_VAL_UPPERFILTERS;
                         RegistryDataType = REG_MULTI_SZ;
                         break;
                     default:
@@ -2932,31 +3070,67 @@ BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
     return ret;
 }
 
+
 /***********************************************************************
  *             SetupDiInstallClassA (SETUPAPI.@)
  */
 BOOL WINAPI SetupDiInstallClassA(
-        HWND hwndParent,
-        PCSTR InfFileName,
-        DWORD Flags,
-        HSPFILEQ FileQueue)
+        IN HWND hwndParent OPTIONAL,
+        IN PCSTR InfFileName,
+        IN DWORD Flags,
+        IN HSPFILEQ FileQueue OPTIONAL)
+{
+    return SetupDiInstallClassExA(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
+}
+
+
+/***********************************************************************
+ *             SetupDiInstallClassW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupDiInstallClassW(
+        IN HWND hwndParent OPTIONAL,
+        IN PCWSTR InfFileName,
+        IN DWORD Flags,
+        IN HSPFILEQ FileQueue OPTIONAL)
+{
+    return SetupDiInstallClassExW(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
+}
+
+
+/***********************************************************************
+ *             SetupDiInstallClassExA (SETUPAPI.@)
+ */
+BOOL WINAPI SetupDiInstallClassExA(
+        IN HWND hwndParent OPTIONAL,
+        IN PCSTR InfFileName OPTIONAL,
+        IN DWORD Flags,
+        IN HSPFILEQ FileQueue OPTIONAL,
+        IN const GUID* InterfaceClassGuid OPTIONAL,
+        IN PVOID Reserved1,
+        IN PVOID Reserved2)
 {
-    UNICODE_STRING FileNameW;
+    PWSTR InfFileNameW = NULL;
     BOOL Result;
 
-    if (!RtlCreateUnicodeStringFromAsciiz(&FileNameW, InfFileName))
+    if (InfFileName)
     {
-        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-        return FALSE;
+        InfFileNameW = MultiByteToUnicode(InfFileName, CP_ACP);
+        if (InfFileNameW == NULL)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            return FALSE;
+        }
     }
 
-    Result = SetupDiInstallClassW(hwndParent, FileNameW.Buffer, Flags, FileQueue);
+    Result = SetupDiInstallClassExW(hwndParent, InfFileNameW, Flags,
+        FileQueue, InterfaceClassGuid, Reserved1, Reserved2);
 
-    RtlFreeUnicodeString(&FileNameW);
+    MyFree(InfFileNameW);
 
     return Result;
 }
 
+
 static HKEY CreateClassKey(HINF hInf)
 {
     WCHAR FullBuffer[MAX_PATH];
@@ -2976,7 +3150,7 @@ static HKEY CreateClassKey(HINF hInf)
         return INVALID_HANDLE_VALUE;
     }
 
-    lstrcpyW(FullBuffer, ControlClass);
+    lstrcpyW(FullBuffer, REGSTR_PATH_CLASS_NT);
     lstrcatW(FullBuffer, Buffer);
 
 
@@ -3021,103 +3195,125 @@ static HKEY CreateClassKey(HINF hInf)
     return hClassKey;
 }
 
+
 /***********************************************************************
- *             SetupDiInstallClassW (SETUPAPI.@)
+ *             SetupDiInstallClassExW (SETUPAPI.@)
  */
-BOOL WINAPI SetupDiInstallClassW(
-        HWND hwndParent,
-        PCWSTR InfFileName,
-        DWORD Flags,
-        HSPFILEQ FileQueue)
+BOOL WINAPI SetupDiInstallClassExW(
+        IN HWND hwndParent OPTIONAL,
+        IN PCWSTR InfFileName OPTIONAL,
+        IN DWORD Flags,
+        IN HSPFILEQ FileQueue OPTIONAL,
+        IN const GUID* InterfaceClassGuid OPTIONAL,
+        IN PVOID Reserved1,
+        IN PVOID Reserved2)
 {
-    WCHAR SectionName[MAX_PATH];
-    DWORD SectionNameLength = 0;
-    HINF hInf;
-    BOOL bFileQueueCreated = FALSE;
-    HKEY hClassKey;
-
-    TRACE("%p %s 0x%lx %p\n", hwndParent, debugstr_w(InfFileName),
-        Flags, FileQueue);
+    BOOL ret = FALSE;
 
-    FIXME("not fully implemented\n");
+    TRACE("%p %s 0x%lx %p %s %p %p\n", hwndParent, debugstr_w(InfFileName), Flags,
+        FileQueue, debugstr_guid(InterfaceClassGuid), Reserved1, Reserved2);
 
-    if ((Flags & DI_NOVCP) && (FileQueue == NULL || FileQueue == INVALID_HANDLE_VALUE))
+    if (!InfFileName && !InterfaceClassGuid)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL))
     {
-       SetLastError(ERROR_INVALID_PARAMETER);
-       return FALSE;
+        TRACE("Unknown flags: 0x%08lx\n", Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL));
+        SetLastError(ERROR_INVALID_FLAGS);
     }
-
-    /* Open the .inf file */
-    hInf = SetupOpenInfFileW(InfFileName,
-                            NULL,
-                            INF_STYLE_WIN4,
-                            NULL);
-    if (hInf == INVALID_HANDLE_VALUE)
+    else if ((Flags & DI_NOVCP) && FileQueue == NULL)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (Reserved1 != NULL)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (Reserved2 != NULL)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else
     {
+        WCHAR SectionName[MAX_PATH];
+        HINF hInf = INVALID_HANDLE_VALUE;
+        HKEY hClassKey = INVALID_HANDLE_VALUE;
+        PVOID callback_context = NULL;
 
-       return FALSE;
-    }
+        if (InterfaceClassGuid)
+        {
+            /* SetupDiCreateDeviceInterface??? */
+            FIXME("Installing an interface is not implemented\n");
+            SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+        }
+        else
+        {
+            if (Flags & DI_NOVCP)
+                FIXME("FileQueue argument ignored\n");
+            if (Flags & (DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL))
+                FIXME("Flags 0x%lx ignored\n", Flags & (DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL));
+
+            /* Open the .inf file */
+            hInf = SetupOpenInfFileW(
+                InfFileName,
+                NULL,
+                INF_STYLE_WIN4,
+                NULL);
+            if (hInf == INVALID_HANDLE_VALUE)
+                goto cleanup;
 
-    /* Create or open the class registry key 'HKLM\\CurrentControlSet\\Class\\{GUID}' */
-    hClassKey = CreateClassKey(hInf);
-    if (hClassKey == INVALID_HANDLE_VALUE)
-    {
-       SetupCloseInfFile(hInf);
-       return FALSE;
-    }
+            /* Create or open the class registry key 'HKLM\CurrentControlSet\Class\{GUID}' */
+            hClassKey = CreateClassKey(hInf);
+            if (hClassKey == INVALID_HANDLE_VALUE)
+                goto cleanup;
 
+            /* Try to append a layout file */
+            ret = SetupOpenAppendInfFileW(NULL, hInf, NULL);
+            if (!ret)
+                goto cleanup;
 
+            /* Retrieve the actual section name */
+            ret = SetupDiGetActualSectionToInstallW(
+                hInf,
+                ClassInstall32,
+                SectionName,
+                MAX_PATH - wcslen(DotServices),
+                NULL,
+                NULL);
+            if (!ret)
+                goto cleanup;
 
-    /* Try to append a layout file */
-#if 0
-    SetupOpenAppendInfFileW(NULL, hInf, NULL);
-#endif
+            callback_context = SetupInitDefaultQueueCallback(hwndParent);
+            if (!callback_context)
+                goto cleanup;
 
-    /* Retrieve the actual section name */
-    SetupDiGetActualSectionToInstallW(hInf,
-                                     ClassInstall32,
-                                     SectionName,
-                                     MAX_PATH,
-                                     &SectionNameLength,
-                                     NULL);
+            ret = SetupInstallFromInfSectionW(
+                hwndParent,
+                hInf,
+                SectionName,
+                SPINST_REGISTRY | SPINST_FILES | SPINST_BITREG | SPINST_INIFILES | SPINST_INI2REG,
+                hClassKey,
+                NULL, /* SourceRootPath */
+                0, /* CopyFlags */
+                SetupDefaultQueueCallbackW,
+                callback_context,
+                NULL,
+                NULL);
+            if (!ret)
+                goto cleanup;
 
-#if 0
-    if (!(Flags & DI_NOVCP))
-    {
-       FileQueue = SetupOpenFileQueue();
-       if (FileQueue == INVALID_HANDLE_VALUE)
-       {
-           SetupCloseInfFile(hInf);
-       RegCloseKey(hClassKey);
-           return FALSE;
-       }
+            /* Install .Services section */
+            lstrcatW(SectionName, DotServices);
+            ret = SetupInstallServicesFromInfSectionW(hInf, SectionName, 0);
+            if (!ret)
+                goto cleanup;
 
-       bFileQueueCreated = TRUE;
+            ret = TRUE;
+        }
 
+cleanup:
+        if (hInf != INVALID_HANDLE_VALUE)
+            SetupCloseInfFile(hInf);
+        if (hClassKey != INVALID_HANDLE_VALUE)
+            RegCloseKey(hClassKey);
+        SetupTermDefaultQueueCallback(callback_context);
     }
-#endif
-
-    SetupInstallFromInfSectionW(NULL,
-                               hInf,
-                               SectionName,
-                               SPINST_REGISTRY,
-                               hClassKey,
-                               NULL,
-                               0,
-                               NULL,
-                               NULL,
-                               INVALID_HANDLE_VALUE,
-                               NULL);
-
-    /* FIXME: Process InterfaceInstall32 section */
-
-    if (bFileQueueCreated)
-       SetupCloseFileQueue(FileQueue);
 
-    SetupCloseInfFile(hInf);
-
-    RegCloseKey(hClassKey);
-    return TRUE;
+    TRACE("Returning %d\n", ret);
+    return ret;
 }
 
 
@@ -3189,11 +3385,11 @@ HKEY WINAPI SetupDiOpenClassRegKeyExW(
 
     if (Flags == DIOCR_INSTALLER)
     {
-        lpKeyName = ControlClass;
+        lpKeyName = REGSTR_PATH_CLASS_NT;
     }
     else if (Flags == DIOCR_INTERFACE)
     {
-        lpKeyName = DeviceClasses;
+        lpKeyName = REGSTR_PATH_DEVICE_CLASSES;
     }
     else
     {
@@ -3217,7 +3413,7 @@ HKEY WINAPI SetupDiOpenClassRegKeyExW(
     rc = RegOpenKeyExW(HKLM,
                      lpKeyName,
                      0,
-                     ClassGuid ? KEY_ENUMERATE_SUB_KEYS : samDesired,
+                     ClassGuid ? 0 : samDesired,
                      &hClassesKey);
     if (MachineName != NULL) RegCloseKey(HKLM);
     if (rc != ERROR_SUCCESS)
@@ -3357,7 +3553,7 @@ BOOL WINAPI SetupDiSetClassInstallParamsW(
         SP_DEVINSTALL_PARAMS_W InstallParams;
         BOOL Result;
 
-        InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+        InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
         Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
         if (!Result)
             goto done;
@@ -3397,14 +3593,16 @@ done:
 
 static BOOL PropertyChangeHandler(
        IN HDEVINFO DeviceInfoSet,
-       IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
+       IN PSP_DEVINFO_DATA DeviceInfoData,
        IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
        IN DWORD ClassInstallParamsSize)
 {
     PSP_PROPCHANGE_PARAMS PropChangeParams = (PSP_PROPCHANGE_PARAMS)ClassInstallParams;
     BOOL ret = FALSE;
 
-    if (ClassInstallParamsSize != sizeof(SP_PROPCHANGE_PARAMS))
+    if (!DeviceInfoData)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (ClassInstallParamsSize != sizeof(SP_PROPCHANGE_PARAMS))
         SetLastError(ERROR_INVALID_PARAMETER);
     else if (PropChangeParams && PropChangeParams->StateChange != DICS_ENABLE
         && PropChangeParams->StateChange != DICS_DISABLE && PropChangeParams->StateChange != DICS_PROPCHANGE
@@ -3559,6 +3757,9 @@ BOOL WINAPI SetupDiCallClassInstaller(
 
         switch (InstallFunction)
         {
+            case DIF_ADDPROPERTYPAGE_ADVANCED:
+                CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
+                break;
             case DIF_ALLOW_INSTALL:
                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
                 break;
@@ -3628,13 +3829,13 @@ BOOL WINAPI SetupDiCallClassInstaller(
                 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
                 if (hKey != INVALID_HANDLE_VALUE)
                 {
-                    rc = RegQueryValueExW(hKey, L"CoInstallers32", NULL, &dwRegType, NULL, &dwLength);
+                    rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, &dwRegType, NULL, &dwLength);
                     if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
                     {
                         LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
                         if (KeyBuffer != NULL)
                         {
-                            rc = RegQueryValueExW(hKey, L"CoInstallers32", NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
+                            rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
                             if (rc == ERROR_SUCCESS)
                             {
                                 LPWSTR ptr;
@@ -3663,7 +3864,7 @@ BOOL WINAPI SetupDiCallClassInstaller(
             {
                 rc = RegOpenKeyEx(
                     HKEY_LOCAL_MACHINE,
-                    L"SYSTEM\\CurrentControlSet\\Control\\CoDeviceInstallers",
+                    REGSTR_PATH_CODEVICEINSTALLERS,
                     0, /* Options */
                     KEY_QUERY_VALUE,
                     &hKey);
@@ -3710,13 +3911,13 @@ BOOL WINAPI SetupDiCallClassInstaller(
                 hKey = SetupDiOpenClassRegKey(&DeviceInfoData->ClassGuid, KEY_QUERY_VALUE);
                 if (hKey != INVALID_HANDLE_VALUE)
                 {
-                    rc = RegQueryValueExW(hKey, L"Installer32", NULL, &dwRegType, NULL, &dwLength);
+                    rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength);
                     if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
                     {
                         LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
                         if (KeyBuffer != NULL)
                         {
-                            rc = RegQueryValueExW(hKey, L"Installer32", NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
+                            rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
                             if (rc == ERROR_SUCCESS)
                             {
                                 /* Get ClassInstaller function pointer */
@@ -3840,6 +4041,35 @@ BOOL WINAPI SetupDiCallClassInstaller(
     return ret;
 }
 
+/***********************************************************************
+ *             SetupDiGetDeviceInfoListClass  (SETUPAPI.@)
+ */
+BOOL WINAPI SetupDiGetDeviceInfoListClass(
+        IN HDEVINFO DeviceInfoSet,
+        OUT LPGUID ClassGuid)
+{
+    struct DeviceInfoSet *list;
+    BOOL ret = FALSE;
+
+    TRACE("%p %p\n", DeviceInfoSet, ClassGuid);
+
+    if (!DeviceInfoSet)
+        SetLastError(ERROR_INVALID_HANDLE);
+    else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
+        SetLastError(ERROR_INVALID_HANDLE);
+    else if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
+        SetLastError(ERROR_NO_ASSOCIATED_CLASS);
+    else
+    {
+        memcpy(&ClassGuid, &list->ClassGuid, sizeof(GUID));
+
+        ret = TRUE;
+    }
+
+    TRACE("Returning %d\n", ret);
+    return ret;
+}
+
 /***********************************************************************
  *             SetupDiGetDeviceInfoListDetailW  (SETUPAPI.@)
  */
@@ -4215,7 +4445,7 @@ BOOL WINAPI SetupDiGetClassDevPropertySheetsW(
         if (hKey == INVALID_HANDLE_VALUE)
             goto cleanup;
 
-        rc = RegQueryValueExW(hKey, L"EnumPropPages32", NULL, &dwRegType, NULL, &dwLength);
+        rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, &dwRegType, NULL, &dwLength);
         if (rc == ERROR_FILE_NOT_FOUND)
         {
             /* No registry key. As it is optional, don't say it's a bad error */
@@ -4236,7 +4466,7 @@ BOOL WINAPI SetupDiGetClassDevPropertySheetsW(
             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
             goto cleanup;
         }
-        rc = RegQueryValueExW(hKey, L"EnumPropPages32", NULL, NULL, (LPBYTE)PropPageProvider, &dwLength);
+        rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, NULL, (LPBYTE)PropPageProvider, &dwLength);
         if (rc != ERROR_SUCCESS)
         {
             SetLastError(rc);
@@ -4321,6 +4551,63 @@ HKEY WINAPI SetupDiCreateDevRegKeyA(
     return ret;
 }
 
+static HKEY
+OpenHardwareProfileKey(
+        IN HKEY HKLM,
+        IN DWORD HwProfile,
+        IN DWORD samDesired)
+{
+    HKEY hHWProfilesKey = INVALID_HANDLE_VALUE;
+    HKEY hHWProfileKey = INVALID_HANDLE_VALUE;
+    HKEY ret = INVALID_HANDLE_VALUE;
+    LONG rc;
+
+    rc = RegOpenKeyExW(HKLM,
+        REGSTR_PATH_HWPROFILES,
+        0,
+        0,
+        &hHWProfilesKey);
+    if (rc != ERROR_SUCCESS)
+    {
+        SetLastError(rc);
+        goto cleanup;
+    }
+    if (HwProfile == 0)
+    {
+        rc = RegOpenKeyExW(
+            hHWProfilesKey,
+            REGSTR_KEY_CURRENT,
+            0,
+            KEY_CREATE_SUB_KEY,
+            &hHWProfileKey);
+    }
+    else
+    {
+        WCHAR subKey[5];
+        snprintfW(subKey, 4, L"%04lu", HwProfile);
+        subKey[4] = '\0';
+        rc = RegOpenKeyExW(
+            hHWProfilesKey,
+            subKey,
+            0,
+            KEY_CREATE_SUB_KEY,
+            &hHWProfileKey);
+    }
+    if (rc != ERROR_SUCCESS)
+    {
+        SetLastError(rc);
+        goto cleanup;
+    }
+    ret = hHWProfileKey;
+
+cleanup:
+    if (hHWProfilesKey != INVALID_HANDLE_VALUE)
+        RegCloseKey(hHWProfilesKey);
+    if (hHWProfileKey != INVALID_HANDLE_VALUE && hHWProfileKey != ret)
+        RegCloseKey(hHWProfileKey);
+    return ret;
+}
+
 /***********************************************************************
  *             SetupDiCreateDevRegKeyW (SETUPAPI.@)
  */
@@ -4362,37 +4649,79 @@ HKEY WINAPI SetupDiCreateDevRegKeyW(
         LPWSTR pDeviceInstance; /* Points into DriverKey, on the Index field */
         DWORD Index; /* Index used in the DriverKey name */
         DWORD rc;
+        HKEY hHWProfileKey = INVALID_HANDLE_VALUE;
+        HKEY hEnumKey = INVALID_HANDLE_VALUE;
         HKEY hClassKey = INVALID_HANDLE_VALUE;
         HKEY hDeviceKey = INVALID_HANDLE_VALUE;
         HKEY hKey = INVALID_HANDLE_VALUE;
+        HKEY RootKey;
 
-        if (Scope == DICS_FLAG_CONFIGSPECIFIC)
+        if (Scope == DICS_FLAG_GLOBAL)
+            RootKey = list->HKLM;
+        else /* Scope == DICS_FLAG_CONFIGSPECIFIC */
         {
-            FIXME("DICS_FLAG_CONFIGSPECIFIC case unimplemented\n");
-            goto cleanup;
+            hHWProfileKey = OpenHardwareProfileKey(list->HKLM, HwProfile, KEY_CREATE_SUB_KEY);
+            if (hHWProfileKey == INVALID_HANDLE_VALUE)
+                goto cleanup;
+            RootKey = hHWProfileKey;
         }
 
         if (KeyType == DIREG_DEV)
         {
-            FIXME("DIREG_DEV case unimplemented\n");
-        }
-        else /* KeyType == DIREG_DRV */
-        {
-            if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) != RPC_S_OK)
-                goto cleanup;
-            /* The driver key is in HKLM\System\CurrentControlSet\Control\Class\{GUID}\Index */
-            DriverKey = HeapAlloc(GetProcessHeap(), 0, (wcslen(lpGuidString) + 7) * sizeof(WCHAR) + sizeof(UNICODE_STRING));
-            if (!DriverKey)
-            {
-                SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)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->DeviceName,
+                0,
+                NULL,
+                REG_OPTION_NON_VOLATILE,
+#if _WIN32_WINNT >= 0x502
+                KEY_READ | KEY_WRITE,
+#else
+                KEY_ALL_ACCESS,
+#endif
+                NULL,
+                &hKey,
+                NULL);
+            if (rc != ERROR_SUCCESS)
+            {
+                SetLastError(rc);
+                goto cleanup;
+            }
+        }
+        else /* KeyType == DIREG_DRV */
+        {
+            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, (wcslen(lpGuidString) + 7) * sizeof(WCHAR) + sizeof(UNICODE_STRING));
+            if (!DriverKey)
+            {
+                SetLastError(ERROR_NOT_ENOUGH_MEMORY);
                 goto cleanup;
             }
             wcscpy(DriverKey, L"{");
             wcscat(DriverKey, lpGuidString);
             wcscat(DriverKey, L"}\\");
             pDeviceInstance = &DriverKey[wcslen(DriverKey)];
-            rc = RegOpenKeyExW(list->HKLM,
-                ControlClass,
+            rc = RegOpenKeyExW(RootKey,
+                REGSTR_PATH_CLASS_NT,
                 0,
                 KEY_CREATE_SUB_KEY,
                 &hClassKey);
@@ -4443,7 +4772,7 @@ HKEY WINAPI SetupDiCreateDevRegKeyW(
             hDeviceKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, Scope, HwProfile, DIREG_DEV, KEY_SET_VALUE);
             if (hDeviceKey == INVALID_HANDLE_VALUE)
                 goto cleanup;
-            rc = RegSetValueEx(hDeviceKey, L"Driver", 0, REG_SZ, (const BYTE *)DriverKey, (wcslen(DriverKey) + 1) * sizeof(WCHAR));
+            rc = RegSetValueEx(hDeviceKey, REGSTR_VAL_DRIVER, 0, REG_SZ, (const BYTE *)DriverKey, (wcslen(DriverKey) + 1) * sizeof(WCHAR));
             if (rc != ERROR_SUCCESS)
             {
                 SetLastError(rc);
@@ -4463,6 +4792,10 @@ cleanup:
         if (lpGuidString)
             RpcStringFreeW(&lpGuidString);
         HeapFree(GetProcessHeap(), 0, DriverKey);
+        if (hHWProfileKey != INVALID_HANDLE_VALUE)
+            RegCloseKey(hHWProfileKey);
+        if (hEnumKey != INVALID_HANDLE_VALUE)
+            RegCloseKey(hEnumKey);
         if (hClassKey != INVALID_HANDLE_VALUE)
             RegCloseKey(hClassKey);
         if (hDeviceKey != INVALID_HANDLE_VALUE)
@@ -4506,104 +4839,112 @@ HKEY WINAPI SetupDiOpenDevRegKey(
         SetLastError(ERROR_INVALID_PARAMETER);
     else
     {
-        HKEY hKey = INVALID_HANDLE_VALUE;
-        HKEY hRootKey = INVALID_HANDLE_VALUE;
         struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
         LPWSTR DriverKey = NULL;
         DWORD dwLength = 0;
         DWORD dwRegType;
         DWORD rc;
+        HKEY hHWProfileKey = INVALID_HANDLE_VALUE;
+        HKEY hEnumKey = INVALID_HANDLE_VALUE;
+        HKEY hKey = INVALID_HANDLE_VALUE;
+        HKEY RootKey;
 
-        if (Scope == DICS_FLAG_CONFIGSPECIFIC)
+        if (Scope == DICS_FLAG_GLOBAL)
+            RootKey = list->HKLM;
+        else /* Scope == DICS_FLAG_CONFIGSPECIFIC */
         {
-            FIXME("DICS_FLAG_CONFIGSPECIFIC case unimplemented\n");
+            hHWProfileKey = OpenHardwareProfileKey(list->HKLM, HwProfile, 0);
+            if (hHWProfileKey == INVALID_HANDLE_VALUE)
+                goto cleanup;
+            RootKey = hHWProfileKey;
         }
-        else /* Scope == DICS_FLAG_GLOBAL */
+
+        rc = RegOpenKeyExW(
+            RootKey,
+            REGSTR_PATH_SYSTEMENUM,
+            0, /* Options */
+            0,
+            &hEnumKey);
+        if (rc != ERROR_SUCCESS)
         {
-            rc = RegOpenKeyExW(
-                list->HKLM,
-                EnumKeyName,
-                0, /* Options */
-                KEY_ENUMERATE_SUB_KEYS,
-                &hRootKey);
-            if (rc != ERROR_SUCCESS)
-            {
-                SetLastError(rc);
-                goto cleanup;
-            }
-            rc = RegOpenKeyExW(
-                hRootKey,
-                deviceInfo->DeviceName,
-                0, /* Options */
-                KeyType == DIREG_DEV ? samDesired : KEY_QUERY_VALUE,
-                &hKey);
-            RegCloseKey(hRootKey);
-            hRootKey = INVALID_HANDLE_VALUE;
-            if (rc != ERROR_SUCCESS)
-            {
-                SetLastError(rc);
-                goto cleanup;
-            }
-            if (KeyType == DIREG_DEV)
-            {
-                /* We're done. Just return the hKey handle */
-                ret = hKey;
-                goto cleanup;
-            }
-            /* Read the 'Driver' key */
-            rc = RegQueryValueExW(hKey, L"Driver", NULL, &dwRegType, NULL, &dwLength);
-            if (rc != ERROR_SUCCESS)
-            {
-                SetLastError(rc);
-                goto cleanup;
-            }
-            if (dwRegType != REG_SZ)
-            {
-                SetLastError(ERROR_GEN_FAILURE);
-                goto cleanup;
-            }
-            DriverKey = HeapAlloc(GetProcessHeap(), 0, dwLength);
-            if (!DriverKey)
-            {
-                SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-                goto cleanup;
-            }
-            rc = RegQueryValueExW(hKey, L"Driver", NULL, &dwRegType, (LPBYTE)DriverKey, &dwLength);
-            if (rc != ERROR_SUCCESS)
-            {
-                SetLastError(rc);
-                goto cleanup;
-            }
-            RegCloseKey(hKey);
-            hKey = INVALID_HANDLE_VALUE;
-            /* Need to open the driver key */
-            rc = RegOpenKeyExW(
-                list->HKLM,
-                ControlClass,
-                0, /* Options */
-                KEY_ENUMERATE_SUB_KEYS,
-                &hRootKey);
-            if (rc != ERROR_SUCCESS)
-            {
-                SetLastError(rc);
-                goto cleanup;
-            }
-            rc = RegOpenKeyExW(
-                hRootKey,
-                DriverKey,
-                0, /* Options */
-                samDesired,
-                &hKey);
-            if (rc != ERROR_SUCCESS)
-            {
-                SetLastError(rc);
-                goto cleanup;
-            }
+            SetLastError(rc);
+            goto cleanup;
+        }
+        rc = RegOpenKeyExW(
+            hEnumKey,
+            deviceInfo->DeviceName,
+            0, /* Options */
+            KeyType == DIREG_DEV ? samDesired : KEY_QUERY_VALUE,
+            &hKey);
+        RegCloseKey(hEnumKey);
+        hEnumKey = INVALID_HANDLE_VALUE;
+        if (rc != ERROR_SUCCESS)
+        {
+            SetLastError(rc);
+            goto cleanup;
+        }
+        if (KeyType == DIREG_DEV)
+        {
+            /* We're done. Just return the hKey handle */
             ret = hKey;
+            goto cleanup;
+        }
+        /* Read the 'Driver' key */
+        rc = RegQueryValueExW(hKey, REGSTR_VAL_DRIVER, NULL, &dwRegType, NULL, &dwLength);
+        if (rc != ERROR_SUCCESS)
+        {
+            SetLastError(rc);
+            goto cleanup;
+        }
+        else if (dwRegType != REG_SZ)
+        {
+            SetLastError(ERROR_GEN_FAILURE);
+            goto cleanup;
+        }
+        DriverKey = HeapAlloc(GetProcessHeap(), 0, dwLength);
+        if (!DriverKey)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            goto cleanup;
+        }
+        rc = RegQueryValueExW(hKey, REGSTR_VAL_DRIVER, NULL, &dwRegType, (LPBYTE)DriverKey, &dwLength);
+        if (rc != ERROR_SUCCESS)
+        {
+            SetLastError(rc);
+            goto cleanup;
+        }
+        RegCloseKey(hKey);
+        hKey = INVALID_HANDLE_VALUE;
+        /* Need to open the driver key */
+        rc = RegOpenKeyExW(
+            RootKey,
+            REGSTR_PATH_CLASS_NT,
+            0, /* Options */
+            0,
+            &hEnumKey);
+        if (rc != ERROR_SUCCESS)
+        {
+            SetLastError(rc);
+            goto cleanup;
+        }
+        rc = RegOpenKeyExW(
+            hEnumKey,
+            DriverKey,
+            0, /* Options */
+            samDesired,
+            &hKey);
+        if (rc != ERROR_SUCCESS)
+        {
+            SetLastError(rc);
+            goto cleanup;
         }
+        ret = hKey;
+
 cleanup:
-        if (hRootKey != INVALID_HANDLE_VALUE)
-            RegCloseKey(hRootKey);
+        if (hHWProfileKey != INVALID_HANDLE_VALUE)
+            RegCloseKey(hHWProfileKey);
+        if (hEnumKey != INVALID_HANDLE_VALUE)
+            RegCloseKey(hEnumKey);
         if (hKey != INVALID_HANDLE_VALUE && hKey != ret)
             RegCloseKey(hKey);
     }
@@ -4819,13 +5160,18 @@ AddDriverToList(
         NULL);
 
     /* Copy MatchingId information */
-    driverInfo->MatchingId = HeapAlloc(GetProcessHeap(), 0, (wcslen(MatchingId) + 1) * sizeof(WCHAR));
-    if (!driverInfo->MatchingId)
+    if (MatchingId)
     {
-        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-        goto cleanup;
+        driverInfo->MatchingId = HeapAlloc(GetProcessHeap(), 0, (wcslen(MatchingId) + 1) * sizeof(WCHAR));
+        if (!driverInfo->MatchingId)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            goto cleanup;
+        }
+        RtlCopyMemory(driverInfo->MatchingId, MatchingId, (wcslen(MatchingId) + 1) * sizeof(WCHAR));
     }
-    RtlCopyMemory(driverInfo->MatchingId, MatchingId, (wcslen(MatchingId) + 1) * sizeof(WCHAR));
+    else
+        driverInfo->MatchingId = NULL;
 
     /* Get inf install section */
     Result = FALSE;
@@ -5088,8 +5434,6 @@ SetupDiBuildDriverInfoList(
         SetLastError(ERROR_INVALID_HANDLE);
     else if (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER)
         SetLastError(ERROR_INVALID_PARAMETER);
-    else if (DriverType == SPDIT_CLASSDRIVER && DeviceInfoData)
-        SetLastError(ERROR_INVALID_PARAMETER);
     else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData)
         SetLastError(ERROR_INVALID_PARAMETER);
     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
@@ -5098,7 +5442,7 @@ SetupDiBuildDriverInfoList(
     {
         BOOL Result;
 
-        InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+        InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
         Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
         if (!Result)
             goto done;
@@ -5163,40 +5507,64 @@ SetupDiBuildDriverInfoList(
                 goto done;
         }
 
-        /* Enumerate .inf files */
-        Result = FALSE;
-        RequiredSize = 32768; /* Initial buffer size */
-        SetLastError(ERROR_INSUFFICIENT_BUFFER);
-        while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+        if (InstallParams.Flags & DI_ENUMSINGLEINF)
         {
-            HeapFree(GetProcessHeap(), 0, Buffer);
+            /* InstallParams.DriverPath contains the name of a .inf file */
+            RequiredSize = wcslen(InstallParams.DriverPath) + 2;
             Buffer = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
             if (!Buffer)
             {
-                Result = FALSE;
                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-                break;
+                goto done;
             }
-            Result = SetupGetInfFileListW(
-                *InstallParams.DriverPath ? InstallParams.DriverPath : NULL,
-                INF_STYLE_WIN4,
-                Buffer, RequiredSize,
-                &RequiredSize);
+            wcscpy(Buffer, InstallParams.DriverPath);
+            ((LPWSTR)Buffer)[RequiredSize - 1] = 0;
+            Result = TRUE;
         }
-        if (!Result && GetLastError() == ERROR_FILE_NOT_FOUND)
+        else
         {
-            /* No .inf file in specified directory. So, we should
-             * success as we created an empty driver info list.
-             */
-            ret = TRUE;
-            goto done;
+            /* Enumerate .inf files */
+            Result = FALSE;
+            RequiredSize = 32768; /* Initial buffer size */
+            SetLastError(ERROR_INSUFFICIENT_BUFFER);
+            while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+            {
+                HeapFree(GetProcessHeap(), 0, Buffer);
+                Buffer = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
+                if (!Buffer)
+                {
+                    Result = FALSE;
+                    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                    break;
+                }
+                Result = SetupGetInfFileListW(
+                    *InstallParams.DriverPath ? InstallParams.DriverPath : NULL,
+                    INF_STYLE_WIN4,
+                    Buffer, RequiredSize,
+                    &RequiredSize);
+            }
+            if (!Result && GetLastError() == ERROR_FILE_NOT_FOUND)
+            {
+                /* No .inf file in specified directory. So, we should
+                 * success as we created an empty driver info list.
+                 */
+                ret = TRUE;
+                goto done;
+            }
         }
         if (Result)
         {
             LPCWSTR filename;
             LPWSTR pFullFilename;
 
-            if (*InstallParams.DriverPath)
+            if (InstallParams.Flags & DI_ENUMSINGLEINF)
+            {
+                FullInfFileName = HeapAlloc(GetProcessHeap(), 0, MAX_PATH);
+                if (!FullInfFileName)
+                    goto done;
+                pFullFilename = &FullInfFileName[0];
+            }
+            else if (*InstallParams.DriverPath)
             {
                 DWORD len;
                 len = GetFullPathNameW(InstallParams.DriverPath, 0, NULL, NULL);
@@ -5650,9 +6018,9 @@ SetupDiOpenDeviceInfoW(
             /* Open supposed registry key */
             rc = RegOpenKeyExW(
                 list->HKLM,
-                EnumKeyName,
+                REGSTR_PATH_SYSTEMENUM,
                 0, /* Options */
-                KEY_ENUMERATE_SUB_KEYS,
+                0,
                 &hEnumKey);
             if (rc != ERROR_SUCCESS)
             {
@@ -5797,10 +6165,12 @@ SetupDiEnumDriverInfoW(
         SetLastError(ERROR_INVALID_USER_BUFFER);
     else
     {
-        struct DeviceInfoElement *devInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
+        struct DeviceInfoElement *devInfo = NULL;
         PLIST_ENTRY ItemList;
+        if (DeviceInfoData)
+            devInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
         if (DriverType == SPDIT_CLASSDRIVER ||
-            devInfo->CreationFlags & DICD_INHERIT_CLASSDRVS)
+            (devInfo && devInfo->CreationFlags & DICD_INHERIT_CLASSDRVS))
         {
             ListHead = &((struct DeviceInfoSet *)DeviceInfoSet)->DriverListHead;
         }
@@ -5831,6 +6201,44 @@ SetupDiEnumDriverInfoW(
 }
 
 
+/***********************************************************************
+ *             SetupDiGetSelectedDevice (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiGetSelectedDevice(
+    IN HDEVINFO DeviceInfoSet,
+    OUT PSP_DEVINFO_DATA DeviceInfoData)
+{
+    struct DeviceInfoSet *list;
+    BOOL ret = FALSE;
+
+    TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
+
+    if (!DeviceInfoSet)
+        SetLastError(ERROR_INVALID_HANDLE);
+    else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
+        SetLastError(ERROR_INVALID_HANDLE);
+    else if (list->SelectedDevice == NULL)
+        SetLastError(ERROR_NO_DEVICE_SELECTED);
+    else if (!DeviceInfoData)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else
+    {
+        memcpy(&DeviceInfoData->ClassGuid,
+            &list->SelectedDevice->ClassGuid,
+            sizeof(GUID));
+        DeviceInfoData->DevInst = list->SelectedDevice->dnDevInst;
+        DeviceInfoData->Reserved = (ULONG_PTR)list->SelectedDevice;
+        ret = TRUE;
+    }
+
+    TRACE("Returning %d\n", ret);
+    return ret;
+}
+
+
 /***********************************************************************
  *             SetupDiGetSelectedDriverA (SETUPAPI.@)
  */
@@ -5918,7 +6326,7 @@ SetupDiGetSelectedDriverW(
     {
         SP_DEVINSTALL_PARAMS InstallParams;
 
-        InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+        InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
         if (SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
         {
             struct DriverInfoElement *driverInfo;
@@ -5941,6 +6349,40 @@ SetupDiGetSelectedDriverW(
 }
 
 
+/***********************************************************************
+ *             SetupDiSetSelectedDevice (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiSetSelectedDevice(
+    IN HDEVINFO DeviceInfoSet,
+    IN PSP_DEVINFO_DATA DeviceInfoData)
+{
+    struct DeviceInfoSet *list;
+    BOOL ret = FALSE;
+
+    TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
+
+    if (!DeviceInfoSet)
+        SetLastError(ERROR_INVALID_HANDLE);
+    else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
+        SetLastError(ERROR_INVALID_HANDLE);
+    else if (!DeviceInfoData)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else if (DeviceInfoData->Reserved == 0)
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else
+    {
+        list->SelectedDevice = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
+        ret = TRUE;
+    }
+
+    TRACE("Returning %d\n", ret);
+    return ret;
+}
+
+
 /***********************************************************************
  *             SetupDiSetSelectedDriverA (SETUPAPI.@)
  */
@@ -6346,15 +6788,99 @@ SetupDiGetDriverInfoDetailW(
     return ret;
 }
 
+/* Return the current hardware profile id, or -1 if error */
+static DWORD
+GetCurrentHwProfile(
+    IN HDEVINFO DeviceInfoSet)
+{
+    HKEY hKey = INVALID_HANDLE_VALUE;
+    DWORD dwRegType, dwLength;
+    DWORD hwProfile;
+    LONG rc;
+    DWORD ret = (DWORD)-1;
+
+    rc = RegOpenKeyExW(
+        ((struct DeviceInfoSet *)DeviceInfoSet)->HKLM,
+        REGSTR_PATH_IDCONFIGDB,
+        0, /* Options */
+        KEY_QUERY_VALUE,
+        &hKey);
+    if (rc != ERROR_SUCCESS)
+    {
+        SetLastError(rc);
+        goto cleanup;
+    }
+
+    dwLength = sizeof(DWORD);
+    rc = RegQueryValueExW(
+        hKey,
+        REGSTR_VAL_CURRENTCONFIG,
+        NULL,
+        &dwRegType,
+        (LPBYTE)&hwProfile, &dwLength);
+    if (rc != ERROR_SUCCESS)
+    {
+        SetLastError(rc);
+        goto cleanup;
+    }
+    else if (dwRegType != REG_DWORD || dwLength != sizeof(DWORD))
+    {
+        SetLastError(ERROR_GEN_FAILURE);
+        goto cleanup;
+    }
+
+    ret = hwProfile;
+
+cleanup:
+    if (hKey != INVALID_HANDLE_VALUE)
+        RegCloseKey(hKey);
+
+    return hwProfile;
+}
+
+static BOOL
+ResetDevice(
+    IN HDEVINFO DeviceInfoSet,
+    IN PSP_DEVINFO_DATA DeviceInfoData)
+{
+    PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData;
+    struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
+    NTSTATUS Status;
+
+    if (((struct DeviceInfoSet *)DeviceInfoSet)->HKLM != HKEY_LOCAL_MACHINE)
+    {
+        /* At the moment, I only know how to start local devices */
+        SetLastError(ERROR_INVALID_COMPUTERNAME);
+        return FALSE;
+    }
+
+    RtlInitUnicodeString(&ResetDeviceData.DeviceInstance, deviceInfo->DeviceName);
+    Status = NtPlugPlayControl(PlugPlayControlResetDevice, &ResetDeviceData, sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA));
+    SetLastError(RtlNtStatusToDosError(Status));
+    return NT_SUCCESS(Status);
+}
+
+static BOOL StopDevice(
+    IN HDEVINFO DeviceInfoSet,
+    IN PSP_DEVINFO_DATA DeviceInfoData)
+{
+    FIXME("Stub %p %p\n", DeviceInfoSet, DeviceInfoData);
+    return TRUE;
+}
+
 /***********************************************************************
  *             SetupDiChangeState (SETUPAPI.@)
  */
 BOOL WINAPI
 SetupDiChangeState(
     IN HDEVINFO DeviceInfoSet,
-    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
+    IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
 {
     PSP_PROPCHANGE_PARAMS PropChange;
+    HKEY hKey = INVALID_HANDLE_VALUE;
+    LPCWSTR RegistryValueName;
+    DWORD dwConfigFlags, dwLength, dwRegType;
+    LONG rc;
     BOOL ret = FALSE;
 
     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
@@ -6366,13 +6892,90 @@ SetupDiChangeState(
     if (!PropChange)
     {
         SetLastError(ERROR_INVALID_PARAMETER);
-        goto done;
+        goto cleanup;
     }
 
-    FIXME("Stub %p %p\n", DeviceInfoSet, DeviceInfoData);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    if (PropChange->Scope == DICS_FLAG_GLOBAL)
+        RegistryValueName = REGSTR_VAL_CONFIGFLAGS;
+    else
+        RegistryValueName = REGSTR_VAL_CSCONFIGFLAGS;
+
+    switch (PropChange->StateChange)
+    {
+        case DICS_ENABLE:
+        case DICS_DISABLE:
+        {
+            /* Enable/disable device in registry */
+            hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, PropChange->Scope, PropChange->HwProfile, DIREG_DEV, 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);
+            if (hKey == INVALID_HANDLE_VALUE)
+                break;
+            dwLength = sizeof(DWORD);
+            rc = RegQueryValueExW(
+                hKey,
+                RegistryValueName,
+                NULL,
+                &dwRegType,
+                (LPBYTE)&dwConfigFlags, &dwLength);
+            if (rc == ERROR_FILE_NOT_FOUND)
+                dwConfigFlags = 0;
+            else if (rc != ERROR_SUCCESS)
+            {
+                SetLastError(rc);
+                goto cleanup;
+            }
+            else if (dwRegType != REG_DWORD || dwLength != sizeof(DWORD))
+            {
+                SetLastError(ERROR_GEN_FAILURE);
+                goto cleanup;
+            }
+            if (PropChange->StateChange == DICS_ENABLE)
+                dwConfigFlags &= ~(PropChange->Scope == DICS_FLAG_GLOBAL ? CONFIGFLAG_DISABLED : CSCONFIGFLAG_DISABLED);
+            else
+                dwConfigFlags |= (PropChange->Scope == DICS_FLAG_GLOBAL ? CONFIGFLAG_DISABLED : CSCONFIGFLAG_DISABLED);
+            rc = RegSetValueEx(
+                hKey,
+                RegistryValueName,
+                0,
+                REG_DWORD,
+                (LPBYTE)&dwConfigFlags, sizeof(DWORD));
+            if (rc != ERROR_SUCCESS)
+            {
+                SetLastError(rc);
+                goto cleanup;
+            }
+
+            /* Enable/disable device if needed */
+            if (PropChange->Scope == DICS_FLAG_GLOBAL
+                || PropChange->HwProfile == 0
+                || PropChange->HwProfile == GetCurrentHwProfile(DeviceInfoSet))
+            {
+                if (PropChange->StateChange == DICS_ENABLE)
+                    ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
+                else
+                    ret = StopDevice(DeviceInfoSet, DeviceInfoData);
+            }
+            else
+                ret = TRUE;
+            break;
+        }
+        case DICS_PROPCHANGE:
+        {
+            ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
+            break;
+        }
+        default:
+        {
+            ERR("Unknown StateChange 0x%lx\n", PropChange->StateChange);
+            SetLastError(ERROR_NOT_SUPPORTED);
+        }
+    }
+
+cleanup:
+    if (hKey != INVALID_HANDLE_VALUE)
+        RegCloseKey(hKey);
 
-done:
     TRACE("Returning %d\n", ret);
     return ret;
 }
@@ -6443,6 +7046,9 @@ SetupDiInstallDriverFiles(
         struct DriverInfoElement *SelectedDriver;
         WCHAR SectionName[MAX_PATH];
         DWORD SectionNameLength = 0;
+        PVOID InstallMsgHandler;
+        PVOID InstallMsgHandlerContext;
+        PVOID Context = NULL;
 
         InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
         ret = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
@@ -6459,21 +7065,49 @@ SetupDiInstallDriverFiles(
         ret = SetupDiGetActualSectionToInstallW(
             SelectedDriver->InfFileDetails->hInf,
             SelectedDriver->Details.SectionName,
-            SectionName, MAX_PATH, &SectionNameLength, NULL);
+            SectionName, MAX_PATH - strlenW(DotCoInstallers), &SectionNameLength, NULL);
         if (!ret)
             goto done;
 
-        if (!InstallParams.InstallMsgHandler)
+        if (InstallParams.InstallMsgHandler)
         {
-            InstallParams.InstallMsgHandler = SetupDefaultQueueCallbackW;
-            InstallParams.InstallMsgHandlerContext = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
-            SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
+            InstallMsgHandler = InstallParams.InstallMsgHandler;
+            InstallMsgHandlerContext = InstallParams.InstallMsgHandlerContext;
+        }
+        else
+        {
+            Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
+            if (!Context)
+                goto cleanup;
+            InstallMsgHandler = SetupDefaultQueueCallback;
+            InstallMsgHandlerContext = Context;
         }
         ret = SetupInstallFromInfSectionW(InstallParams.hwndParent,
             SelectedDriver->InfFileDetails->hInf, SectionName,
             SPINST_FILES, NULL, NULL, SP_COPY_NEWER,
-            InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext,
+            InstallMsgHandler, InstallMsgHandlerContext,
             DeviceInfoSet, DeviceInfoData);
+        if (!ret)
+            goto done;
+
+        /* Install files from .CoInstallers section */
+        lstrcatW(SectionName, DotCoInstallers);
+        ret = SetupInstallFromInfSectionW(InstallParams.hwndParent,
+            SelectedDriver->InfFileDetails->hInf, SectionName,
+            SPINST_FILES, NULL, NULL, SP_COPY_NEWER,
+            InstallMsgHandler, InstallMsgHandlerContext,
+            DeviceInfoSet, DeviceInfoData);
+        if (!ret)
+            goto done;
+
+        /* Set the DI_NOFILECOPY flag to prevent another
+         * installation during SetupDiInstallDevice */
+        InstallParams.Flags |= DI_NOFILECOPY;
+        ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
+
+cleanup:
+       if (Context)
+           SetupTermDefaultQueueCallback(Context);
     }
 
 done:
@@ -6512,6 +7146,7 @@ SetupDiRegisterCoDeviceInstallers(
         WCHAR SectionName[MAX_PATH];
         DWORD SectionNameLength = 0;
         HKEY hKey = INVALID_HANDLE_VALUE;
+        PVOID Context = NULL;
 
         InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
         Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
@@ -6530,9 +7165,9 @@ SetupDiRegisterCoDeviceInstallers(
             SelectedDriver->InfFileDetails->hInf,
             SelectedDriver->Details.SectionName,
             SectionName, MAX_PATH, &SectionNameLength, NULL);
-        if (!Result || SectionNameLength > MAX_PATH - wcslen(L".CoInstallers") - 1)
+        if (!Result || SectionNameLength > MAX_PATH - strlenW(DotCoInstallers) - 1)
             goto cleanup;
-        wcscat(SectionName, L".CoInstallers");
+        lstrcatW(SectionName, DotCoInstallers);
 
         /* Open/Create driver key information */
 #if _WIN32_WINNT >= 0x502
@@ -6550,17 +7185,14 @@ SetupDiRegisterCoDeviceInstallers(
         if (!(InstallParams.Flags & DI_NOFILECOPY))
         {
             DoAction |= SPINST_FILES;
-            if (!InstallParams.InstallMsgHandler)
-            {
-                InstallParams.InstallMsgHandler = SetupDefaultQueueCallbackW;
-                InstallParams.InstallMsgHandlerContext = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
-                SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
-            }
+            Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
+            if (!Context)
+                goto cleanup;
         }
         Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
             SelectedDriver->InfFileDetails->hInf, SectionName,
             DoAction, hKey, NULL, SP_COPY_NEWER,
-            InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext,
+            SetupDefaultQueueCallback, Context,
             DeviceInfoSet, DeviceInfoData);
         if (!Result)
             goto cleanup;
@@ -6568,6 +7200,8 @@ SetupDiRegisterCoDeviceInstallers(
         ret = TRUE;
 
 cleanup:
+        if (Context)
+            SetupTermDefaultQueueCallback(Context);
         if (hKey != INVALID_HANDLE_VALUE)
             RegCloseKey(hKey);
     }
@@ -6576,6 +7210,24 @@ cleanup:
     return ret;
 }
 
+static BOOL
+InstallOneInterface(
+    IN LPGUID InterfaceGuid,
+    IN LPCWSTR ReferenceString,
+    IN LPCWSTR InterfaceSection,
+    IN UINT InterfaceFlags)
+{
+    if (InterfaceFlags != 0)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    FIXME("Need to AddInterface(%s %s %s %u)\n", debugstr_guid(InterfaceGuid),
+        debugstr_w(ReferenceString), debugstr_w(InterfaceSection), InterfaceFlags);
+    return TRUE;
+}
+
 /***********************************************************************
  *             SetupDiInstallDeviceInterfaces (SETUPAPI.@)
  */
@@ -6584,12 +7236,122 @@ SetupDiInstallDeviceInterfaces(
     IN HDEVINFO DeviceInfoSet,
     IN PSP_DEVINFO_DATA DeviceInfoData)
 {
+    struct DeviceInfoSet *list = NULL;
+    BOOL ret = FALSE;
+
     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
 
-    FIXME("SetupDiInstallDeviceInterfaces not implemented. Doing nothing\n");
-    //SetLastError(ERROR_GEN_FAILURE);
-    //return FALSE;
-    return TRUE;
+    if (!DeviceInfoSet)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
+        SetLastError(ERROR_INVALID_HANDLE);
+    else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
+        SetLastError(ERROR_INVALID_HANDLE);
+    else if (!DeviceInfoData)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else
+    {
+        struct DriverInfoElement *SelectedDriver;
+        SP_DEVINSTALL_PARAMS_W InstallParams;
+        WCHAR SectionName[MAX_PATH];
+        DWORD SectionNameLength = 0;
+        INFCONTEXT ContextInterface;
+        LPWSTR InterfaceGuidString = NULL;
+        LPWSTR ReferenceString = NULL;
+        LPWSTR InterfaceSection = NULL;
+        UINT InterfaceFlags;
+        GUID InterfaceGuid;
+        BOOL Result;
+
+        InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
+        Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
+        if (!Result)
+            goto cleanup;
+
+        SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
+        if (SelectedDriver == NULL)
+        {
+            SetLastError(ERROR_NO_DRIVER_SELECTED);
+            ret = FALSE;
+            goto cleanup;
+        }
+
+        /* Get .Interfaces section name */
+        Result = SetupDiGetActualSectionToInstallW(
+            SelectedDriver->InfFileDetails->hInf,
+            SelectedDriver->Details.SectionName,
+            SectionName, MAX_PATH, &SectionNameLength, NULL);
+        if (!Result || SectionNameLength > MAX_PATH - wcslen(L".Interfaces") - 1)
+            goto cleanup;
+        wcscat(SectionName, L".Interfaces");
+
+        ret = TRUE;
+        Result = SetupFindFirstLineW(
+            SelectedDriver->InfFileDetails->hInf,
+            SectionName,
+            L"AddInterface",
+            &ContextInterface);
+        while (ret && Result)
+        {
+            ret = GetStringField(&ContextInterface, 1, &InterfaceGuidString);
+            if (!ret)
+                goto cleanup;
+            else if (strlenW(InterfaceGuidString) != MAX_GUID_STRING_LEN - 1)
+            {
+                SetLastError(ERROR_INVALID_PARAMETER);
+                ret = FALSE;
+                goto cleanup;
+            }
+
+            InterfaceGuidString[MAX_GUID_STRING_LEN - 2] = '\0'; /* Replace the } by a NULL character */
+            if (UuidFromStringW(&InterfaceGuidString[1], &InterfaceGuid) != RPC_S_OK)
+            {
+                /* Bad GUID, skip the entry */
+                SetLastError(ERROR_INVALID_PARAMETER);
+                ret = FALSE;
+                goto cleanup;
+            }
+
+            ret = GetStringField(&ContextInterface, 2, &ReferenceString);
+            if (!ret)
+                goto cleanup;
+
+            ret = GetStringField(&ContextInterface, 3, &InterfaceSection);
+            if (!ret)
+                goto cleanup;
+
+            ret = SetupGetIntField(
+                &ContextInterface,
+                4, /* Field index */
+                &InterfaceFlags);
+            if (!ret)
+            {
+                if (GetLastError() == ERROR_INVALID_PARAMETER)
+                {
+                    /* The field may be empty. Ignore the error */
+                    InterfaceFlags = 0;
+                    ret = TRUE;
+                }
+                else
+                    goto cleanup;
+            }
+
+            /* Install Interface */
+            ret = InstallOneInterface(&InterfaceGuid, ReferenceString, InterfaceSection, InterfaceFlags);
+
+cleanup:
+            MyFree(InterfaceGuidString);
+            MyFree(ReferenceString);
+            MyFree(InterfaceSection);
+            InterfaceGuidString = ReferenceString = InterfaceSection = NULL;
+            Result = SetupFindNextMatchLineW(&ContextInterface, L"AddInterface", &ContextInterface);
+        }
+    }
+
+    TRACE("Returning %d\n", ret);
+    return ret;
 }
 
 BOOL
@@ -6639,7 +7401,6 @@ SetupDiInstallDevice(
     IN HDEVINFO DeviceInfoSet,
     IN PSP_DEVINFO_DATA DeviceInfoData)
 {
-    struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
     SP_DEVINSTALL_PARAMS_W InstallParams;
     struct DriverInfoElement *SelectedDriver;
     SYSTEMTIME DriverDate;
@@ -6647,11 +7408,8 @@ SetupDiInstallDevice(
     WCHAR Buffer[32];
     DWORD SectionNameLength = 0;
     BOOL Result = FALSE;
-    INFCONTEXT ContextService;
-    INT Flags;
     ULONG DoAction;
     DWORD RequiredSize;
-    LPCWSTR AssociatedService = NULL;
     LPWSTR pSectionName = NULL;
     WCHAR ClassName[MAX_CLASS_NAME_LEN];
     GUID ClassGuid;
@@ -6662,6 +7420,7 @@ SetupDiInstallDevice(
     BOOL NeedtoCopyFile;
     LARGE_INTEGER fullVersion;
     LONG rc;
+    PVOID Context = NULL;
     BOOL ret = FALSE; /* Return value */
 
     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
@@ -6707,7 +7466,7 @@ SetupDiInstallDevice(
         SelectedDriver->InfFileDetails->hInf,
         SelectedDriver->Details.SectionName,
         SectionName, MAX_PATH, &SectionNameLength, NULL);
-    if (!Result || SectionNameLength > MAX_PATH - 9)
+    if (!Result || SectionNameLength > MAX_PATH - wcslen(DotServices))
         goto cleanup;
     pSectionName = &SectionName[wcslen(SectionName)];
 
@@ -6741,33 +7500,24 @@ SetupDiInstallDevice(
         goto cleanup;
 
     /* Install main section */
-    DoAction = SPINST_REGISTRY;
+    DoAction = 0;
+    if (!(InstallParams.FlagsEx & DI_FLAGSEX_NO_DRVREG_MODIFY))
+        DoAction |= SPINST_REGISTRY;
     if (!(InstallParams.Flags & DI_NOFILECOPY))
     {
         DoAction |= SPINST_FILES;
-        if (!InstallParams.InstallMsgHandler)
-        {
-            InstallParams.InstallMsgHandler = SetupDefaultQueueCallbackW;
-            InstallParams.InstallMsgHandlerContext = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
-            SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
-        }
+        Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
+        if (!Context)
+            goto cleanup;
     }
     *pSectionName = '\0';
     Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
         SelectedDriver->InfFileDetails->hInf, SectionName,
         DoAction, hKey, NULL, SP_COPY_NEWER,
-        InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext,
+        SetupDefaultQueueCallback, Context,
         DeviceInfoSet, DeviceInfoData);
     if (!Result)
         goto cleanup;
-    if (!(InstallParams.Flags & DI_NOFILECOPY) && !(InstallParams.Flags & DI_NOVCP))
-    {
-        if (Result && InstallParams.InstallMsgHandler == SetupDefaultQueueCallbackW)
-        {
-            /* Delete resources allocated by SetupInitDefaultQueueCallback */
-            SetupTermDefaultQueueCallback(InstallParams.InstallMsgHandlerContext);
-        }
-    }
     InstallParams.Flags |= DI_NOFILECOPY;
     SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
 
@@ -6788,22 +7538,22 @@ SetupDiInstallDevice(
     if (rc == ERROR_SUCCESS)
         rc = RegSetValueEx(hKey, L"DriverDateData", 0, REG_BINARY, (const BYTE *)&SelectedDriver->Info.DriverDate, sizeof(FILETIME));
     if (rc == ERROR_SUCCESS)
-        rc = RegSetValueEx(hKey, L"DriverDesc", 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (wcslen(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
+        rc = RegSetValueEx(hKey, REGSTR_VAL_DRVDESC, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (wcslen(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
     if (rc == ERROR_SUCCESS)
     {
         swprintf(Buffer, L"%u.%u.%u.%u", fullVersion.HighPart >> 16, fullVersion.HighPart & 0xffff, fullVersion.LowPart >> 16, fullVersion.LowPart & 0xffff);
         rc = RegSetValueEx(hKey, L"DriverVersion", 0, REG_SZ, (const BYTE *)Buffer, (wcslen(Buffer) + 1) * sizeof(WCHAR));
     }
     if (rc == ERROR_SUCCESS)
-        rc = RegSetValueEx(hKey, L"InfPath", 0, REG_SZ, (const BYTE *)SelectedDriver->Details.InfFileName, (wcslen(SelectedDriver->Details.InfFileName) + 1) * sizeof(WCHAR));
+        rc = RegSetValueEx(hKey, REGSTR_VAL_INFPATH, 0, REG_SZ, (const BYTE *)SelectedDriver->Details.InfFileName, (wcslen(SelectedDriver->Details.InfFileName) + 1) * sizeof(WCHAR));
     if (rc == ERROR_SUCCESS)
-        rc = RegSetValueEx(hKey, L"InfSection", 0, REG_SZ, (const BYTE *)SelectedDriver->Details.SectionName, (wcslen(SelectedDriver->Details.SectionName) + 1) * sizeof(WCHAR));
+        rc = RegSetValueEx(hKey, REGSTR_VAL_INFSECTION, 0, REG_SZ, (const BYTE *)SelectedDriver->Details.SectionName, (wcslen(SelectedDriver->Details.SectionName) + 1) * sizeof(WCHAR));
     if (rc == ERROR_SUCCESS)
-        rc = RegSetValueEx(hKey, L"InfSectionExt", 0, REG_SZ, (const BYTE *)&SectionName[wcslen(SelectedDriver->Details.SectionName)], (wcslen(SectionName) - wcslen(SelectedDriver->Details.SectionName) + 1) * sizeof(WCHAR));
+        rc = RegSetValueEx(hKey, REGSTR_VAL_INFSECTIONEXT, 0, REG_SZ, (const BYTE *)&SectionName[wcslen(SelectedDriver->Details.SectionName)], (wcslen(SectionName) - wcslen(SelectedDriver->Details.SectionName) + 1) * sizeof(WCHAR));
     if (rc == ERROR_SUCCESS)
-        rc = RegSetValueEx(hKey, L"MatchingDeviceId", 0, REG_SZ, (const BYTE *)SelectedDriver->MatchingId, (wcslen(SelectedDriver->MatchingId) + 1) * sizeof(WCHAR));
+        rc = RegSetValueEx(hKey, REGSTR_VAL_MATCHINGDEVID, 0, REG_SZ, (const BYTE *)SelectedDriver->MatchingId, (wcslen(SelectedDriver->MatchingId) + 1) * sizeof(WCHAR));
     if (rc == ERROR_SUCCESS)
-        rc = RegSetValueEx(hKey, L"ProviderName", 0, REG_SZ, (const BYTE *)SelectedDriver->Info.ProviderName, (wcslen(SelectedDriver->Info.ProviderName) + 1) * sizeof(WCHAR));
+        rc = RegSetValueEx(hKey, REGSTR_VAL_PROVIDER_NAME, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.ProviderName, (wcslen(SelectedDriver->Info.ProviderName) + 1) * sizeof(WCHAR));
     if (rc != ERROR_SUCCESS)
     {
        SetLastError(rc);
@@ -6815,99 +7565,19 @@ SetupDiInstallDevice(
     /* FIXME: Process .LogConfigOverride section */
 
     /* Install .Services section */
-    wcscpy(pSectionName, L".Services");
-    Result = SetupFindFirstLineW(SelectedDriver->InfFileDetails->hInf, SectionName, NULL, &ContextService);
-    while (Result)
-    {
-        LPWSTR ServiceName = NULL;
-        LPWSTR ServiceSection = NULL;
-
-        Result = SetupGetStringFieldW(
-            &ContextService,
-            1, /* Field index */
-            NULL, 0,
-            &RequiredSize);
-        if (!Result)
-            goto nextservice;
-        if (RequiredSize > 0)
-        {
-            /* We got the needed size for the buffer */
-            ServiceName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
-            if (!ServiceName)
-            {
-                SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-                goto nextservice;
-            }
-            Result = SetupGetStringFieldW(
-                &ContextService,
-                1, /* Field index */
-                ServiceName, RequiredSize,
-                &RequiredSize);
-            if (!Result)
-                goto nextservice;
-        }
-        Result = SetupGetIntField(
-            &ContextService,
-            2, /* Field index */
-            &Flags);
-        if (!Result)
-        {
-            /* The field may be empty. Ignore the error */
-            Flags = 0;
-        }
-        Result = SetupGetStringFieldW(
-            &ContextService,
-            3, /* Field index */
-            NULL, 0,
-            &RequiredSize);
-        if (!Result)
-        {
-            if (GetLastError() == ERROR_INVALID_PARAMETER)
-            {
-                /* This first is probably missing. It is not
-                 * required, so ignore the error */
-                RequiredSize = 0;
-                Result = TRUE;
-            }
-            else
-                goto nextservice;
-        }
-        if (RequiredSize > 0)
-        {
-            /* We got the needed size for the buffer */
-            ServiceSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
-            if (!ServiceSection)
-            {
-                SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-                goto nextservice;
-            }
-            Result = SetupGetStringFieldW(
-                &ContextService,
-                3, /* Field index */
-                ServiceSection, RequiredSize,
-                &RequiredSize);
-            if (!Result)
-                goto nextservice;
-
-            SetLastError(ERROR_SUCCESS);
-            Result = SetupInstallServicesFromInfSectionExW(
-                SelectedDriver->InfFileDetails->hInf,
-                ServiceSection, Flags, DeviceInfoSet, DeviceInfoData, ServiceName, NULL);
-        }
-        if (Result && (Flags & SPSVCINST_ASSOCSERVICE))
-        {
-            AssociatedService = ServiceName;
-            ServiceName = NULL;
-            if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED)
-                RebootRequired = TRUE;
-        }
-nextservice:
-        HeapFree(GetProcessHeap(), 0, ServiceName);
-        HeapFree(GetProcessHeap(), 0, ServiceSection);
-        if (!Result)
-            goto cleanup;
-        Result = SetupFindNextLine(&ContextService, &ContextService);
-    }
+    wcscpy(pSectionName, DotServices);
+    Result = SetupInstallServicesFromInfSectionExW(
+        SelectedDriver->InfFileDetails->hInf,
+        SectionName,
+        0,
+        DeviceInfoSet,
+        DeviceInfoData,
+        NULL,
+        NULL);
+    if (!Result)
+        goto cleanup;
+    if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED)
+        RebootRequired = TRUE;
 
     /* Copy .inf file to Inf\ directory (if needed) */
     Result = InfIsFromOEMLocation(SelectedDriver->InfFileDetails->FullInfFileName, &NeedtoCopyFile);
@@ -6935,11 +7605,14 @@ nextservice:
         goto cleanup;
 
     /* Install .HW section */
+    DoAction = 0;
+    if (!(InstallParams.FlagsEx & DI_FLAGSEX_NO_DRVREG_MODIFY))
+        DoAction |= SPINST_REGISTRY;
     wcscpy(pSectionName, L".HW");
     Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
         SelectedDriver->InfFileDetails->hInf, SectionName,
-        SPINST_REGISTRY, hKey, NULL, 0,
-        InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext,
+        DoAction, hKey, NULL, 0,
+        NULL, NULL,
         DeviceInfoSet, DeviceInfoData);
     if (!Result)
         goto cleanup;
@@ -6950,16 +7623,13 @@ nextservice:
     TRACE("ClassGUID       : '%S'\n", lpFullGuidString);
     TRACE("DeviceDesc      : '%S'\n", SelectedDriver->Info.Description);
     TRACE("Mfg             : '%S'\n", SelectedDriver->Info.MfgName);
-    TRACE("Service         : '%S'\n", AssociatedService);
-    rc = RegSetValueEx(hKey, L"Class", 0, REG_SZ, (const BYTE *)ClassName, (wcslen(ClassName) + 1) * sizeof(WCHAR));
+    rc = RegSetValueEx(hKey, REGSTR_VAL_CLASS, 0, REG_SZ, (const BYTE *)ClassName, (wcslen(ClassName) + 1) * sizeof(WCHAR));
     if (rc == ERROR_SUCCESS)
-        rc = RegSetValueEx(hKey, L"ClassGUID", 0, REG_SZ, (const BYTE *)lpFullGuidString, (wcslen(lpFullGuidString) + 1) * sizeof(WCHAR));
+        rc = RegSetValueEx(hKey, REGSTR_VAL_CLASSGUID, 0, REG_SZ, (const BYTE *)lpFullGuidString, (wcslen(lpFullGuidString) + 1) * sizeof(WCHAR));
     if (rc == ERROR_SUCCESS)
-        rc = RegSetValueEx(hKey, L"DeviceDesc", 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (wcslen(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
+        rc = RegSetValueEx(hKey, REGSTR_VAL_DEVDESC, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (wcslen(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
     if (rc == ERROR_SUCCESS)
-        rc = RegSetValueEx(hKey, L"Mfg", 0, REG_SZ, (const BYTE *)SelectedDriver->Info.MfgName, (wcslen(SelectedDriver->Info.MfgName) + 1) * sizeof(WCHAR));
-    if (rc == ERROR_SUCCESS && *AssociatedService)
-        rc = RegSetValueEx(hKey, L"Service", 0, REG_SZ, (const BYTE *)AssociatedService, (wcslen(AssociatedService) + 1) * sizeof(WCHAR));
+        rc = RegSetValueEx(hKey, REGSTR_VAL_MFG, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.MfgName, (wcslen(SelectedDriver->Info.MfgName) + 1) * sizeof(WCHAR));
     if (rc != ERROR_SUCCESS)
     {
        SetLastError(rc);
@@ -6968,13 +7638,7 @@ nextservice:
 
     /* Start the device */
     if (!RebootRequired && !(InstallParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT | DI_DONOTCALLCONFIGMG)))
-    {
-        PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData;
-        NTSTATUS Status;
-        RtlInitUnicodeString(&ResetDeviceData.DeviceInstance, DevInfo->DeviceName);
-        Status = NtPlugPlayControl(PlugPlayControlResetDevice, &ResetDeviceData, sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA));
-        ret = NT_SUCCESS(Status);
-    }
+        ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
     else
         ret = TRUE;
 
@@ -6986,9 +7650,9 @@ cleanup:
         RegCloseKey(hKey);
     if (lpGuidString)
         RpcStringFreeW(&lpGuidString);
-    HeapFree(GetProcessHeap(), 0, (LPWSTR)AssociatedService);
     HeapFree(GetProcessHeap(), 0, lpFullGuidString);
-
+    if (Context)
+        SetupTermDefaultQueueCallback(Context);
     TRACE("Returning %d\n", ret);
     return ret;
 }