implemented SetupDiSetSelectedDriverA
[reactos.git] / reactos / lib / setupapi / devinst.c
index d8c2076..880a5ad 100644 (file)
@@ -116,22 +116,33 @@ struct DeviceInterface /* Element of DeviceInfoElement.InterfaceListHead */
     WCHAR SymbolicLink[0]; /* \\?\ACPI#PNP0501#4&2658d0a0&0#{GUID} */
 };
 
+/* We don't want to open the .inf file to read only one information in it, so keep a handle to it once it
+ * has been already loaded once. Keep also a reference counter */
+struct InfFileDetails
+{
+    HINF hInf;
+    LONG References;
+};
+
 struct DriverInfoElement /* Element of DeviceInfoSet.DriverListHead and DeviceInfoElement.DriverListHead */
 {
     LIST_ENTRY ListEntry;
 
     DWORD DriverRank;
     SP_DRVINFO_DATA_V2_W Info;
+    SP_DRVINFO_DETAIL_DATA_W Details;
     GUID ClassGuid;
-    LPWSTR InfPath;
-    LPWSTR InfSection;
     LPWSTR MatchingId;
+    struct InfFileDetails *InfFileDetails;
 };
 
 struct DeviceInfoElement /* Element of DeviceInfoSet.ListHead */
 {
     LIST_ENTRY ListEntry;
 
+    /* Reserved Field points to a struct DriverInfoElement */
+    SP_DEVINSTALL_PARAMS_W InstallParams;
+
     /* Information about devnode:
      * - DeviceName:
      *       "Root\*PNP0501" for example.
@@ -155,31 +166,16 @@ struct DeviceInfoElement /* Element of DeviceInfoSet.ListHead */
      *              the unique ID needs to be generated
      *       - DICD_INHERIT_CLASSDRVS
      *              inherit driver of the device info set (== same pointer)
-     * - hwndParent
-     *       Used when doing device-specific actions. Can be NULL
      */
     PCWSTR DeviceName;
     PCWSTR UniqueId;
     PCWSTR DeviceDescription;
     GUID ClassGuid;
     DWORD CreationFlags;
-    HWND hwndParent;
-
-    /* Flags is a combination of:
-     * - DI_DIDCOMPAT
-     *       Set when the device driver list is created
-     * FlagsEx is a combination of:
-     * - DI_FLAGSEX_DIDCOMPATINFO (FIXME: not supported)
-     */
-    DWORD Flags;
-    DWORD FlagsEx;
 
     /* If CreationFlags contains DICD_INHERIT_CLASSDRVS, this list is invalid */
     /* If the driver is not searched/detected, this list is empty */
     LIST_ENTRY DriverListHead; /* List of struct DriverInfoElement */
-    /* Points into DriverListHead list. The pointer is NULL if no driver is
-     * currently chosen. */
-    struct DriverInfoElement *SelectedDriver;
 
     /* List of interfaces implemented by this device */
     LIST_ENTRY InterfaceListHead; /* List of struct DeviceInterface */
@@ -191,26 +187,13 @@ struct DeviceInfoSet /* HDEVINFO */
 {
     DWORD magic; /* SETUP_DEV_INFO_SET_MAGIC */
     GUID ClassGuid; /* If != GUID_NULL, only devices of this class can be in the device info set */
-    HWND hwndParent; /* only used on non-device-specific actions, like as a select-device dialog using the global class driver list */
     HKEY HKLM; /* Local or distant HKEY_LOCAL_MACHINE registry key */
 
-    /* Flags is a combination of:
-     * - DI_DIDCLASS
-     *       Set when the class driver list is created
-     * - DI_MULTMFGS (FIXME: not supported)
-     * - DI_COMPAT_FROM_CLASS (FIXME: not supported)
-     *       Forces SetupDiBuildDriverInfoList to build a class drivers list
-     * FlagsEx is a combination of:
-     * - DI_FLAGSEX_DIDINFOLIST (FIXME: not supported)
-     */
-    DWORD Flags;
-    DWORD FlagsEx;
+    /* Reserved Field points to a struct DriverInfoElement */
+    SP_DEVINSTALL_PARAMS_W InstallParams;
 
     /* If the driver is not searched/detected, this list is empty */
     LIST_ENTRY DriverListHead; /* List of struct DriverInfoElement */
-    /* Points into DriverListHead list. The pointer is NULL if no driver is
-     * currently chosen. */
-    struct DriverInfoElement *SelectedDriver;
 
     LIST_ENTRY ListHead; /* List of struct DeviceInfoElement */
 };
@@ -760,13 +743,16 @@ SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
     return (HDEVINFO)INVALID_HANDLE_VALUE;
   }
+  memset(list, 0, sizeof(struct DeviceInfoSet));
 
   list->magic = SETUP_DEV_INFO_SET_MAGIC;
   memcpy(
     &list->ClassGuid,
     ClassGuid ? ClassGuid : &GUID_NULL,
     sizeof(list->ClassGuid));
-  list->hwndParent = hwndParent;
+  list->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
+  list->InstallParams.Flags |= DI_CLASSINSTALLPARAMS;
+  list->InstallParams.hwndParent = hwndParent;
   if (MachineName)
   {
     rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &list->HKLM);
@@ -781,8 +767,6 @@ SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
   {
     list->HKLM = HKEY_LOCAL_MACHINE;
   }
-  list->Flags = 0; /* FIXME */
-  list->FlagsEx = 0; /* FIXME */
   InitializeListHead(&list->DriverListHead);
   InitializeListHead(&list->ListHead);
   return (HDEVINFO)list;
@@ -1191,26 +1175,26 @@ CreateDeviceInfoElement(
     IN LPCGUID pClassGuid,
     OUT struct DeviceInfoElement **pDeviceInfo)
 {
+    DWORD size;
     struct DeviceInfoElement *deviceInfo;
 
     *pDeviceInfo = NULL;
 
-    deviceInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInfoElement) + (wcslen(InstancePath) + 1) * sizeof(WCHAR));
+    size = sizeof(struct DeviceInfoElement) + (wcslen(InstancePath) + 1) * sizeof(WCHAR);
+    deviceInfo = HeapAlloc(GetProcessHeap(), 0, size);
     if (!deviceInfo)
     {
         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
         return FALSE;
     }
+    memset(deviceInfo, 0, size);
+    deviceInfo->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
     wcscpy(deviceInfo->Data, InstancePath);
     deviceInfo->DeviceName = deviceInfo->Data;
     deviceInfo->UniqueId = wcsrchr(deviceInfo->Data, '\\');
     deviceInfo->DeviceDescription = NULL;
     memcpy(&deviceInfo->ClassGuid, pClassGuid, sizeof(GUID));
     deviceInfo->CreationFlags = 0;
-    deviceInfo->hwndParent = NULL;
-    deviceInfo->Flags = 0; /* FIXME */
-    deviceInfo->FlagsEx = 0; /* FIXME */
-    deviceInfo->SelectedDriver = NULL;
     InitializeListHead(&deviceInfo->DriverListHead);
     InitializeListHead(&deviceInfo->InterfaceListHead);
 
@@ -1959,6 +1943,67 @@ BOOL WINAPI SetupDiEnumDeviceInterfaces(
     return ret;
 }
 
+static VOID ReferenceInfFile(struct InfFileDetails* infFile)
+{
+    InterlockedIncrement(&infFile->References);
+}
+
+static VOID DereferenceInfFile(struct InfFileDetails* infFile)
+{
+    if (InterlockedDecrement(&infFile->References) == 0)
+    {
+        SetupCloseInfFile(infFile->hInf);
+        HeapFree(GetProcessHeap(), 0, infFile);
+    }
+}
+
+static BOOL DestroyDriverInfoElement(struct DriverInfoElement* driverInfo)
+{
+    DereferenceInfFile(driverInfo->InfFileDetails);
+    HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId);
+    HeapFree(GetProcessHeap(), 0, driverInfo);
+    return TRUE;
+}
+
+static BOOL DestroyDeviceInfoElement(struct DeviceInfoElement* deviceInfo)
+{
+    PLIST_ENTRY ListEntry;
+    struct DriverInfoElement *driverInfo;
+
+    while (!IsListEmpty(&deviceInfo->DriverListHead))
+    {
+        ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
+        driverInfo = (struct DriverInfoElement *)ListEntry;
+        if (!DestroyDriverInfoElement(driverInfo))
+            return FALSE;
+    }
+    while (!IsListEmpty(&deviceInfo->InterfaceListHead))
+    {
+        ListEntry = RemoveHeadList(&deviceInfo->InterfaceListHead);
+        HeapFree(GetProcessHeap(), 0, ListEntry);
+    }
+    HeapFree(GetProcessHeap(), 0, deviceInfo);
+    return TRUE;
+}
+
+static BOOL DestroyDeviceInfoSet(struct DeviceInfoSet* list)
+{
+    PLIST_ENTRY ListEntry;
+    struct DeviceInfoElement *deviceInfo;
+
+    while (!IsListEmpty(&list->ListHead))
+    {
+        ListEntry = RemoveHeadList(&list->ListHead);
+        deviceInfo = (struct DeviceInfoElement *)ListEntry;
+        if (!DestroyDeviceInfoElement(deviceInfo))
+            return FALSE;
+    }
+    if (list->HKLM != HKEY_LOCAL_MACHINE)
+        RegCloseKey(list->HKLM);
+    HeapFree(GetProcessHeap(), 0, list);
+    return TRUE;
+}
+
 /***********************************************************************
  *             SetupDiDestroyDeviceInfoList (SETUPAPI.@)
  */
@@ -1972,25 +2017,7 @@ BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
         struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
 
         if (list->magic == SETUP_DEV_INFO_SET_MAGIC)
