- Set SPINT_DEFAULT, SPINT_REMOVED and SPINT_ACTIVE in interface flags when needed
[reactos.git] / reactos / lib / setupapi / devinst.c
index 7e6d27e..1ed0c4f 100644 (file)
@@ -28,9 +28,12 @@ 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 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};
 
@@ -1651,6 +1654,7 @@ static LONG SETUP_CreateSerialDeviceList(
                     HeapFree(GetProcessHeap(), 0, devices);
                 return GetLastError();
             }
+            interfaceInfo->Flags |= SPINT_ACTIVE | SPINT_DEFAULT;
             InsertTailList(&deviceInfo->InterfaceListHead, &interfaceInfo->ListEntry);
         }
     }
@@ -1670,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;
@@ -1678,6 +1683,7 @@ static LONG SETUP_CreateInterfaceList(
     DWORD i, j;
     DWORD dwLength, dwInstancePathLength;
     DWORD dwRegType;
+    DWORD LinkedValue;
     GUID ClassGuid;
     struct DeviceInfoElement *deviceInfo;
 
@@ -1896,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);
@@ -2372,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;
                     }
@@ -3174,182 +3196,6 @@ static HKEY CreateClassKey(HINF hInf)
 }
 
 
-static BOOL
-InstallServicesSection(
-        IN HINF hInf,
-        IN PCWSTR SectionName,
-        IN HDEVINFO DeviceInfoSet OPTIONAL,
-        IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
-        OUT PCWSTR* pAssociatedService OPTIONAL,
-        OUT PBOOL pRebootRequired OPTIONAL)
-{
-    INFCONTEXT ContextService;
-    INFCONTEXT ContextInclude;
-    DWORD RequiredSize;
-    INT Flags;
-    BOOL ret = FALSE;
-
-    /* Parse 'Include' line */
-    if (SetupFindFirstLineW(hInf, SectionName, L"Include", &ContextInclude))
-    {
-        DWORD Index = 1;
-        while (TRUE)
-        {
-            static WCHAR szBuffer[MAX_PATH];
-            PWSTR pBuffer = NULL;
-            DWORD required;
-
-            ret = SetupGetStringFieldW(&ContextInclude, Index, szBuffer, MAX_PATH, &required);
-            if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
-                break;
-            else if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
-            {
-                pBuffer = MyMalloc(required);
-                ret = SetupGetStringFieldW(&ContextInclude, Index, pBuffer, required, &required);
-            }
-            if (ret)
-                ret = SetupOpenAppendInfFileW(pBuffer ? pBuffer : szBuffer, hInf, NULL);
-
-            MyFree(pBuffer);
-            if (!ret)
-                goto done;
-            Index++;
-        }
-    }
-
-    /* Parse 'Needs' line */
-    if (SetupFindFirstLineW(hInf, SectionName, L"Needs", &ContextInclude))
-    {
-        DWORD Index = 1;
-        while (TRUE)
-        {
-            static WCHAR szBuffer[MAX_PATH];
-            PWSTR pBuffer = NULL;
-            DWORD required;
-
-            ret = SetupGetStringFieldW(&ContextInclude, Index, szBuffer, MAX_PATH, &required);
-            if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
-                break;
-            else if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
-            {
-                pBuffer = MyMalloc(required);
-                ret = SetupGetStringFieldW(&ContextInclude, Index, pBuffer, required, &required);
-            }
-            if (ret)
-            {
-                ret = InstallServicesSection(hInf, pBuffer ? pBuffer : szBuffer,
-                    DeviceInfoSet, DeviceInfoData, pAssociatedService, pRebootRequired);
-            }
-
-            MyFree(pBuffer);
-            if (!ret)
-                goto done;
-            Index++;
-        }
-    }
-
-    ret = SetupFindFirstLineW(hInf, SectionName, NULL, &ContextService);
-    while (ret)
-    {
-        LPWSTR ServiceName = NULL;
-        LPWSTR ServiceSection = NULL;
-
-        ret = SetupGetStringFieldW(
-            &ContextService,
-            1, /* Field index */
-            NULL, 0,
-            &RequiredSize);
-        if (!ret)
-            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;
-            }
-            ret = SetupGetStringFieldW(
-                &ContextService,
-                1, /* Field index */
-                ServiceName, RequiredSize,
-                &RequiredSize);
-            if (!ret)
-                goto nextservice;
-        }
-        ret = SetupGetIntField(
-            &ContextService,
-            2, /* Field index */
-            &Flags);
-        if (!ret)
-        {
-            /* The field may be empty. Ignore the error */
-            Flags = 0;
-        }
-        ret = SetupGetStringFieldW(
-            &ContextService,
-            3, /* Field index */
-            NULL, 0,
-            &RequiredSize);
-        if (!ret)
-        {
-            if (GetLastError() == ERROR_INVALID_PARAMETER)
-            {
-                /* This first is probably missing. It is not
-                 * required, so ignore the error */
-                RequiredSize = 0;
-                ret = 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;
-            }
-            ret = SetupGetStringFieldW(
-                &ContextService,
-                3, /* Field index */
-                ServiceSection, RequiredSize,
-                &RequiredSize);
-            if (!ret)
-                goto nextservice;
-
-            SetLastError(ERROR_SUCCESS);
-            ret = SetupInstallServicesFromInfSectionExW(
-                hInf,
-                ServiceSection, Flags, DeviceInfoSet, DeviceInfoData, ServiceName, NULL);
-        }
-        if (ret && (Flags & SPSVCINST_ASSOCSERVICE))
-        {
-            if (pAssociatedService)
-            {
-                *pAssociatedService = ServiceName;
-                ServiceName = NULL;
-            }
-            if (pRebootRequired && GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED)
-                *pRebootRequired = TRUE;
-        }
-nextservice:
-        HeapFree(GetProcessHeap(), 0, ServiceName);
-        HeapFree(GetProcessHeap(), 0, ServiceSection);
-        if (!ret)
-            goto done;
-        ret = SetupFindNextLine(&ContextService, &ContextService);
-    }
-
-    ret = TRUE;
-
-done:
-    return ret;
-}
-
 /***********************************************************************
  *             SetupDiInstallClassExW (SETUPAPI.@)
  */