-        {
-            PLIST_ENTRY ListEntry, InterfaceEntry;
-            struct DeviceInfoElement *deviceInfo;
-            while (!IsListEmpty(&list->ListHead))
-            {
-                ListEntry = RemoveHeadList(&list->ListHead);
-                deviceInfo = (struct DeviceInfoElement *)ListEntry;
-                while (!IsListEmpty(&deviceInfo->InterfaceListHead))
-                {
-                    InterfaceEntry = RemoveHeadList(&deviceInfo->InterfaceListHead);
-                    HeapFree(GetProcessHeap(), 0, InterfaceEntry);
-                }
-                HeapFree(GetProcessHeap(), 0, ListEntry);
-            }
-            if (list->HKLM != HKEY_LOCAL_MACHINE)
-                RegCloseKey(list->HKLM);
-            HeapFree(GetProcessHeap(), 0, list);
-            ret = TRUE;
-        }
+            ret = DestroyDeviceInfoSet(list);
         else
             SetLastError(ERROR_INVALID_HANDLE);
     }
@@ -2177,7 +2204,7 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(
         PropertyBufferSizeW,
         &RequiredSizeW);
 
-    if (bResult || GetLastError() == ERROR_MORE_DATA)
+    if (bResult || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
     {
         bIsStringProperty = (RegType == REG_SZ || RegType == REG_MULTI_SZ || RegType == REG_EXPAND_SZ);
 
@@ -2272,6 +2299,7 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
             case SPDRP_SECURITY:
             case SPDRP_SERVICE:
             case SPDRP_UI_NUMBER:
+            case SPDRP_UI_NUMBER_DESC_FORMAT:
             case SPDRP_UPPERFILTERS:
             {
                 LPCWSTR RegistryPropertyName;
@@ -2309,6 +2337,8 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
                         RegistryPropertyName = L"Service"; break;
                     case SPDRP_UI_NUMBER:
                         RegistryPropertyName = L"UINumber"; break;
+                    case SPDRP_UI_NUMBER_DESC_FORMAT:
+                        RegistryPropertyName = L"UINumberDescFormat"; break;
                     case SPDRP_UPPERFILTERS:
                         RegistryPropertyName = L"UpperFilters"; break;
                     default:
@@ -2351,10 +2381,19 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
                     &BufferSize);
                 if (RequiredSize)
                     *RequiredSize = BufferSize;
-                if (rc == ERROR_SUCCESS)
-                    ret = TRUE;
-                else
-                    SetLastError(rc);
+                switch(rc) {
+                    case ERROR_SUCCESS:
+                        if (PropertyBuffer != NULL || BufferSize == 0)
+                            ret = TRUE;
+                        else
+                            SetLastError(ERROR_INSUFFICIENT_BUFFER);
+                        break;
+                    case ERROR_MORE_DATA:
+                        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+                        break;
+                    default:
+                        SetLastError(rc);
+                }
                 RegCloseKey(hKey);
                 break;
             }
@@ -2386,7 +2425,6 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
             case SPDRP_EXCLUSIVE:
             case SPDRP_CHARACTERISTICS:
             case SPDRP_ADDRESS:
-            case SPDRP_UI_NUMBER_DESC_FORMAT:
             case SPDRP_DEVICE_POWER_DATA:*/
 #if (WINVER >= 0x501)
             /*case SPDRP_REMOVAL_POLICY:
@@ -2407,6 +2445,154 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
     return ret;
 }
 
+/***********************************************************************
+ *             SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
+ */
+BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(
+        IN HDEVINFO DeviceInfoSet,
+        IN OUT PSP_DEVINFO_DATA DeviceInfoData,
+        IN DWORD Property,
+        IN CONST BYTE *PropertyBuffer,
+        IN DWORD PropertyBufferSize)
+{
+    FIXME("%p %p 0x%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
+        Property, PropertyBuffer, PropertyBufferSize);
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return FALSE;
+}
+
+/***********************************************************************
+ *             SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
+        IN HDEVINFO DeviceInfoSet,
+        IN OUT PSP_DEVINFO_DATA DeviceInfoData,
+        IN DWORD Property,
+        IN const BYTE *PropertyBuffer,
+        IN DWORD PropertyBufferSize)
+{
+    struct DeviceInfoSet *list;
+    BOOL ret = FALSE;
+
+    TRACE("%p %p 0x%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
+        Property, PropertyBuffer, PropertyBufferSize);
+
+    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_HANDLE);
+    else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else
+    {
+        switch (Property)
+        {
+            case SPDRP_COMPATIBLEIDS:
+            case SPDRP_CONFIGFLAGS:
+            case SPDRP_FRIENDLYNAME:
+            case SPDRP_HARDWAREID:
+            case SPDRP_LOCATION_INFORMATION:
+            case SPDRP_LOWERFILTERS:
+            case SPDRP_SECURITY:
+            case SPDRP_SERVICE:
+            case SPDRP_UI_NUMBER_DESC_FORMAT:
+            case SPDRP_UPPERFILTERS:
+            {
+                LPCWSTR RegistryPropertyName;
+                DWORD RegistryDataType;
+                HKEY hKey;
+                LONG rc;
+
+                switch (Property)
+                {
+                    case SPDRP_COMPATIBLEIDS:
+                        RegistryPropertyName = L"CompatibleIDs";
+                        RegistryDataType = REG_MULTI_SZ;
+                        break;
+                    case SPDRP_CONFIGFLAGS:
+                        RegistryPropertyName = L"ConfigFlags";
+                        RegistryDataType = REG_DWORD;
+                        break;
+                    case SPDRP_FRIENDLYNAME:
+                        RegistryPropertyName = L"FriendlyName";
+                        RegistryDataType = REG_SZ;
+                        break;
+                    case SPDRP_HARDWAREID:
+                        RegistryPropertyName = L"HardwareID";
+                        RegistryDataType = REG_MULTI_SZ;
+                        break;
+                    case SPDRP_LOCATION_INFORMATION:
+                        RegistryPropertyName = L"LocationInformation";
+                        RegistryDataType = REG_SZ;
+                        break;
+                    case SPDRP_LOWERFILTERS:
+                        RegistryPropertyName = L"LowerFilters";
+                        RegistryDataType = REG_MULTI_SZ;
+                        break;
+                    case SPDRP_SECURITY:
+                        RegistryPropertyName = L"Security";
+                        RegistryDataType = REG_BINARY;
+                        break;
+                    case SPDRP_SERVICE:
+                        RegistryPropertyName = L"Service";
+                        RegistryDataType = REG_SZ;
+                        break;
+                    case SPDRP_UI_NUMBER_DESC_FORMAT:
+                        RegistryPropertyName = L"UINumberDescFormat";
+                        RegistryDataType = REG_SZ;
+                        break;
+                    case SPDRP_UPPERFILTERS:
+                        RegistryPropertyName = L"UpperFilters";
+                        RegistryDataType = REG_MULTI_SZ;
+                        break;
+                    default:
+                        /* Should not happen */
+                        RegistryPropertyName = NULL;
+                        RegistryDataType = REG_BINARY;
+                        break;
+                }
+                /* Open device registry key */
+                hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE);
+                if (hKey != INVALID_HANDLE_VALUE)
+                {
+                    /* Write new data */
+                    rc = RegSetValueExW(
+                        hKey,
+                        RegistryPropertyName,
+                        0, /* Reserved */
+                        RegistryDataType,
+                        PropertyBuffer,
+                        PropertyBufferSize);
+                    if (rc == ERROR_SUCCESS)
+                        ret = TRUE;
+                    else
+                        SetLastError(rc);
+                    RegCloseKey(hKey);
+                }
+                break;
+            }
+
+            /*case SPDRP_CHARACTERISTICS:
+            case SPDRP_DEVTYPE:
+            case SPDRP_EXCLUSIVE:*/
+#if (WINVER >= 0x501)
+            //case SPDRP_REMOVAL_POLICY_OVERRIDE:
+#endif
+            //case SPDRP_SECURITY_SDS:
+
+            default:
+            {
+                FIXME("Property 0x%lx not implemented\n", Property);
+                SetLastError(ERROR_NOT_SUPPORTED);
+            }
+        }
+    }
+
+    TRACE("Returning %d\n", ret);
+    return ret;
+}
 
 /***********************************************************************
  *             SetupDiInstallClassA (SETUPAPI.@)
@@ -2814,14 +3000,6 @@ GetFunctionPointer(
         goto cleanup;
     }
 
-    /* W->A conversion for function name */
-    FunctionNameA = UnicodeToMultiByte(Comma + 1, CP_ACP);
-    if (!FunctionNameA)
-    {
-        rc = GetLastError();
-        goto cleanup;
-    }
-
     /* Load library */
     *Comma = '\0';
     hModule = LoadLibraryW(InstallerName);
@@ -2832,6 +3010,18 @@ GetFunctionPointer(
         goto cleanup;
     }
 
+    /* Skip comma spaces */
+    while (*Comma == ',' || isspaceW(*Comma))
+        Comma++;
+
+    /* W->A conversion for function name */
+    FunctionNameA = UnicodeToMultiByte(Comma, CP_ACP);
+    if (!FunctionNameA)
+    {
+        rc = GetLastError();
+        goto cleanup;
+    }
+
     /* Search function */
     *FunctionPointer = GetProcAddress(hModule, FunctionNameA);
     if (!*FunctionPointer)
@@ -2887,6 +3077,7 @@ BOOL WINAPI SetupDiCallClassInstaller(
         SetLastError(ERROR_INVALID_USER_BUFFER);
     else
     {
+        SP_DEVINSTALL_PARAMS_W InstallParams;
 #define CLASS_COINSTALLER  0x1
 #define DEVICE_COINSTALLER 0x2
 #define CLASS_INSTALLER    0x4
@@ -2935,6 +3126,11 @@ BOOL WINAPI SetupDiCallClassInstaller(
                 SetLastError(ERROR_INVALID_PARAMETER);
         }
 
+        InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
+        if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
+            /* Don't process this call, as a parameter is invalid */
+            CanHandle = 0;
+
         if (CanHandle != 0)
         {
             LIST_ENTRY ClassCoInstallersListHead;
@@ -2952,7 +3148,39 @@ BOOL WINAPI SetupDiCallClassInstaller(
 
             if (CanHandle & DEVICE_COINSTALLER)
             {
-                FIXME("Doesn't use Device co-installers at the moment\n");
+                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);
+                    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);
+                            if (rc == ERROR_SUCCESS)
+                            {
+                                LPWSTR ptr;
+                                for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
+                                {
+                                    /* Add coinstaller to DeviceCoInstallersListHead list */
+                                    struct CoInstallerElement *coinstaller;
+                                    TRACE("Got device coinstaller '%s'\n", debugstr_w(ptr));
+                                    coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
+                                    if (!coinstaller)
+                                        continue;
+                                    memset(coinstaller, 0, sizeof(struct CoInstallerElement));
+                                    if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
+                                        InsertTailList(&DeviceCoInstallersListHead, &coinstaller->ListEntry);
+                                    else
+                                        HeapFree(GetProcessHeap(), 0, coinstaller);
+                                }
+                            }
+                            HeapFree(GetProcessHeap(), 0, KeyBuffer);
+                        }
+                    }
+                    RegCloseKey(hKey);
+                }
             }
             if (CanHandle & CLASS_COINSTALLER)
             {
@@ -2968,7 +3196,7 @@ BOOL WINAPI SetupDiCallClassInstaller(
                     if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) == RPC_S_OK)
                     {
                         rc = RegQueryValueExW(hKey, lpGuidString, NULL, &dwRegType, NULL, &dwLength);
-                        if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
+                        if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
                         {
                             LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
                             if (KeyBuffer != NULL)
@@ -2976,11 +3204,20 @@ BOOL WINAPI SetupDiCallClassInstaller(
                                 rc = RegQueryValueExW(hKey, lpGuidString, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
                                 if (rc == ERROR_SUCCESS)
                                 {
-                                    LPCWSTR ptr;
+                                    LPWSTR ptr;
                                     for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
                                     {
                                         /* Add coinstaller to ClassCoInstallersListHead list */
-                                        FIXME("Class coinstaller is '%S'. UNIMPLEMENTED!\n", ptr);
+                                        struct CoInstallerElement *coinstaller;
+                                        TRACE("Got class coinstaller '%s'\n", debugstr_w(ptr));
+                                        coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
+                                        if (!coinstaller)
+                                            continue;
+                                        memset(coinstaller, 0, sizeof(struct CoInstallerElement));
+                                        if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
+                                            InsertTailList(&ClassCoInstallersListHead, &coinstaller->ListEntry);
+                                        else
+                                            HeapFree(GetProcessHeap(), 0, coinstaller);
                                     }
                                 }
                                 HeapFree(GetProcessHeap(), 0, KeyBuffer);
@@ -2991,7 +3228,7 @@ BOOL WINAPI SetupDiCallClassInstaller(
                     RegCloseKey(hKey);
                 }
             }
-            if (CanHandle & CLASS_INSTALLER)
+            if ((CanHandle & CLASS_INSTALLER) && !(InstallParams.FlagsEx & DI_FLAGSEX_CI_FAILED))
             {
                 hKey = SetupDiOpenClassRegKey(&DeviceInfoData->ClassGuid, KEY_QUERY_VALUE);
                 if (hKey != INVALID_HANDLE_VALUE)
@@ -3006,7 +3243,12 @@ BOOL WINAPI SetupDiCallClassInstaller(
                             if (rc == ERROR_SUCCESS)
                             {
                                 /* Get ClassInstaller function pointer */
-                                rc = GetFunctionPointer(KeyBuffer, &ClassInstallerLibrary, (PVOID*)&ClassInstaller);
+                                TRACE("Got class installer '%s'\n", debugstr_w(KeyBuffer));
+                                if (GetFunctionPointer(KeyBuffer, &ClassInstallerLibrary, (PVOID*)&ClassInstaller) != ERROR_SUCCESS)
+                                {
+                                    InstallParams.FlagsEx |= DI_FLAGSEX_CI_FAILED;
+                                    SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
+                                }
                             }
                             HeapFree(GetProcessHeap(), 0, KeyBuffer);
                         }
@@ -3059,7 +3301,7 @@ BOOL WINAPI SetupDiCallClassInstaller(
             /* Call default handler */
             if (rc == ERROR_DI_DO_DEFAULT)
             {
-                if (DefaultHandler /*FIXME && DI_NODI_DEFAULTACTION not set */)
+                if (DefaultHandler && !(InstallParams.Flags & DI_NODI_DEFAULTACTION))
                 {
                     if ((*DefaultHandler)(DeviceInfoSet, DeviceInfoData))
                         rc = NO_ERROR;
@@ -3171,8 +3413,76 @@ BOOL WINAPI SetupDiGetDeviceInstallParamsW(
        IN PSP_DEVINFO_DATA DeviceInfoData,
        OUT PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
 {
-    FIXME("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
-    return FALSE;
+    struct DeviceInfoSet *list;
+    BOOL ret = FALSE;
+
+    TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
+
+    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 && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else if (!DeviceInstallParams)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else
+    {
+        PSP_DEVINSTALL_PARAMS_W Source;
+
+        if (DeviceInfoData)
+            Source = &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->InstallParams;
+        else
+            Source = &list->InstallParams;
+        memcpy(DeviceInstallParams, Source, Source->cbSize);
+        ret = TRUE;
+    }
+
+    TRACE("Returning %d\n", ret);
+    return ret;
+}
+
+/***********************************************************************
+ *             SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupDiSetDeviceInstallParamsW(
+       IN HDEVINFO DeviceInfoSet,
+       IN PSP_DEVINFO_DATA DeviceInfoData,
+       IN PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
+{
+    struct DeviceInfoSet *list;
+    BOOL ret = FALSE;
+
+    TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
+
+    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 && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else if (!DeviceInstallParams)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else
+    {
+        PSP_DEVINSTALL_PARAMS_W Destination;
+
+        /* FIXME: Validate parameters */
+
+        if (DeviceInfoData)
+            Destination = &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->InstallParams;
+        else
+            Destination = &list->InstallParams;
+        memcpy(Destination, DeviceInstallParams, DeviceInstallParams->cbSize);
+        ret = TRUE;
+    }
+
+    TRACE("Returning %d\n", ret);
+    return ret;
 }
 
 /***********************************************************************
@@ -3267,7 +3577,11 @@ HKEY WINAPI SetupDiCreateDevRegKeyW(
                     0,
                     NULL,
                     REG_OPTION_NON_VOLATILE,
+#if _WIN32_WINNT >= 0x502
                     KEY_READ | KEY_WRITE,
+#else
+                    KEY_ALL_ACCESS,
+#endif
                     NULL,
                     &hKey,
                     &Disposition);
@@ -3611,6 +3925,7 @@ AddDriverToList(
     IN DWORD DriverType, /* SPDIT_CLASSDRIVER or SPDIT_COMPATDRIVER */
     IN LPGUID ClassGuid,
     IN INFCONTEXT ContextDevice,
+    IN struct InfFileDetails *InfFileDetails,
     IN LPCWSTR InfFile,
     IN LPCWSTR ProviderName,
     IN LPCWSTR ManufacturerName,
@@ -3620,10 +3935,10 @@ AddDriverToList(
     IN DWORD Rank)
 {
     struct DriverInfoElement *driverInfo = NULL;
+    HANDLE hFile = INVALID_HANDLE_VALUE;
     DWORD RequiredSize = 128; /* Initial buffer size */
     BOOL Result = FALSE;
     PLIST_ENTRY PreviousEntry;
-    LPWSTR DeviceDescription = NULL;
     LPWSTR InfInstallSection = NULL;
     BOOL ret = FALSE;
 
@@ -3635,34 +3950,38 @@ AddDriverToList(
     }
     memset(driverInfo, 0, sizeof(struct DriverInfoElement));
 
-    /* Fill InfSection field */
-    SetLastError(ERROR_INSUFFICIENT_BUFFER);
-    while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
-    {
-        HeapFree(GetProcessHeap(), 0, driverInfo->InfSection);
-        driverInfo->InfSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
-        if (!driverInfo->InfSection)
-        {
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            goto cleanup;
-        }
-        Result = SetupGetStringFieldW(
-            &ContextDevice,
-            1,
-            driverInfo->InfSection, RequiredSize,
-            &RequiredSize);
-    }
-    if (!Result)
-        goto cleanup;
+    driverInfo->Details.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
+    driverInfo->Details.Reserved = (ULONG_PTR)driverInfo;
 
-    /* Copy InfFile information */
-    driverInfo->InfPath = HeapAlloc(GetProcessHeap(), 0, (wcslen(InfFile) + 1) * sizeof(WCHAR));
-    if (!driverInfo->InfPath)
-    {
-        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+    /* Copy InfFileName field */
+    wcsncpy(driverInfo->Details.InfFileName, InfFile, MAX_PATH - 1);
+    driverInfo->Details.InfFileName[MAX_PATH - 1] = '\0';
+
+    /* Fill InfDate field */
+    /* FIXME: hFile = CreateFile(driverInfo->Details.InfFileName,
+        GENERIC_READ, FILE_SHARE_READ,
+        NULL, OPEN_EXISTING, 0, NULL);
+    if (hFile == INVALID_HANDLE_VALUE)
         goto cleanup;
-    }
-    RtlCopyMemory(driverInfo->InfPath, InfFile, (wcslen(InfFile) + 1) * sizeof(WCHAR));
+    Result = GetFileTime(hFile, NULL, NULL, &driverInfo->Details.InfDate);
+    if (!Result)
+        goto cleanup;*/
+
+    /* Fill SectionName field */
+    Result = SetupGetStringFieldW(
+        &ContextDevice,
+        1,
+        driverInfo->Details.SectionName, LINE_LEN,
+        NULL);
+    if (!Result)
+        goto cleanup;
+
+    /* Fill DrvDescription field */
+    Result = SetupGetStringFieldW(
+        &ContextDevice,
+        0, /* Field index */
+        driverInfo->Details.DrvDescription, LINE_LEN,
+        NULL);
 
     /* Copy MatchingId information */
     driverInfo->MatchingId = HeapAlloc(GetProcessHeap(), 0, (wcslen(MatchingId) + 1) * sizeof(WCHAR));
@@ -3673,25 +3992,6 @@ AddDriverToList(
     }
     RtlCopyMemory(driverInfo->MatchingId, MatchingId, (wcslen(MatchingId) + 1) * sizeof(WCHAR));
 
-    /* Get device description */
-    Result = FALSE;
-    RequiredSize = 128; /* Initial buffer size */
-    SetLastError(ERROR_INSUFFICIENT_BUFFER);
-    while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
-    {
-        HeapFree(GetProcessHeap(), 0, DeviceDescription);
-        DeviceDescription = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
-        if (!DeviceDescription)
-            goto cleanup;
-        Result = SetupGetStringFieldW(
-            &ContextDevice,
-            0, /* Field index */
-            DeviceDescription, RequiredSize,
-            &RequiredSize);
-    }
-    if (!Result)
-        goto cleanup;
-
     /* Get inf install section */
     Result = FALSE;
     RequiredSize = 128; /* Initial buffer size */
@@ -3712,13 +4012,13 @@ AddDriverToList(
         goto cleanup;
 
     TRACE("Adding driver '%S' [%S/%S] (Rank 0x%lx)\n",
-        DeviceDescription, InfFile, InfInstallSection, Rank);
+        driverInfo->Details.DrvDescription, InfFile, InfInstallSection, Rank);
 
     driverInfo->DriverRank = Rank;
     memcpy(&driverInfo->ClassGuid, ClassGuid, sizeof(GUID));
     driverInfo->Info.DriverType = DriverType;
     driverInfo->Info.Reserved = (ULONG_PTR)driverInfo;
-    wcsncpy(driverInfo->Info.Description, DeviceDescription, LINE_LEN - 1);
+    wcsncpy(driverInfo->Info.Description, driverInfo->Details.DrvDescription, LINE_LEN - 1);
     driverInfo->Info.Description[LINE_LEN - 1] = '\0';
     wcsncpy(driverInfo->Info.MfgName, ManufacturerName, LINE_LEN - 1);
     driverInfo->Info.MfgName[LINE_LEN - 1] = '\0';
@@ -3731,6 +4031,8 @@ AddDriverToList(
         driverInfo->Info.ProviderName[0] = '\0';
     driverInfo->Info.DriverDate = DriverDate;
     driverInfo->Info.DriverVersion = DriverVersion;
+    ReferenceInfFile(InfFileDetails);
+    driverInfo->InfFileDetails = InfFileDetails;
 
     /* Insert current driver in driver list, according to its rank */
     PreviousEntry = DriverListHead->Flink;
@@ -3755,14 +4057,11 @@ cleanup:
     if (!ret)
     {
         if (driverInfo)
-        {
-            HeapFree(GetProcessHeap(), 0, driverInfo->InfPath);
-            HeapFree(GetProcessHeap(), 0, driverInfo->InfSection);
             HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId);
-        }
         HeapFree(GetProcessHeap(), 0, driverInfo);
     }
-    HeapFree(GetProcessHeap(), 0, DeviceDescription);
+    if (hFile != INVALID_HANDLE_VALUE)
+        CloseHandle(hFile);
     HeapFree(GetProcessHeap(), 0, InfInstallSection);
 
     return ret;
@@ -3897,11 +4196,12 @@ SetupDiBuildDriverInfoList(
     IN DWORD DriverType)
 {
     struct DeviceInfoSet *list;
+    SP_DEVINSTALL_PARAMS_W InstallParams;
     PVOID Buffer = NULL;
-    HINF hInf = INVALID_HANDLE_VALUE;
+    struct InfFileDetails *currentInfFileDetails = NULL;
     LPWSTR ProviderName = NULL;
     LPWSTR ManufacturerName = NULL;
-    LPWSTR ManufacturerSection = NULL;
+    WCHAR ManufacturerSection[LINE_LEN + 1];
     LPWSTR HardwareIDs = NULL;
     LPWSTR CompatibleIDs = NULL;
     FILETIME DriverDate;
@@ -3927,7 +4227,12 @@ SetupDiBuildDriverInfoList(
         SetLastError(ERROR_INVALID_USER_BUFFER);
     else
     {
-        BOOL Result = FALSE;
+        BOOL Result;
+
+        InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+        Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
+        if (!Result)
+            goto done;
 
         if (DriverType == SPDIT_COMPATDRIVER)
         {
@@ -4004,11 +4309,19 @@ SetupDiBuildDriverInfoList(
                 break;
             }
             Result = SetupGetInfFileListW(
-                NULL, /* Directory path */
+                *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;
@@ -4019,19 +4332,30 @@ SetupDiBuildDriverInfoList(
                 GUID ClassGuid;
                 TRACE("Opening file %S\n", filename);
 
-                hInf = SetupOpenInfFileW(filename, NULL, INF_STYLE_WIN4, NULL);
-                if (hInf == INVALID_HANDLE_VALUE)
+                currentInfFileDetails = HeapAlloc(GetProcessHeap(), 0, sizeof(struct InfFileDetails));
+                if (!currentInfFileDetails)
+                    continue;
+                memset(currentInfFileDetails, 0, sizeof(struct InfFileDetails));
+
+                currentInfFileDetails->hInf = SetupOpenInfFileW(filename, NULL, INF_STYLE_WIN4, NULL);
+                ReferenceInfFile(currentInfFileDetails);
+                if (currentInfFileDetails->hInf == INVALID_HANDLE_VALUE)
+                {
+                    HeapFree(GetProcessHeap(), 0, currentInfFileDetails);
+                    currentInfFileDetails = NULL;
                     continue;
+                }
 
                 if (!GetVersionInformationFromInfFile(
-                    hInf,
+                    currentInfFileDetails->hInf,
                     &ClassGuid,
                     &ProviderName,
                     &DriverDate,
                     &DriverVersion))
                 {
-                    SetupCloseInfFile(hInf);
-                    hInf = INVALID_HANDLE_VALUE;
+                    SetupCloseInfFile(currentInfFileDetails->hInf);
+                    HeapFree(GetProcessHeap(), 0, currentInfFileDetails->hInf);
+                    currentInfFileDetails = NULL;
                     continue;
                 }
 
@@ -4045,7 +4369,7 @@ SetupDiBuildDriverInfoList(
                 }
 
                 /* Get the manufacturers list */
-                Result = SetupFindFirstLineW(hInf, L"Manufacturer", NULL, &ContextManufacturer);
+                Result = SetupFindFirstLineW(currentInfFileDetails->hInf, L"Manufacturer", NULL, &ContextManufacturer);
                 while (Result)
                 {
                     Result = SetupGetStringFieldW(
@@ -4068,29 +4392,24 @@ SetupDiBuildDriverInfoList(
                             ManufacturerName, RequiredSize,
                             &RequiredSize);
                     }
+                    /* Get manufacturer section name */
                     Result = SetupGetStringFieldW(
                         &ContextManufacturer,
                         1, /* Field index */
-                        NULL, 0,
+                        ManufacturerSection, LINE_LEN,
                         &RequiredSize);
                     if (Result)
                     {
-                        /* We got the needed size for the buffer */
-                        ManufacturerSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
-                        if (!ManufacturerSection)
+                        ManufacturerSection[RequiredSize] = 0; /* Final NULL char */
+                        /* Add (possible) extension to manufacturer section name */
+                        Result = SetupDiGetActualSectionToInstallW(
+                            currentInfFileDetails->hInf, ManufacturerSection, ManufacturerSection, LINE_LEN, NULL, NULL);
+                        if (Result)
                         {
-                            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-                            goto done;
+                            TRACE("Enumerating devices in manufacturer %S\n", ManufacturerSection);
+                            Result = SetupFindFirstLineW(currentInfFileDetails->hInf, ManufacturerSection, NULL, &ContextDevice);
                         }
-                        Result = SetupGetStringFieldW(
-                            &ContextManufacturer,
-                            1, /* Field index */
-                            ManufacturerSection, RequiredSize,
-                            &RequiredSize);
                     }
-
-                    TRACE("Enumerating devices in manufacturer %S\n", ManufacturerSection);
-                    Result = SetupFindFirstLineW(hInf, ManufacturerSection, NULL, &ContextDevice);
                     while (Result)
                     {
                         if (DriverType == SPDIT_CLASSDRIVER)
@@ -4101,6 +4420,7 @@ SetupDiBuildDriverInfoList(
                                 DriverType,
                                 &ClassGuid,
                                 ContextDevice,
+                                currentInfFileDetails,
                                 filename,
                                 ProviderName,
                                 ManufacturerName,
@@ -4156,6 +4476,7 @@ SetupDiBuildDriverInfoList(
                                             DriverType,
                                             &ClassGuid,
                                             ContextDevice,
+                                            currentInfFileDetails,
                                             filename,
                                             ProviderName,
                                             ManufacturerName,
@@ -4176,6 +4497,7 @@ SetupDiBuildDriverInfoList(
                                                 DriverType,
                                                 &ClassGuid,
                                                 ContextDevice,
+                                                currentInfFileDetails,
                                                 filename,
                                                 ProviderName,
                                                 ManufacturerName,
@@ -4193,8 +4515,7 @@ SetupDiBuildDriverInfoList(
                     }
 
                     HeapFree(GetProcessHeap(), 0, ManufacturerName);
-                    HeapFree(GetProcessHeap(), 0, ManufacturerSection);
-                    ManufacturerName = ManufacturerSection = NULL;
+                    ManufacturerName = NULL;
                     Result = SetupFindNextLine(&ContextManufacturer, &ContextManufacturer);
                 }
 
@@ -4203,8 +4524,8 @@ next:
                 HeapFree(GetProcessHeap(), 0, ProviderName);
                 ProviderName = NULL;
 
-                SetupCloseInfFile(hInf);
-                hInf = INVALID_HANDLE_VALUE;
+                DereferenceInfFile(currentInfFileDetails);
+                currentInfFileDetails = NULL;
             }
             ret = TRUE;
         }
@@ -4215,20 +4536,23 @@ done:
     {
         if (DeviceInfoData)
         {
-            struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
-            deviceInfo->Flags |= DI_DIDCOMPAT;
+            InstallParams.Flags |= DI_DIDCOMPAT;
+            InstallParams.FlagsEx |= DI_FLAGSEX_DIDCOMPATINFO;
         }
         else
-            list->Flags |= DI_DIDCLASS;
+        {
+            InstallParams.Flags |= DI_DIDCLASS;
+            InstallParams.FlagsEx |= DI_FLAGSEX_DIDINFOLIST;
+        }
+        ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
     }
 
     HeapFree(GetProcessHeap(), 0, ProviderName);
     HeapFree(GetProcessHeap(), 0, ManufacturerName);
-    HeapFree(GetProcessHeap(), 0, ManufacturerSection);
     HeapFree(GetProcessHeap(), 0, HardwareIDs);
     HeapFree(GetProcessHeap(), 0, CompatibleIDs);
-    if (hInf != INVALID_HANDLE_VALUE)
-        SetupCloseInfFile(hInf);
+    if (currentInfFileDetails)
+        DereferenceInfFile(currentInfFileDetails);
     HeapFree(GetProcessHeap(), 0, Buffer);
 
     TRACE("Returning %d\n", ret);
@@ -4277,25 +4601,17 @@ SetupDiDestroyDriverInfoList(
         SetLastError(ERROR_INVALID_USER_BUFFER);
     else
     {
-        struct DeviceInfoElement *deviceInfo = NULL;
         PLIST_ENTRY ListEntry;
         struct DriverInfoElement *driverInfo;
+        SP_DEVINSTALL_PARAMS_W InstallParams;
+
+        InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
+        if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
+            goto done;
 
         if (!DeviceInfoData)
+            /* Fall back to destroying class driver list */
             DriverType = SPDIT_CLASSDRIVER;
-        if (DriverType == SPDIT_CLASSDRIVER)
-        {
-            if (!(list->Flags & DI_DIDCLASS))
-                /* The list was not created */
-                goto done;
-        }
-        else if (DriverType == SPDIT_COMPATDRIVER)
-        {
-            deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
-            if (!(deviceInfo->Flags & DI_DIDCOMPAT))
-                /* The list was not created */
-                goto done;
-        }
 
         if (DriverType == SPDIT_CLASSDRIVER)
         {
@@ -4303,33 +4619,38 @@ SetupDiDestroyDriverInfoList(
             {
                  ListEntry = RemoveHeadList(&list->DriverListHead);
                  driverInfo = (struct DriverInfoElement *)ListEntry;
-                 HeapFree(GetProcessHeap(), 0, driverInfo->InfSection);
-                 HeapFree(GetProcessHeap(), 0, driverInfo->InfPath);
-                 HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId);
-                 HeapFree(GetProcessHeap(), 0, driverInfo);
+                 DestroyDriverInfoElement(driverInfo);
             }
-            list->Flags &= ~(DI_DIDCLASS | DI_MULTMFGS);
-            list->FlagsEx &= ~DI_FLAGSEX_DIDINFOLIST;
-            list->SelectedDriver = NULL;
+            InstallParams.Reserved = 0;
+            InstallParams.Flags &= ~(DI_DIDCLASS | DI_MULTMFGS);
+            InstallParams.FlagsEx &= ~DI_FLAGSEX_DIDINFOLIST;
+            ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParams);
         }
         else
         {
+            SP_DEVINSTALL_PARAMS_W InstallParamsSet;
+            struct DeviceInfoElement *deviceInfo;
+
+            InstallParamsSet.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
+            if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParamsSet))
+                goto done;
+            deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
             while (!IsListEmpty(&deviceInfo->DriverListHead))
             {
                  ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
                  driverInfo = (struct DriverInfoElement *)ListEntry;
-                 if (list->SelectedDriver == driverInfo)
-                     list->SelectedDriver = NULL;
-                 HeapFree(GetProcessHeap(), 0, driverInfo->InfSection);
-                 HeapFree(GetProcessHeap(), 0, driverInfo->InfPath);
-                 HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId);
-                 HeapFree(GetProcessHeap(), 0, driverInfo);
+                 if ((PVOID)InstallParamsSet.Reserved == driverInfo)
+                 {
+                     InstallParamsSet.Reserved = 0;
+                     SetupDiSetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParamsSet);
+                 }
+                 DestroyDriverInfoElement(driverInfo);
             }
-            deviceInfo->Flags &= ~DI_DIDCOMPAT;
-            deviceInfo->FlagsEx &= ~DI_FLAGSEX_DIDCOMPATINFO;
-            deviceInfo->SelectedDriver = NULL;
+            InstallParams.Reserved = 0;
+            InstallParams.Flags &= ~DI_DIDCOMPAT;
+            InstallParams.FlagsEx &= ~DI_FLAGSEX_DIDCOMPATINFO;
+            ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
         }
-        ret = TRUE;
     }
 
 done:
@@ -4629,22 +4950,23 @@ SetupDiGetSelectedDriverW(
         SetLastError(ERROR_INVALID_USER_BUFFER);
     else
     {
-        struct DriverInfoElement *driverInfo;
-        
-        if (DeviceInfoData)
-            driverInfo = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver;
-        else
-            driverInfo = ((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver;
+        SP_DEVINSTALL_PARAMS InstallParams;
 
-        if (driverInfo == NULL)
-            SetLastError(ERROR_NO_DRIVER_SELECTED);
-        else
+        InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+        if (SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
         {
-            memcpy(
-                &DriverInfoData->DriverType,
-                &driverInfo->Info.DriverType,
-                DriverInfoData->cbSize - FIELD_OFFSET(SP_DRVINFO_DATA_W, DriverType));
-            ret = TRUE;
+            struct DriverInfoElement *driverInfo;
+            driverInfo = (struct DriverInfoElement *)InstallParams.Reserved;
+            if (driverInfo == NULL)
+                SetLastError(ERROR_NO_DRIVER_SELECTED);
+            else
+            {
+                memcpy(
+                    &DriverInfoData->DriverType,
+                    &driverInfo->Info.DriverType,
+                    DriverInfoData->cbSize - FIELD_OFFSET(SP_DRVINFO_DATA_W, DriverType));
+                ret = TRUE;
+            }
         }
     }
 
@@ -4652,6 +4974,70 @@ SetupDiGetSelectedDriverW(
     return ret;
 }
 
+
+/***********************************************************************
+ *             SetupDiSetSelectedDriverA (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiSetSelectedDriverA(
+    IN HDEVINFO DeviceInfoSet,
+    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
+    IN OUT PSP_DRVINFO_DATA_A DriverInfoData OPTIONAL)
+{
+    SP_DRVINFO_DATA_V1_W DriverInfoDataW;
+    PSP_DRVINFO_DATA_W pDriverInfoDataW = NULL;
+    BOOL ret = FALSE;
+
+    if (DriverInfoData != NULL)
+    {
+        if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_A) &&
+            DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_A));
+        {
+            SetLastError(ERROR_INVALID_PARAMETER);
+            return FALSE;
+        }
+
+        DriverInfoDataW.cbSize = sizeof(SP_DRVINFO_DATA_V1_W);
+        DriverInfoDataW.Reserved = DriverInfoData->Reserved;
+
+        if (DriverInfoDataW.Reserved == 0)
+        {
+            DriverInfoDataW.DriverType = DriverInfoData->DriverType;
+
+            /* convert the strings to unicode */
+            if (!MultiByteToWideChar(CP_ACP,
+                                     0,
+                                     DriverInfoData->Description,
+                                     LINE_LEN,
+                                     DriverInfoDataW.Description,
+                                     LINE_LEN) ||
+                !MultiByteToWideChar(CP_ACP,
+                                     0,
+                                     DriverInfoData->ProviderName,
+                                     LINE_LEN,
+                                     DriverInfoDataW.ProviderName,
+                                     LINE_LEN))
+            {
+                return FALSE;
+            }
+        }
+
+        pDriverInfoDataW = (PSP_DRVINFO_DATA_W)&DriverInfoDataW;
+    }
+
+    ret = SetupDiSetSelectedDriverW(DeviceInfoSet,
+                                    DeviceInfoData,
+                                    pDriverInfoDataW);
+
+    if (ret && pDriverInfoDataW != NULL)
+    {
+        DriverInfoData->Reserved = DriverInfoDataW.Reserved;
+    }
+
+    return ret;
+}
+
+
 /***********************************************************************
  *             SetupDiSetSelectedDriverW (SETUPAPI.@)
  */
@@ -4682,12 +5068,12 @@ SetupDiSetSelectedDriverW(
 
         if (DeviceInfoData)
         {
-            pDriverInfo = &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver;
+            pDriverInfo = (struct DriverInfoElement **)&((struct DeviceInfoElement *)DeviceInfoData->Reserved)->InstallParams.Reserved;
             ListHead = &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->DriverListHead;
         }
         else
         {
-            pDriverInfo = &((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver;
+            pDriverInfo = (struct DriverInfoElement **)&((struct DeviceInfoSet *)DeviceInfoSet)->InstallParams.Reserved;
             ListHead = &((struct DeviceInfoSet *)DeviceInfoSet)->DriverListHead;
         }
 
@@ -4738,6 +5124,258 @@ SetupDiSetSelectedDriverW(
     return ret;
 }
 
+/***********************************************************************
+ *             SetupDiGetDriverInfoDetailA (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiGetDriverInfoDetailA(
+    IN HDEVINFO DeviceInfoSet,
+    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
+    IN PSP_DRVINFO_DATA_A DriverInfoData,
+    OUT PSP_DRVINFO_DETAIL_DATA_A DriverInfoDetailData OPTIONAL,
+    IN DWORD DriverInfoDetailDataSize,
+    OUT PDWORD RequiredSize OPTIONAL)
+{
+    SP_DRVINFO_DATA_V2_W DriverInfoDataW;
+    PSP_DRVINFO_DETAIL_DATA_W DriverInfoDetailDataW = NULL;
+    DWORD BufSize = 0;
+    DWORD HardwareIDLen = 0;
+    BOOL ret = FALSE;
+    
+    /* do some sanity checks, the unicode version might do more thorough checks */
+    if (DriverInfoData == NULL ||
+        (DriverInfoDetailData == NULL && DriverInfoDetailDataSize != 0) ||
+        (DriverInfoDetailData != NULL &&
+         (DriverInfoDetailDataSize < FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID) + sizeof(CHAR) ||
+          DriverInfoDetailData->cbSize != sizeof(SP_DRVINFO_DETAIL_DATA_A))))
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        goto Cleanup;
+    }
+
+    /* make sure we support both versions of the SP_DRVINFO_DATA structure */
+    if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V1_A))
+    {
+        DriverInfoDataW.cbSize = sizeof(SP_DRVINFO_DATA_V1_W);
+    }
+    else if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V2_A))
+    {
+        DriverInfoDataW.cbSize = sizeof(SP_DRVINFO_DATA_V2_W);
+    }
+    else
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        goto Cleanup;
+    }
+    DriverInfoDataW.DriverType = DriverInfoData->DriverType;
+    DriverInfoDataW.Reserved = DriverInfoData->Reserved;
+    
+    /* convert the strings to unicode */
+    if (MultiByteToWideChar(CP_ACP,
+                            0,
+                            DriverInfoData->Description,
+                            LINE_LEN,
+                            DriverInfoDataW.Description,
+                            LINE_LEN) &&
+        MultiByteToWideChar(CP_ACP,
+                            0,
+                            DriverInfoData->MfgName,
+                            LINE_LEN,
+                            DriverInfoDataW.MfgName,
+                            LINE_LEN) &&
+        MultiByteToWideChar(CP_ACP,
+                            0,
+                            DriverInfoData->ProviderName,
+                            LINE_LEN,
+                            DriverInfoDataW.ProviderName,
+                            LINE_LEN))
+    {
+        if (DriverInfoDataW.cbSize == sizeof(SP_DRVINFO_DATA_V2_W))
+        {
+            DriverInfoDataW.DriverDate = ((PSP_DRVINFO_DATA_V2_A)DriverInfoData)->DriverDate;
+            DriverInfoDataW.DriverVersion = ((PSP_DRVINFO_DATA_V2_A)DriverInfoData)->DriverVersion;
+        }
+
+        if (DriverInfoDetailData != NULL)
+        {
+            /* calculate the unicode buffer size from the ansi buffer size */
+            HardwareIDLen = DriverInfoDetailDataSize - FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID);
+            BufSize = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID) +
+                      (HardwareIDLen * sizeof(WCHAR));
+
+            DriverInfoDetailDataW = MyMalloc(BufSize);
+            if (DriverInfoDetailDataW == NULL)
+            {
+                SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                goto Cleanup;
+            }
+
+            /* initialize the buffer */
+            ZeroMemory(DriverInfoDetailDataW,
+                       BufSize);
+            DriverInfoDetailDataW->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W);
+        }
+
+        /* call the unicode version */
+        ret = SetupDiGetDriverInfoDetailW(DeviceInfoSet,
+                                          DeviceInfoData,
+                                          &DriverInfoDataW,
+                                          DriverInfoDetailDataW,
+                                          BufSize,
+                                          RequiredSize);
+
+        if (ret)
+        {
+            if (DriverInfoDetailDataW != NULL)
+            {
+                /* convert the SP_DRVINFO_DETAIL_DATA_W structure to ansi */
+                DriverInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_A);
+                DriverInfoDetailData->InfDate = DriverInfoDetailDataW->InfDate;
+                DriverInfoDetailData->Reserved = DriverInfoDetailDataW->Reserved;
+                if (WideCharToMultiByte(CP_ACP,
+                                        0,
+                                        DriverInfoDetailDataW->SectionName,
+                                        LINE_LEN,
+                                        DriverInfoDetailData->SectionName,
+                                        LINE_LEN,
+                                        NULL,
+                                        NULL) &&
+                    WideCharToMultiByte(CP_ACP,
+                                        0,
+                                        DriverInfoDetailDataW->InfFileName,
+                                        MAX_PATH,
+                                        DriverInfoDetailData->InfFileName,
+                                        MAX_PATH,
+                                        NULL,
+                                        NULL) &&
+                    WideCharToMultiByte(CP_ACP,
+                                        0,
+                                        DriverInfoDetailDataW->DrvDescription,
+                                        LINE_LEN,
+                                        DriverInfoDetailData->DrvDescription,
+                                        LINE_LEN,
+                                        NULL,
+                                        NULL) &&
+                    WideCharToMultiByte(CP_ACP,
+                                        0,
+                                        DriverInfoDetailDataW->HardwareID,
+                                        HardwareIDLen,
+                                        DriverInfoDetailData->HardwareID,
+                                        HardwareIDLen,
+                                        NULL,
+                                        NULL))
+                {
+                    DWORD len, cnt = 0;
+                    DWORD hwidlen = HardwareIDLen;
+                    CHAR *s = DriverInfoDetailData->HardwareID;
+
+                    /* count the strings in the list */
+                    while (*s != '\0')
+                    {
+                        len = lstrlenA(s) + 1;
+                        if (hwidlen > len)
+                        {
+                            cnt++;
+                            s += len;
+                            hwidlen -= len;
+                        }
+                        else
+                        {
+                            /* looks like the string list wasn't terminated... */
+                            SetLastError(ERROR_INVALID_USER_BUFFER);
+                            ret = FALSE;
+                            break;
+                        }
+                    }
+
+                    /* make sure CompatIDsOffset points to the second string in the
+                       list, if present */
+                    if (cnt > 1)
+                    {
+                        DriverInfoDetailData->CompatIDsOffset = lstrlenA(DriverInfoDetailData->HardwareID) + 1;
+                        DriverInfoDetailData->CompatIDsLength = (DWORD)(s - DriverInfoDetailData->HardwareID) -
+                                                                DriverInfoDetailData->CompatIDsOffset + 1;
+                    }
+                    else
+                    {
+                        DriverInfoDetailData->CompatIDsOffset = 0;
+                        DriverInfoDetailData->CompatIDsLength = 0;
+                    }
+                }
+                else
+                {
+                    ret = FALSE;
+                }
+            }
+
+            if (RequiredSize != NULL)
+            {
+                *RequiredSize = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID) +
+                                (((*RequiredSize) - FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID)) / sizeof(WCHAR));
+            }
+        }
+    }
+    
+Cleanup:
+    if (DriverInfoDetailDataW != NULL)
+    {
+        MyFree(DriverInfoDetailDataW);
+    }
+
+    return ret;
+}
+
+/***********************************************************************
+ *             SetupDiGetDriverInfoDetailW (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiGetDriverInfoDetailW(
+    IN HDEVINFO DeviceInfoSet,
+    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
+    IN PSP_DRVINFO_DATA_W DriverInfoData,
+    OUT PSP_DRVINFO_DETAIL_DATA_W DriverInfoDetailData OPTIONAL,
+    IN DWORD DriverInfoDetailDataSize,
+    OUT PDWORD RequiredSize OPTIONAL)
+{
+    BOOL ret = FALSE;
+
+    if (!DeviceInfoSet)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
+        SetLastError(ERROR_INVALID_HANDLE);
+    else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
+        SetLastError(ERROR_INVALID_HANDLE);
+    else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else if (!DriverInfoData)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (!DriverInfoDetailData && DriverInfoDetailDataSize != 0)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (DriverInfoDetailData && DriverInfoDetailDataSize < sizeof(SP_DRVINFO_DETAIL_DATA_W))
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (DriverInfoDetailData && DriverInfoDetailData->cbSize != sizeof(SP_DRVINFO_DETAIL_DATA_W))
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else if (DriverInfoDetailData && DriverInfoDetailData->Reserved == 0)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else
+    {
+        struct DriverInfoElement *driverInfoElement;
+        driverInfoElement = (struct DriverInfoElement *)DriverInfoData->Reserved;
+
+        memcpy(
+            DriverInfoDetailData,
+            &driverInfoElement->Details,
+            driverInfoElement->Details.cbSize);
+        /* FIXME: copy HardwareIDs/CompatibleIDs if buffer is big enough
+         * Don't forget to set CompatIDsOffset and CompatIDsLength fields.
+         */
+        ret = TRUE;
+    }
+
+    TRACE("Returning %d\n", ret);
+    return ret;
+}
+
 /***********************************************************************
  *             SetupDiSelectBestCompatDrv (SETUPAPI.@)
  */
@@ -4794,48 +5432,50 @@ SetupDiInstallDriverFiles(
         SetLastError(ERROR_INVALID_HANDLE);
     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
         SetLastError(ERROR_INVALID_USER_BUFFER);
-    else if (DeviceInfoData && ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver == NULL)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else if (!DeviceInfoData && ((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver == NULL)
-        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (DeviceInfoData && ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->InstallParams.Reserved == 0)
+        SetLastError(ERROR_NO_DRIVER_SELECTED);
+    else if (!DeviceInfoData && ((struct DeviceInfoSet *)DeviceInfoSet)->InstallParams.Reserved == 0)
+        SetLastError(ERROR_NO_DRIVER_SELECTED);
     else
     {
-        struct DriverInfoElement *DriverInfo;
-        HWND hWnd;
-        HINF hInf;
-
-        if (DeviceInfoData)
+        SP_DEVINSTALL_PARAMS_W InstallParams;
+        struct DriverInfoElement *SelectedDriver;
+        WCHAR SectionName[MAX_PATH];
+        DWORD SectionNameLength = 0;
+
+        InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
+        ret = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
+        if (!ret)
+            goto done;
+
+        SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
+        if (!SelectedDriver)
         {
-            DriverInfo = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver;
-            hWnd = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->hwndParent;
-        }
-        else
-        {
-            DriverInfo = ((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver;
-            hWnd = ((struct DeviceInfoSet *)DeviceInfoSet)->hwndParent;
+            SetLastError(ERROR_NO_DRIVER_SELECTED);
+            goto done;
         }
 
-        hInf = SetupOpenInfFileW(DriverInfo->InfPath, NULL, INF_STYLE_WIN4, NULL);
-        if (hInf != INVALID_HANDLE_VALUE)
-        {
-            WCHAR SectionName[MAX_PATH];
-            DWORD SectionNameLength = 0;
+        ret = SetupDiGetActualSectionToInstallW(
+            SelectedDriver->InfFileDetails->hInf,
+            SelectedDriver->Details.SectionName,
+            SectionName, MAX_PATH, &SectionNameLength, NULL);
+        if (!ret)
+            goto done;
 
-            ret = SetupDiGetActualSectionToInstallW(hInf, DriverInfo->InfSection,
-                SectionName, MAX_PATH, &SectionNameLength, NULL);
-            if (ret)
-            {
-                PVOID callback_context = SetupInitDefaultQueueCallback(hWnd);
-                ret = SetupInstallFromInfSectionW(hWnd, hInf, SectionName,
-                    SPINST_FILES, NULL, NULL, SP_COPY_NEWER,
-                    SetupDefaultQueueCallbackW, callback_context,
-                    NULL, NULL);
-                SetupTermDefaultQueueCallback(callback_context);
-            }
-            SetupCloseInfFile(hInf);
+        if (!InstallParams.InstallMsgHandler)
+        {
+            InstallParams.InstallMsgHandler = SetupDefaultQueueCallbackW;
+            InstallParams.InstallMsgHandlerContext = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
+            SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
         }
+        ret = SetupInstallFromInfSectionW(InstallParams.hwndParent,
+            SelectedDriver->InfFileDetails->hInf, SectionName,
+            SPINST_FILES, NULL, NULL, SP_COPY_NEWER,
+            InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext,
+            DeviceInfoSet, DeviceInfoData);
     }
 
+done:
     TRACE("Returning %d\n", ret);
     return ret;
 }
@@ -4848,12 +5488,91 @@ SetupDiRegisterCoDeviceInstallers(
     IN HDEVINFO DeviceInfoSet,
     IN PSP_DEVINFO_DATA DeviceInfoData)
 {
+    BOOL ret = FALSE; /* Return value */
+
     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
 
-    FIXME("SetupDiRegisterCoDeviceInstallers 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 (((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
+    {
+        SP_DEVINSTALL_PARAMS_W InstallParams;
+        struct DriverInfoElement *SelectedDriver;
+        BOOL Result;
+        DWORD DoAction;
+        WCHAR SectionName[MAX_PATH];
+        DWORD SectionNameLength = 0;
+        HKEY hKey = INVALID_HANDLE_VALUE;;
+
+        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);
+            goto cleanup;
+        }
+
+        /* Get .CoInstallers section name */
+        Result = SetupDiGetActualSectionToInstallW(
+            SelectedDriver->InfFileDetails->hInf,
+            SelectedDriver->Details.SectionName,
+            SectionName, MAX_PATH, &SectionNameLength, NULL);
+        if (!Result || SectionNameLength > MAX_PATH - wcslen(L".CoInstallers") - 1)
+            goto cleanup;
+        wcscat(SectionName, L".CoInstallers");
+
+        /* Open/Create driver key information */
+#if _WIN32_WINNT >= 0x502
+        hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE);
+#else
+        hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
+#endif
+        if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
+            hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
+        if (hKey == INVALID_HANDLE_VALUE)
+            goto cleanup;
+
+        /* Install .CoInstallers section */
+        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);
+            }
+        }
+        Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
+            SelectedDriver->InfFileDetails->hInf, SectionName,
+            DoAction, hKey, NULL, SP_COPY_NEWER,
+            InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext,
+            DeviceInfoSet, DeviceInfoData);
+        if (!Result)
+            goto cleanup;
+
+        ret = TRUE;
+
+cleanup:
+        if (hKey != INVALID_HANDLE_VALUE)
+            RegCloseKey(hKey);
+    }
+
+    TRACE("Returning %d\n", ret);
+    return ret;
 }
 
 /***********************************************************************
@@ -4880,8 +5599,9 @@ SetupDiInstallDevice(
     IN HDEVINFO DeviceInfoSet,
     IN PSP_DEVINFO_DATA DeviceInfoData)
 {
-    struct DriverInfoElement *DriverInfo;
     struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
+    SP_DEVINSTALL_PARAMS_W InstallParams;
+    struct DriverInfoElement *SelectedDriver;
     SYSTEMTIME DriverDate;
     WCHAR SectionName[MAX_PATH];
     WCHAR Buffer[32];
@@ -4889,18 +5609,17 @@ SetupDiInstallDevice(
     BOOL Result = FALSE;
     INFCONTEXT ContextService;
     INT Flags;
+    ULONG DoAction;
     DWORD RequiredSize;
-    HINF hInf = INVALID_HANDLE_VALUE;
     LPCWSTR AssociatedService = NULL;
     LPWSTR pSectionName = NULL;
-    LPWSTR ClassName = NULL;
+    WCHAR ClassName[MAX_CLASS_NAME_LEN];
     GUID ClassGuid;
     LPWSTR lpGuidString = NULL, lpFullGuidString = NULL;
     BOOL RebootRequired = FALSE;
     HKEY hKey = INVALID_HANDLE_VALUE;
     HKEY hClassKey = INVALID_HANDLE_VALUE;
     LONG rc;
-    HWND hWnd;
     BOOL ret = FALSE; /* Return value */
 
     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