@@ -3451,7 +3297,7 @@ BOOL WINAPI SetupDiInstallClassExW(
 
             /* Install .Services section */
             lstrcatW(SectionName, DotServices);
-            ret = InstallServicesSection(hInf, SectionName, NULL, NULL, NULL, NULL);
+            ret = SetupInstallServicesFromInfSectionW(hInf, SectionName, 0);
             if (!ret)
                 goto cleanup;
 
@@ -3707,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;
@@ -5311,13 +5157,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;
@@ -5580,8 +5431,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))
@@ -5590,7 +5439,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;
@@ -6313,10 +6162,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;
         }
@@ -6472,7 +6323,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;
@@ -7113,8 +6964,8 @@ SetupDiChangeState(
         }
         default:
         {
-            FIXME("Unknown StateChange 0x%lx\n", PropChange->StateChange);
-            SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+            ERR("Unknown StateChange 0x%lx\n", PropChange->StateChange);
+            SetLastError(ERROR_NOT_SUPPORTED);
         }
     }
 
@@ -7192,6 +7043,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);
@@ -7208,21 +7062,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:
@@ -7261,6 +7143,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);
@@ -7279,9 +7162,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
@@ -7299,17 +7182,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;
@@ -7317,6 +7197,8 @@ SetupDiRegisterCoDeviceInstallers(
         ret = TRUE;
 
 cleanup:
+        if (Context)
+            SetupTermDefaultQueueCallback(Context);
         if (hKey != INVALID_HANDLE_VALUE)
             RegCloseKey(hKey);
     }
@@ -7325,6 +7207,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.@)
  */
@@ -7333,12 +7233,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
@@ -7397,7 +7407,6 @@ SetupDiInstallDevice(
     BOOL Result = FALSE;
     ULONG DoAction;
     DWORD RequiredSize;
-    LPCWSTR AssociatedService = NULL;
     LPWSTR pSectionName = NULL;
     WCHAR ClassName[MAX_CLASS_NAME_LEN];
     GUID ClassGuid;
@@ -7408,6 +7417,7 @@ SetupDiInstallDevice(
     BOOL NeedtoCopyFile;
     LARGE_INTEGER fullVersion;
     LONG rc;
+    PVOID Context = NULL;
     BOOL ret = FALSE; /* Return value */
 
     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
@@ -7487,33 +7497,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);
 
@@ -7534,22 +7535,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);
@@ -7562,15 +7563,18 @@ SetupDiInstallDevice(
 
     /* Install .Services section */
     wcscpy(pSectionName, DotServices);
-    Result = InstallServicesSection(
+    Result = SetupInstallServicesFromInfSectionExW(
         SelectedDriver->InfFileDetails->hInf,
         SectionName,
+        0,
         DeviceInfoSet,
         DeviceInfoData,
-        &AssociatedService,
-        &RebootRequired);
+        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);
@@ -7598,11 +7602,14 @@ SetupDiInstallDevice(
         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;
@@ -7613,7 +7620,6 @@ SetupDiInstallDevice(
     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, REGSTR_VAL_CLASS, 0, REG_SZ, (const BYTE *)ClassName, (wcslen(ClassName) + 1) * sizeof(WCHAR));
     if (rc == ERROR_SUCCESS)
         rc = RegSetValueEx(hKey, REGSTR_VAL_CLASSGUID, 0, REG_SZ, (const BYTE *)lpFullGuidString, (wcslen(lpFullGuidString) + 1) * sizeof(WCHAR));
@@ -7621,8 +7627,6 @@ SetupDiInstallDevice(
         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, REGSTR_VAL_MFG, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.MfgName, (wcslen(SelectedDriver->Info.MfgName) + 1) * sizeof(WCHAR));
-    if (rc == ERROR_SUCCESS && AssociatedService && *AssociatedService)
-        rc = RegSetValueEx(hKey, REGSTR_VAL_SERVICE, 0, REG_SZ, (const BYTE *)AssociatedService, (wcslen(AssociatedService) + 1) * sizeof(WCHAR));
     if (rc != ERROR_SUCCESS)
     {
        SetLastError(rc);
@@ -7643,9 +7647,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;
 }