@@ -4913,10 +5632,6 @@ SetupDiInstallDevice(
         SetLastError(ERROR_INVALID_HANDLE);
     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
         SetLastError(ERROR_INVALID_USER_BUFFER);
-    else if (DeviceInfoData && ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver == NULL)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else if (!DeviceInfoData && ((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver == NULL)
-        SetLastError(ERROR_INVALID_PARAMETER);
     else
         Result = TRUE;
 
@@ -4926,46 +5641,37 @@ SetupDiInstallDevice(
         goto cleanup;
     }
 
-    /* FIXME: If DI_FLAGSEX_SETFAILEDINSTALL is set, set FAILEDINSTALL flag in ConfigFlags registry and exit */
+    InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
+    Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
+    if (!Result)
+        goto cleanup;
 
-    if (DeviceInfoData)
+    if (InstallParams.FlagsEx & DI_FLAGSEX_SETFAILEDINSTALL)
     {
-        DriverInfo = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver;
-        hWnd = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->hwndParent;
+        /* FIXME: set FAILEDINSTALL in ConfigFlags registry value */
+        goto cleanup;
     }
-    else
+
+    SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
+    if (SelectedDriver == NULL)
     {
-        DriverInfo = ((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver;
-        hWnd = ((struct DeviceInfoSet *)DeviceInfoSet)->hwndParent;
+        SetLastError(ERROR_NO_DRIVER_SELECTED);
+        goto cleanup;
     }
-    FileTimeToSystemTime(&DriverInfo->Info.DriverDate, &DriverDate);
 
-    hInf = SetupOpenInfFileW(DriverInfo->InfPath, NULL, INF_STYLE_WIN4, NULL);
-    if (hInf == INVALID_HANDLE_VALUE)
-        goto cleanup;
+    FileTimeToSystemTime(&SelectedDriver->Info.DriverDate, &DriverDate);
 
-    Result = SetupDiGetActualSectionToInstallW(hInf, DriverInfo->InfSection,
+    Result = SetupDiGetActualSectionToInstallW(
+        SelectedDriver->InfFileDetails->hInf,
+        SelectedDriver->Details.SectionName,
         SectionName, MAX_PATH, &SectionNameLength, NULL);
     if (!Result || SectionNameLength > MAX_PATH - 9)
         goto cleanup;
     pSectionName = &SectionName[wcslen(SectionName)];
 
     /* Get information from [Version] section */
-    ClassName = NULL;
-    RequiredSize = 0;
-    if (!SetupDiGetINFClassW(DriverInfo->InfPath, &ClassGuid, ClassName, RequiredSize, &RequiredSize))
-    {
-        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
-            goto cleanup;
-        ClassName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
-        if (!ClassName)
-        {
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            goto cleanup;
-        }
-        if (!SetupDiGetINFClassW(DriverInfo->InfPath, &ClassGuid, ClassName, RequiredSize, &RequiredSize))
-            goto cleanup;
-    }
+    if (!SetupDiGetINFClassW(SelectedDriver->Details.InfFileName, &ClassGuid, ClassName, MAX_CLASS_NAME_LEN, &RequiredSize))
+        goto cleanup;
     /* Format ClassGuid to a string */
     if (UuidToStringW((UUID*)&ClassGuid, &lpGuidString) != RPC_S_OK)
         goto cleanup;
@@ -4982,55 +5688,79 @@ SetupDiInstallDevice(
     lpFullGuidString[RequiredSize + 2] = '\0';
 
     /* Open/Create driver key information */
-    hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_SET_VALUE);
+#if _WIN32_WINNT >= 0x502
+    hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE);
+#else
+    hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
+#endif
     if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
         hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
     if (hKey == INVALID_HANDLE_VALUE)
         goto cleanup;
 
     /* Install main section */
-    /* Files have already been copied in SetupDiInstallDriverFiles.
-     * Process only registry entries. */
+    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);
+        }
+    }
     *pSectionName = '\0';
-    Result = SetupInstallFromInfSectionW(hWnd, hInf, SectionName,
-        SPINST_REGISTRY, hKey, NULL, 0,
-        SetupDefaultQueueCallbackW, NULL,
-        NULL, NULL);
+    Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
+        SelectedDriver->InfFileDetails->hInf, SectionName,
+        DoAction, hKey, NULL, SP_COPY_NEWER,
+        InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext,
+        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);
 
     /* Write information to driver key */
     *pSectionName = UNICODE_NULL;
     TRACE("Write information to driver key\n");
     TRACE("DriverDate      : '%u-%u-%u'\n", DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
-    TRACE("DriverDesc      : '%S'\n", DriverInfo->Info.Description);
-    TRACE("DriverVersion   : '%u.%u.%u.%u'\n", DriverInfo->Info.DriverVersion & 0xff, (DriverInfo->Info.DriverVersion >> 8) & 0xff, (DriverInfo->Info.DriverVersion >> 16) & 0xff, (DriverInfo->Info.DriverVersion >> 24) & 0xff);
-    TRACE("InfPath         : '%S'\n", DriverInfo->InfPath);
-    TRACE("InfSection      : '%S'\n", DriverInfo->InfSection);
-    TRACE("InfSectionExt   : '%S'\n", &SectionName[wcslen(DriverInfo->InfSection)]); /* FIXME */
-    TRACE("MatchingDeviceId: '%S'\n", DriverInfo->MatchingId);
-    TRACE("ProviderName    : '%S'\n", DriverInfo->Info.ProviderName);
+    TRACE("DriverDesc      : '%S'\n", SelectedDriver->Info.Description);
+    TRACE("DriverVersion   : '%u.%u.%u.%u'\n", SelectedDriver->Info.DriverVersion & 0xff, (SelectedDriver->Info.DriverVersion >> 8) & 0xff, (SelectedDriver->Info.DriverVersion >> 16) & 0xff, (SelectedDriver->Info.DriverVersion >> 24) & 0xff);
+    TRACE("InfPath         : '%S'\n", SelectedDriver->Details.InfFileName);
+    TRACE("InfSection      : '%S'\n", SelectedDriver->Details.SectionName);
+    TRACE("InfSectionExt   : '%S'\n", &SectionName[wcslen(SelectedDriver->Details.SectionName)]);
+    TRACE("MatchingDeviceId: '%S'\n", SelectedDriver->MatchingId);
+    TRACE("ProviderName    : '%S'\n", SelectedDriver->Info.ProviderName);
     swprintf(Buffer, L"%u-%u-%u", DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
     rc = RegSetValueEx(hKey, L"DriverDate", 0, REG_SZ, (const BYTE *)Buffer, (wcslen(Buffer) + 1) * sizeof(WCHAR));
     if (rc == ERROR_SUCCESS)
-        rc = RegSetValueEx(hKey, L"DriverDateData", 0, REG_BINARY, (const BYTE *)&DriverInfo->Info.DriverDate, sizeof(FILETIME));
+        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 *)DriverInfo->Info.Description, (wcslen(DriverInfo->Info.Description) + 1) * sizeof(WCHAR));
+        rc = RegSetValueEx(hKey, L"DriverDesc", 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", DriverInfo->Info.DriverVersion & 0xff, (DriverInfo->Info.DriverVersion >> 8) & 0xff, (DriverInfo->Info.DriverVersion >> 16) & 0xff, (DriverInfo->Info.DriverVersion >> 24) & 0xff);
+        swprintf(Buffer, L"%u.%u.%u.%u", SelectedDriver->Info.DriverVersion & 0xff, (SelectedDriver->Info.DriverVersion >> 8) & 0xff, (SelectedDriver->Info.DriverVersion >> 16) & 0xff, (SelectedDriver->Info.DriverVersion >> 24) & 0xff);
         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 *)DriverInfo->InfPath, (wcslen(DriverInfo->InfPath) + 1) * sizeof(WCHAR));
+        rc = RegSetValueEx(hKey, L"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 *)DriverInfo->InfSection, (wcslen(DriverInfo->InfSection) + 1) * sizeof(WCHAR));
+        rc = RegSetValueEx(hKey, L"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(DriverInfo->InfSection)], (wcslen(SectionName) - wcslen(DriverInfo->InfSection) + 1) * sizeof(WCHAR));
+        rc = RegSetValueEx(hKey, L"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 *)DriverInfo->MatchingId, (wcslen(DriverInfo->MatchingId) + 1) * sizeof(WCHAR));
+        rc = RegSetValueEx(hKey, L"MatchingDeviceId", 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 *)DriverInfo->Info.ProviderName, (wcslen(DriverInfo->Info.ProviderName) + 1) * sizeof(WCHAR));
+        rc = RegSetValueEx(hKey, L"ProviderName", 0, REG_SZ, (const BYTE *)SelectedDriver->Info.ProviderName, (wcslen(SelectedDriver->Info.ProviderName) + 1) * sizeof(WCHAR));
     if (rc != ERROR_SUCCESS)
     {
        SetLastError(rc);
@@ -5039,9 +5769,11 @@ SetupDiInstallDevice(
     RegCloseKey(hKey);
     hKey = INVALID_HANDLE_VALUE;
 
+    /* FIXME: Process .LogConfigOverride section */
+
     /* Install .Services section */
     wcscpy(pSectionName, L".Services");
-    Result = SetupFindFirstLineW(hInf, SectionName, NULL, &ContextService);
+    Result = SetupFindFirstLineW(SelectedDriver->InfFileDetails->hInf, SectionName, NULL, &ContextService);
     while (Result)
     {
         LPWSTR ServiceName = NULL;
@@ -5100,12 +5832,14 @@ SetupDiInstallDevice(
                 &ContextService,
                 3, /* Field index */
                 ServiceSection, RequiredSize,
-               &RequiredSize);
+                &RequiredSize);
             if (!Result)
-               goto nextfile;
+                goto nextfile;
         }
         SetLastError(ERROR_SUCCESS);
-        Result = SetupInstallServicesFromInfSectionExW(hInf, ServiceSection, Flags, DeviceInfoSet, DeviceInfoData, ServiceName, NULL);
+        Result = SetupInstallServicesFromInfSectionExW(
+            SelectedDriver->InfFileDetails->hInf,
+            ServiceSection, Flags, DeviceInfoSet, DeviceInfoData, ServiceName, NULL);
         if (Result && (Flags & SPSVCINST_ASSOCSERVICE))
         {
             AssociatedService = ServiceName;
@@ -5131,10 +5865,11 @@ nextfile:
 
     /* Install .HW section */
     wcscpy(pSectionName, L".HW");
-    Result = SetupInstallFromInfSectionW(hWnd, hInf, SectionName,
+    Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
+        SelectedDriver->InfFileDetails->hInf, SectionName,
         SPINST_REGISTRY, hKey, NULL, 0,
-        SetupDefaultQueueCallbackW, NULL,
-        NULL, NULL);
+        InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext,
+        DeviceInfoSet, DeviceInfoData);
     if (!Result)
         goto cleanup;
 
@@ -5143,17 +5878,17 @@ nextfile:
     TRACE("Service         : '%S'\n", AssociatedService);
     TRACE("Class           : '%S'\n", ClassName);
     TRACE("ClassGUID       : '%S'\n", lpFullGuidString);
-    TRACE("DeviceDesc      : '%S'\n", DriverInfo->Info.Description);
-    TRACE("Mfg             : '%S'\n", DriverInfo->Info.MfgName);
+    TRACE("DeviceDesc      : '%S'\n", SelectedDriver->Info.Description);
+    TRACE("Mfg             : '%S'\n", SelectedDriver->Info.MfgName);
     rc = RegSetValueEx(hKey, L"Service", 0, REG_SZ, (const BYTE *)AssociatedService, (wcslen(AssociatedService) + 1) * sizeof(WCHAR));
     if (rc == ERROR_SUCCESS)
         rc = RegSetValueEx(hKey, L"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));
     if (rc == ERROR_SUCCESS)
-        rc = RegSetValueEx(hKey, L"DeviceDesc", 0, REG_SZ, (const BYTE *)DriverInfo->Info.Description, (wcslen(DriverInfo->Info.Description) + 1) * sizeof(WCHAR));
+        rc = RegSetValueEx(hKey, L"DeviceDesc", 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 *)DriverInfo->Info.MfgName, (wcslen(DriverInfo->Info.MfgName) + 1) * sizeof(WCHAR));
+        rc = RegSetValueEx(hKey, L"Mfg", 0, REG_SZ, (const BYTE *)SelectedDriver->Info.MfgName, (wcslen(SelectedDriver->Info.MfgName) + 1) * sizeof(WCHAR));
     if (rc != ERROR_SUCCESS)
     {
        SetLastError(rc);
@@ -5161,7 +5896,7 @@ nextfile:
     }
 
     /* Start the device */
-    if (!RebootRequired && !(Flags & (DI_NEEDRESTART | DI_NEEDREBOOT | DI_DONOTCALLCONFIGMG)))
+    if (!RebootRequired && !(InstallParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT | DI_DONOTCALLCONFIGMG)))
     {
         PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData;
         NTSTATUS Status;
@@ -5181,10 +5916,7 @@ cleanup:
     if (lpGuidString)
         RpcStringFreeW(&lpGuidString);
     HeapFree(GetProcessHeap(), 0, (LPWSTR)AssociatedService);
-    HeapFree(GetProcessHeap(), 0, ClassName);
     HeapFree(GetProcessHeap(), 0, lpFullGuidString);
-    if (hInf != INVALID_HANDLE_VALUE)
-        SetupCloseInfFile(hInf);
 
     TRACE("Returning %d\n", ret);
     return ret;