Implement DICS_FLAG_CONFIGSPECIFIC and DIREG_DEV cases in SetupDiCreateDevRegKeyW
[reactos.git] / reactos / lib / setupapi / devinst.c
index c05b63f..38a3de3 100644 (file)
@@ -29,6 +29,7 @@ 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 DeviceInstance[]  = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
+static const WCHAR InterfaceInstall32[]  = {'I','n','t','e','r','f','a','c','e','I','n','s','t','a','l','l','3','2',0};
 static const WCHAR NoDisplayClass[]  = {'N','o','D','i','s','p','l','a','y','C','l','a','s','s',0};
 static const WCHAR NoInstallClass[]  = {'N','o','I','s','t','a','l','l','C','l','a','s','s',0};
 static const WCHAR NoUseClass[]  = {'N','o','U','s','e','C','l','a','s','s',0};
@@ -77,6 +78,12 @@ typedef BOOL
     IN PSP_PROPSHEETPAGE_REQUEST PropPageRequest,
     IN LPFNADDPROPSHEETPAGE fAddFunc,
     IN LPARAM lParam);
+typedef BOOL
+(*UPDATE_CLASS_PARAM_HANDLER) (
+    IN HDEVINFO DeviceInfoSet,
+    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
+    IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
+    IN DWORD ClassInstallParamsSize);
 
 struct CoInstallerElement
 {
@@ -88,6 +95,58 @@ struct CoInstallerElement
     PVOID PrivateData;
 };
 
+static BOOL
+PropertyChangeHandler(
+    IN HDEVINFO DeviceInfoSet,
+    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
+    IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
+    IN DWORD ClassInstallParamsSize);
+
+static UPDATE_CLASS_PARAM_HANDLER UpdateClassInstallParamHandlers[] = {
+    NULL, /* DIF_SELECTDEVICE */
+    NULL, /* DIF_INSTALLDEVICE */
+    NULL, /* DIF_ASSIGNRESOURCES */
+    NULL, /* DIF_PROPERTIES */
+    NULL, /* DIF_REMOVE */
+    NULL, /* DIF_FIRSTTIMESETUP */
+    NULL, /* DIF_FOUNDDEVICE */
+    NULL, /* DIF_SELECTCLASSDRIVERS */
+    NULL, /* DIF_VALIDATECLASSDRIVERS */
+    NULL, /* DIF_INSTALLCLASSDRIVERS */
+    NULL, /* DIF_CALCDISKSPACE */
+    NULL, /* DIF_DESTROYPRIVATEDATA */
+    NULL, /* DIF_VALIDATEDRIVER */
+    NULL, /* DIF_MOVEDEVICE */
+    NULL, /* DIF_DETECT */
+    NULL, /* DIF_INSTALLWIZARD */
+    NULL, /* DIF_DESTROYWIZARDDATA */
+    PropertyChangeHandler, /* DIF_PROPERTYCHANGE */
+    NULL, /* DIF_ENABLECLASS */
+    NULL, /* DIF_DETECTVERIFY */
+    NULL, /* DIF_INSTALLDEVICEFILES */
+    NULL, /* DIF_UNREMOVE */
+    NULL, /* DIF_SELECTBESTCOMPATDRV */
+    NULL, /* DIF_ALLOW_INSTALL */
+    NULL, /* DIF_REGISTERDEVICE */
+    NULL, /* DIF_NEWDEVICEWIZARD_PRESELECT */
+    NULL, /* DIF_NEWDEVICEWIZARD_SELECT */
+    NULL, /* DIF_NEWDEVICEWIZARD_PREANALYZE */
+    NULL, /* DIF_NEWDEVICEWIZARD_POSTANALYZE */
+    NULL, /* DIF_NEWDEVICEWIZARD_FINISHINSTALL */
+    NULL, /* DIF_UNUSED1 */
+    NULL, /* DIF_INSTALLINTERFACES */
+    NULL, /* DIF_DETECTCANCEL */
+    NULL, /* DIF_REGISTER_COINSTALLERS */
+    NULL, /* DIF_ADDPROPERTYPAGE_ADVANCED */
+    NULL, /* DIF_ADDPROPERTYPAGE_BASIC */
+    NULL, /* DIF_RESERVED1 */
+    NULL, /* DIF_TROUBLESHOOTER */
+    NULL, /* DIF_POWERMESSAGEWAKE */
+    NULL, /* DIF_ADDREMOTEPROPERTYPAGE_ADVANCED */
+    NULL, /* DIF_UPDATEDRIVER_UI */
+    NULL  /* DIF_RESERVED2 */
+};
+
 /***********************************************************************
  *              SetupDiBuildClassInfoList  (SETUPAPI.@)
  */
@@ -633,7 +692,7 @@ GetErrorCodeFromCrCode(const IN CONFIGRET cr)
       /* FIXME */
       return ERROR_GEN_FAILURE;
   }
-  
+
   /* Does not happen */
 }
 
@@ -656,7 +715,7 @@ SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
   TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
       debugstr_w(MachineName), Reserved);
 
-  size = sizeof(struct DeviceInfoSet);
+  size = FIELD_OFFSET(struct DeviceInfoSet, szData);
   if (MachineName)
     size += (wcslen(MachineName) + 3) * sizeof(WCHAR);
   list = HeapAlloc(GetProcessHeap(), 0, size);
@@ -689,7 +748,7 @@ SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
       SetLastError(ERROR_NOT_ENOUGH_MEMORY);
       goto cleanup;
     }
-    
+
     strcpyW(UNCServerName + 2, MachineName);
     list->szData[0] = list->szData[1] = '\\';
     strcpyW(list->szData + 2, MachineName);
@@ -750,7 +809,7 @@ BOOL WINAPI SetupDiEnumDeviceInfo(
     else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
     {
         struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
-        
+
         if (list->magic != SETUP_DEV_INFO_SET_MAGIC)
             SetLastError(ERROR_INVALID_HANDLE);
         else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
@@ -1145,7 +1204,7 @@ CreateDeviceInfoElement(
 
     *pDeviceInfo = NULL;
 
-    size = sizeof(struct DeviceInfoElement) + (wcslen(InstancePath) + 1) * sizeof(WCHAR);
+    size = FIELD_OFFSET(struct DeviceInfoElement, Data) + (wcslen(InstancePath) + 1) * sizeof(WCHAR);
     deviceInfo = HeapAlloc(GetProcessHeap(), 0, size);
     if (!deviceInfo)
     {
@@ -1186,7 +1245,8 @@ CreateDeviceInterface(
 
     *pDeviceInterface = NULL;
 
-    deviceInterface = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInterface) + (wcslen(SymbolicLink) + 1) * sizeof(WCHAR));
+    deviceInterface = HeapAlloc(GetProcessHeap(), 0,
+        FIELD_OFFSET(struct DeviceInterface, SymbolicLink) + (wcslen(SymbolicLink) + 1) * sizeof(WCHAR));
     if (!deviceInterface)
     {
         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
@@ -1215,7 +1275,7 @@ static LONG SETUP_CreateDevListFromEnumerator(
     DWORD i = 0, j;
     DWORD dwLength, dwRegType;
     DWORD rc;
-    
+
     /* Enumerate device IDs (subkeys of hEnumeratorKey) */
     while (TRUE)
     {
@@ -1632,7 +1692,7 @@ static LONG SETUP_CreateInterfaceList(
             RegCloseKey(hDeviceInstanceKey);
             continue;
         }
-        
+
         /* Enumerate subkeys of hDeviceInstanceKey (ie "#ReferenceString" in IoRegisterDeviceInterface). Skip entries that don't start with '#' */
         j = 0;
         while (TRUE)
@@ -1841,6 +1901,309 @@ HDEVINFO WINAPI SetupDiGetClassDevsExW(
     }
 }
 
+/***********************************************************************
+ *             SetupDiGetClassImageIndex (SETUPAPI.@)
+ */
+
+static BOOL GetIconIndex(
+       IN HKEY hClassKey,
+       OUT PINT ImageIndex)
+{
+    LPWSTR Buffer = NULL;
+    DWORD dwRegType, dwLength;
+    LONG rc;
+    BOOL ret = FALSE;
+
+    /* Read "Icon" registry key */
+    rc = RegQueryValueExW(hClassKey, L"Icon", NULL, &dwRegType, NULL, &dwLength);
+    if (rc != ERROR_SUCCESS)
+    {
+        SetLastError(rc);
+        goto cleanup;
+    } else if (dwRegType != REG_SZ)
+    {
+        SetLastError(ERROR_INVALID_INDEX);
+        goto cleanup;
+    }
+    Buffer = MyMalloc(dwLength + sizeof(WCHAR));
+    if (!Buffer)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        goto cleanup;
+    }
+    rc = RegQueryValueExW(hClassKey, L"Icon", NULL, NULL, (LPBYTE)Buffer, &dwLength);
+    if (rc != ERROR_SUCCESS)
+    {
+        SetLastError(rc);
+        goto cleanup;
+    }
+    /* make sure the returned buffer is NULL-terminated */
+    Buffer[dwLength / sizeof(WCHAR)] = 0;
+
+    /* Transform "Icon" value to a INT */
+    *ImageIndex = atoiW(Buffer);
+    ret = TRUE;
+
+cleanup:
+    MyFree(Buffer);
+    return ret;
+}
+
+BOOL WINAPI SetupDiGetClassImageIndex(
+       IN PSP_CLASSIMAGELIST_DATA ClassImageListData,
+       IN CONST GUID *ClassGuid,
+       OUT PINT ImageIndex)
+{
+    struct ClassImageList *list;
+    BOOL ret = FALSE;
+
+    TRACE("%p %s %p\n", ClassImageListData, debugstr_guid(ClassGuid), ImageIndex);
+
+    if (!ClassImageListData || !ClassGuid || !ImageIndex)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA))
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else if ((list = (struct ClassImageList *)ClassImageListData->Reserved) == NULL)
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else if (list->magic != SETUP_CLASS_IMAGE_LIST_MAGIC)
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else if (!ImageIndex)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else
+    {
+        HKEY hKey = INVALID_HANDLE_VALUE;
+        INT iconIndex;
+
+        /* Read Icon registry entry into Buffer */
+        hKey = SetupDiOpenClassRegKeyExW(ClassGuid, KEY_QUERY_VALUE, DIOCR_INTERFACE, list->MachineName, NULL);
+        if (hKey == INVALID_HANDLE_VALUE)
+            goto cleanup;
+        if (!GetIconIndex(hKey, &iconIndex))
+            goto cleanup;
+
+        if (iconIndex >= 0)
+        {
+            SetLastError(ERROR_INVALID_INDEX);
+            goto cleanup;
+        }
+
+        *ImageIndex = -iconIndex;
+        ret = TRUE;
+
+cleanup:
+        if (hKey != INVALID_HANDLE_VALUE)
+            RegCloseKey(hKey);
+    }
+
+    TRACE("Returning %d\n", ret);
+    return ret;
+}
+
+/***********************************************************************
+ *             SetupDiGetClassImageList(SETUPAPI.@)
+ */
+BOOL WINAPI SetupDiGetClassImageList(
+       OUT PSP_CLASSIMAGELIST_DATA ClassImageListData)
+{
+    return SetupDiGetClassImageListExW(ClassImageListData, NULL, NULL);
+}
+
+/***********************************************************************
+ *             SetupDiGetClassImageListExA(SETUPAPI.@)
+ */
+BOOL WINAPI SetupDiGetClassImageListExA(
+       OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
+       IN PCSTR MachineName OPTIONAL,
+       IN PVOID Reserved)
+{
+    PWSTR MachineNameW = NULL;
+    BOOL ret;
+
+    if (MachineName)
+    {
+        MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
+        if (MachineNameW == NULL)
+            return FALSE;
+    }
+
+    ret = SetupDiGetClassImageListExW(ClassImageListData, MachineNameW, Reserved);
+
+    if (MachineNameW)
+        MyFree(MachineNameW);
+
+    return ret;
+}
+
+/***********************************************************************
+ *             SetupDiGetClassImageListExW(SETUPAPI.@)
+ */
+BOOL WINAPI SetupDiGetClassImageListExW(
+       OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
+       IN PCWSTR MachineName OPTIONAL,
+       IN PVOID Reserved)
+{
+    BOOL ret = FALSE;
+
+    TRACE("%p %p %p\n", ClassImageListData, debugstr_w(MachineName), Reserved);
+
+    if (!ClassImageListData)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA))
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else if (Reserved)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else
+    {
+        struct ClassImageList *list = NULL;
+        DWORD size;
+
+        size = FIELD_OFFSET(struct ClassImageList, szData);
+        if (MachineName)
+            size += (wcslen(MachineName) + 3) * sizeof(WCHAR);
+        list = HeapAlloc(GetProcessHeap(), 0, size);
+        if (!list)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            goto cleanup;
+        }
+        list->magic = SETUP_CLASS_IMAGE_LIST_MAGIC;
+        if (MachineName)
+        {
+            list->szData[0] = list->szData[1] = '\\';
+            strcpyW(list->szData + 2, MachineName);
+            list->MachineName = list->szData;
+        }
+        else
+        {
+            list->MachineName = NULL;
+        }
+
+        ClassImageListData->Reserved = (DWORD)list; /* FIXME: 64 bit portability issue */
+        ret = TRUE;
+
+cleanup:
+        if (!ret)
+            MyFree(list);
+    }
+
+    TRACE("Returning %d\n", ret);
+    return ret;
+}
+
+/***********************************************************************
+ *             SetupDiLoadClassIcon(SETUPAPI.@)
+ */
+BOOL WINAPI SetupDiLoadClassIcon(
+       IN CONST GUID *ClassGuid,
+       OUT HICON *LargeIcon OPTIONAL,
+       OUT PINT MiniIconIndex OPTIONAL)
+{
+    BOOL ret = FALSE;
+
+    if (!ClassGuid)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else
+    {
+        LPWSTR Buffer = NULL;
+        LPCWSTR DllName;
+        INT iconIndex;
+        HKEY hKey = INVALID_HANDLE_VALUE;
+
+        hKey = SetupDiOpenClassRegKey(ClassGuid, KEY_QUERY_VALUE);
+        if (hKey == INVALID_HANDLE_VALUE)
+            goto cleanup;
+
+        if (!GetIconIndex(hKey, &iconIndex))
+            goto cleanup;
+
+        if (iconIndex > 0)
+        {
+            /* Look up icon in dll specified by Installer32 or EnumPropPages32 key */
+            PWCHAR Comma;
+            LONG rc;
+            DWORD dwRegType, dwLength;
+            rc = RegQueryValueExW(hKey, L"Installer32", NULL, &dwRegType, NULL, &dwLength);
+            if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
+            {
+                Buffer = MyMalloc(dwLength + sizeof(WCHAR));
+                if (Buffer == NULL)
+                {
+                    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                    goto cleanup;
+                }
+                rc = RegQueryValueExW(hKey, L"Installer32", NULL, NULL, (LPBYTE)Buffer, &dwLength);
+                if (rc != ERROR_SUCCESS)
+                {
+                    SetLastError(rc);
+                    goto cleanup;
+                }
+                /* make sure the returned buffer is NULL-terminated */
+                Buffer[dwLength / sizeof(WCHAR)] = 0;
+            }
+            else if
+                (ERROR_SUCCESS == (rc = RegQueryValueExW(hKey, L"EnumPropPages32", NULL, &dwRegType, NULL, &dwLength))
+                && dwRegType == REG_SZ)
+            {
+                Buffer = MyMalloc(dwLength + sizeof(WCHAR));
+                if (Buffer == NULL)
+                {
+                    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                    goto cleanup;
+                }
+                rc = RegQueryValueExW(hKey, L"EnumPropPages32", NULL, NULL, (LPBYTE)Buffer, &dwLength);
+                if (rc != ERROR_SUCCESS)
+                {
+                    SetLastError(rc);
+                    goto cleanup;
+                }
+                /* make sure the returned buffer is NULL-terminated */
+                Buffer[dwLength / sizeof(WCHAR)] = 0;
+            }
+            else
+            {
+                /* Unable to find where to load the icon */
+                SetLastError(ERROR_FILE_NOT_FOUND);
+                goto cleanup;
+            }
+            Comma = strchrW(Buffer, ',');
+            if (!Comma)
+            {
+                SetLastError(ERROR_GEN_FAILURE);
+                goto cleanup;
+            }
+            *Comma = '\0';
+            DllName = Buffer;
+        }
+        else
+        {
+            /* Look up icon in setupapi.dll */
+            DllName = L"setupapi.dll";
+            iconIndex = -iconIndex;
+        }
+
+        TRACE("Icon index %d, dll name %s\n", iconIndex, debugstr_w(DllName));
+        if (LargeIcon)
+        {
+            if (1 != ExtractIconEx(DllName, iconIndex, LargeIcon, NULL, 1))
+            {
+                SetLastError(ERROR_INVALID_INDEX);
+                goto cleanup;
+            }
+        }
+        if (MiniIconIndex)
+            *MiniIconIndex = iconIndex;
+        ret = TRUE;
+
+cleanup:
+        if (hKey != INVALID_HANDLE_VALUE)
+            RegCloseKey(hKey);
+        MyFree(Buffer);
+    }
+
+    TRACE("Returning %d\n", ret);
+    return ret;
+}
+
 /***********************************************************************
  *             SetupDiEnumDeviceInterfaces (SETUPAPI.@)
  */
@@ -1936,6 +2299,12 @@ static BOOL DestroyDriverInfoElement(struct DriverInfoElement* driverInfo)
     return TRUE;
 }
 
+static BOOL DestroyClassInstallParams(struct ClassInstallParams* installParams)
+{
+    HeapFree(GetProcessHeap(), 0, installParams->PropChange);
+    return TRUE;
+}
+
 static BOOL DestroyDeviceInfoElement(struct DeviceInfoElement* deviceInfo)
 {
     PLIST_ENTRY ListEntry;
@@ -1953,6 +2322,7 @@ static BOOL DestroyDeviceInfoElement(struct DeviceInfoElement* deviceInfo)
         ListEntry = RemoveHeadList(&deviceInfo->InterfaceListHead);
         HeapFree(GetProcessHeap(), 0, ListEntry);
     }
+    DestroyClassInstallParams(&deviceInfo->ClassInstallParams);
     HeapFree(GetProcessHeap(), 0, deviceInfo);
     return TRUE;
 }
@@ -1972,6 +2342,7 @@ static BOOL DestroyDeviceInfoSet(struct DeviceInfoSet* list)
     if (list->HKLM != HKEY_LOCAL_MACHINE)
         RegCloseKey(list->HKLM);
     CM_Disconnect_Machine(list->hMachine);
+    DestroyClassInstallParams(&list->ClassInstallParams);
     HeapFree(GetProcessHeap(), 0, list);
     return TRUE;
 }
@@ -2271,7 +2642,7 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
             {
                 LPCWSTR RegistryPropertyName;
                 DWORD BufferSize;
-                
+
                 switch (Property)
                 {
                     case SPDRP_CAPABILITIES:
@@ -2448,7 +2819,7 @@ BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
         SetLastError(ERROR_INVALID_HANDLE);
     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
         SetLastError(ERROR_INVALID_HANDLE);
-    else if (DeviceInfoData)
+    else if (!DeviceInfoData)
         SetLastError(ERROR_INVALID_HANDLE);
     else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
         SetLastError(ERROR_INVALID_USER_BUFFER);
@@ -2738,7 +3109,7 @@ BOOL WINAPI SetupDiInstallClassW(
                                INVALID_HANDLE_VALUE,
                                NULL);
 
-    /* FIXME: More code! */
+    /* FIXME: Process InterfaceInstall32 section */
 
     if (bFileQueueCreated)
        SetupCloseFileQueue(FileQueue);
@@ -2766,10 +3137,10 @@ HKEY WINAPI SetupDiOpenClassRegKey(
  *             SetupDiOpenClassRegKeyExA  (SETUPAPI.@)
  */
 HKEY WINAPI SetupDiOpenClassRegKeyExA(
-        const GUID* ClassGuid,
+        const GUID* ClassGuid OPTIONAL,
         REGSAM samDesired,
         DWORD Flags,
-        PCSTR MachineName,
+        PCSTR MachineName OPTIONAL,
         PVOID Reserved)
 {
     PWSTR MachineNameW = NULL;
@@ -2798,10 +3169,10 @@ HKEY WINAPI SetupDiOpenClassRegKeyExA(
  *             SetupDiOpenClassRegKeyExW  (SETUPAPI.@)
  */
 HKEY WINAPI SetupDiOpenClassRegKeyExW(
-        const GUID* ClassGuid,
+        const GUID* ClassGuid OPTIONAL,
         REGSAM samDesired,
         DWORD Flags,
-        PCWSTR MachineName,
+        PCWSTR MachineName OPTIONAL,
         PVOID Reserved)
 {
     LPWSTR lpGuidString;
@@ -2956,14 +3327,131 @@ BOOL WINAPI SetupDiSetClassInstallParamsA(
  *             SetupDiSetClassInstallParamsW (SETUPAPI.@)
  */
 BOOL WINAPI SetupDiSetClassInstallParamsW(
-       HDEVINFO  DeviceInfoSet,
-       PSP_DEVINFO_DATA DeviceInfoData,
-       PSP_CLASSINSTALL_HEADER ClassInstallParams,
-       DWORD ClassInstallParamsSize)
+       IN HDEVINFO DeviceInfoSet,
+       IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
+       IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
+       IN DWORD ClassInstallParamsSize)
 {
-    FIXME("%p %p %x %lu\n",DeviceInfoSet, DeviceInfoData,
-          ClassInstallParams->InstallFunction, ClassInstallParamsSize);
-    return FALSE;
+    struct DeviceInfoSet *list;
+    BOOL ret = FALSE;
+
+    TRACE("%p %p %p %lu\n", DeviceInfoSet, DeviceInfoData,
+        ClassInstallParams, ClassInstallParamsSize);
+
+    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 && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else if (ClassInstallParams && ClassInstallParams->cbSize != sizeof(SP_CLASSINSTALL_HEADER))
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else if (ClassInstallParams && ClassInstallParamsSize < sizeof(SP_CLASSINSTALL_HEADER))
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (!ClassInstallParams && ClassInstallParamsSize != 0)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else
+    {
+        SP_DEVINSTALL_PARAMS_W InstallParams;
+        BOOL Result;
+
+        InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+        Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
+        if (!Result)
+            goto done;
+
+        if (ClassInstallParams)
+        {
+            /* Check parameters in ClassInstallParams */
+            if (ClassInstallParams->InstallFunction < DIF_SELECTDEVICE
+                || ClassInstallParams->InstallFunction - DIF_SELECTDEVICE >= sizeof(UpdateClassInstallParamHandlers)/sizeof(UpdateClassInstallParamHandlers[0]))
+            {
+                SetLastError(ERROR_INVALID_USER_BUFFER);
+                goto done;
+            }
+            else if (UpdateClassInstallParamHandlers[ClassInstallParams->InstallFunction - DIF_SELECTDEVICE] == NULL)
+            {
+                FIXME("InstallFunction %u is valid, but has no associated update handler\n", ClassInstallParams->InstallFunction);
+                SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+                goto done;
+            }
+            ret = UpdateClassInstallParamHandlers[ClassInstallParams->InstallFunction - DIF_SELECTDEVICE](DeviceInfoSet, DeviceInfoData, ClassInstallParams, ClassInstallParamsSize);
+            if (!ret)
+                goto done;
+            InstallParams.Flags |= DI_CLASSINSTALLPARAMS;
+        }
+        else
+        {
+            InstallParams.Flags &= ~DI_CLASSINSTALLPARAMS;
+        }
+
+        ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
+    }
+
+done:
+    TRACE("Returning %d\n", ret);
+    return ret;
+}
+
+static BOOL PropertyChangeHandler(
+       IN HDEVINFO DeviceInfoSet,
+       IN PSP_DEVINFO_DATA DeviceInfoData,
+       IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
+       IN DWORD ClassInstallParamsSize)
+{
+    PSP_PROPCHANGE_PARAMS PropChangeParams = (PSP_PROPCHANGE_PARAMS)ClassInstallParams;
+    BOOL ret = FALSE;
+
+    if (!DeviceInfoData)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (ClassInstallParamsSize != sizeof(SP_PROPCHANGE_PARAMS))
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (PropChangeParams && PropChangeParams->StateChange != DICS_ENABLE
+        && PropChangeParams->StateChange != DICS_DISABLE && PropChangeParams->StateChange != DICS_PROPCHANGE
+        && PropChangeParams->StateChange != DICS_START && PropChangeParams->StateChange != DICS_STOP)
+        SetLastError(ERROR_INVALID_FLAGS);
+    else if (PropChangeParams && PropChangeParams->Scope != DICS_FLAG_GLOBAL
+        && PropChangeParams->Scope != DICS_FLAG_CONFIGSPECIFIC)
+        SetLastError(ERROR_INVALID_FLAGS);
+    else if (PropChangeParams
+        && (PropChangeParams->StateChange == DICS_START || PropChangeParams->StateChange == DICS_STOP)
+        && PropChangeParams->Scope != DICS_FLAG_CONFIGSPECIFIC)
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else
+    {
+        PSP_PROPCHANGE_PARAMS *CurrentPropChangeParams;
+        if (!DeviceInfoData)
+        {
+            struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
+            CurrentPropChangeParams = &list->ClassInstallParams.PropChange;
+        }
+        else
+        {
+            struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
+            CurrentPropChangeParams = &deviceInfo->ClassInstallParams.PropChange;
+        }
+        if (*CurrentPropChangeParams)
+        {
+            MyFree(*CurrentPropChangeParams);
+            *CurrentPropChangeParams = NULL;
+        }
+        if (PropChangeParams)
+        {
+            *CurrentPropChangeParams = MyMalloc(sizeof(SP_PROPCHANGE_PARAMS));
+            if (!*CurrentPropChangeParams)
+            {
+                SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                goto done;
+            }
+            memcpy(*CurrentPropChangeParams, PropChangeParams, sizeof(SP_PROPCHANGE_PARAMS));
+        }
+        ret = TRUE;
+    }
+
+done:
+    return ret;
 }
 
 static DWORD
@@ -3100,6 +3588,10 @@ BOOL WINAPI SetupDiCallClassInstaller(
             case DIF_NEWDEVICEWIZARD_PREANALYZE:
                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
                 break;
+            case DIF_PROPERTYCHANGE:
+                CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
+                DefaultHandler = SetupDiChangeState;
+                break;
             case DIF_REGISTER_COINSTALLERS:
                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
                 DefaultHandler = SetupDiRegisterCoDeviceInstallers;
@@ -3757,7 +4249,7 @@ BOOL WINAPI SetupDiGetClassDevPropertySheetsW(
         rc = GetFunctionPointer(PropPageProvider, &hModule, (PVOID*)&pPropPageProvider);
         if (rc != ERROR_SUCCESS)
         {
-            SetLastError(rc);
+            SetLastError(ERROR_INVALID_PROPPAGE_PROVIDER);
             goto cleanup;
         }
 
@@ -3872,25 +4364,101 @@ HKEY WINAPI SetupDiCreateDevRegKeyW(
         LPWSTR pDeviceInstance; /* Points into DriverKey, on the Index field */
         DWORD Index; /* Index used in the DriverKey name */
         DWORD rc;
+        HKEY hHWProfilesKey = INVALID_HANDLE_VALUE;
+        HKEY hHWProfileKey = INVALID_HANDLE_VALUE;
+        HKEY hEnumKey = INVALID_HANDLE_VALUE;
         HKEY hClassKey = INVALID_HANDLE_VALUE;
         HKEY hDeviceKey = INVALID_HANDLE_VALUE;
         HKEY hKey = INVALID_HANDLE_VALUE;
+        HKEY RootKey;
 
-        if (Scope == DICS_FLAG_CONFIGSPECIFIC)
+        if (Scope == DICS_FLAG_GLOBAL)
+            RootKey = list->HKLM;
+        else /* Scope == DICS_FLAG_CONFIGSPECIFIC */
         {
-            FIXME("DICS_FLAG_CONFIGSPECIFIC case unimplemented\n");
-            goto cleanup;
+            rc = RegOpenKeyExW(list->HKLM,
+                L"SYSTEM\\CurrentControlSet\\Hardware Profiles",
+                0,
+                0,
+                &hHWProfilesKey);
+            if (rc != ERROR_SUCCESS)
+            {
+                SetLastError(rc);
+                goto cleanup;
+            }
+            if (HwProfile == 0)
+            {
+                rc = RegOpenKeyExW(
+                    hHWProfilesKey,
+                    REGSTR_KEY_CURRENT,
+                    0,
+                    KEY_CREATE_SUB_KEY,
+                    &hHWProfileKey);
+            }
+            else
+            {
+                WCHAR subKey[5];
+                snprintfW(subKey, 4, L"%04lu", HwProfile);
+                subKey[4] = '\0';
+                rc = RegOpenKeyExW(
+                    hHWProfilesKey,
+                    subKey,
+                    0,
+                    KEY_CREATE_SUB_KEY,
+                    &hHWProfileKey);
+            }
+            if (rc != ERROR_SUCCESS)
+            {
+                SetLastError(rc);
+                goto cleanup;
+            }
+            RootKey = hHWProfileKey;
         }
 
         if (KeyType == DIREG_DEV)
         {
-            FIXME("DIREG_DEV case unimplemented\n");
+            struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
+
+            rc = RegCreateKeyExW(
+                RootKey,
+                EnumKeyName,
+                0,
+                NULL,
+                REG_OPTION_NON_VOLATILE,
+                KEY_CREATE_SUB_KEY,
+                NULL,
+                &hEnumKey,
+                NULL);
+            if (rc != ERROR_SUCCESS)
+            {
+                SetLastError(rc);
+                goto cleanup;
+            }
+            rc = RegCreateKeyExW(
+                hEnumKey,
+                deviceInfo->DeviceName,
+                0,
+                NULL,
+                REG_OPTION_NON_VOLATILE,
+#if _WIN32_WINNT >= 0x502
+                KEY_READ | KEY_WRITE,
+#else
+                KEY_ALL_ACCESS,
+#endif
+                NULL,
+                &hKey,
+                NULL);
+            if (rc != ERROR_SUCCESS)
+            {
+                SetLastError(rc);
+                goto cleanup;
+            }
         }
         else /* KeyType == DIREG_DRV */
         {
             if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) != RPC_S_OK)
                 goto cleanup;
-            /* The driver key is in HKLM\System\CurrentControlSet\Control\Class\{GUID}\Index */
+            /* The driver key is in \System\CurrentControlSet\Control\Class\{GUID}\Index */
             DriverKey = HeapAlloc(GetProcessHeap(), 0, (wcslen(lpGuidString) + 7) * sizeof(WCHAR) + sizeof(UNICODE_STRING));
             if (!DriverKey)
             {
@@ -3901,7 +4469,7 @@ HKEY WINAPI SetupDiCreateDevRegKeyW(
             wcscat(DriverKey, lpGuidString);
             wcscat(DriverKey, L"}\\");
             pDeviceInstance = &DriverKey[wcslen(DriverKey)];
-            rc = RegOpenKeyExW(list->HKLM,
+            rc = RegOpenKeyExW(RootKey,
                 ControlClass,
                 0,
                 KEY_CREATE_SUB_KEY,
@@ -3973,6 +4541,12 @@ cleanup:
         if (lpGuidString)
             RpcStringFreeW(&lpGuidString);
         HeapFree(GetProcessHeap(), 0, DriverKey);
+        if (hHWProfilesKey != INVALID_HANDLE_VALUE)
+            RegCloseKey(hHWProfilesKey);
+        if (hHWProfileKey != INVALID_HANDLE_VALUE)
+            RegCloseKey(hHWProfileKey);
+        if (hEnumKey != INVALID_HANDLE_VALUE)
+            RegCloseKey(hEnumKey);
         if (hClassKey != INVALID_HANDLE_VALUE)
             RegCloseKey(hClassKey);
         if (hDeviceKey != INVALID_HANDLE_VALUE)
@@ -4205,7 +4779,7 @@ BOOL WINAPI SetupDiCreateDeviceInfoW(
         if (CreationFlags & DICD_GENERATE_ID)
         {
             /* Generate a new unique ID for this device */
-            SetLastError(ERROR_GEN_FAILURE);
+            SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
             FIXME("not implemented\n");
         }
         else
@@ -4360,6 +4934,7 @@ AddDriverToList(
         driverInfo->Details.DrvDescription, InfFile, InfInstallSection, Rank);
 
     driverInfo->DriverRank = Rank;
+    memcpy(&driverInfo->DriverDate, &DriverDate, sizeof(FILETIME));
     memcpy(&driverInfo->ClassGuid, ClassGuid, sizeof(GUID));
     driverInfo->Info.DriverType = DriverType;
     driverInfo->Info.Reserved = (ULONG_PTR)driverInfo;
@@ -4383,7 +4958,10 @@ AddDriverToList(
     PreviousEntry = DriverListHead->Flink;
     while (PreviousEntry != DriverListHead)
     {
-        if (((struct DriverInfoElement *)PreviousEntry)->DriverRank >= Rank)
+        struct DriverInfoElement *CurrentDriver;
+        CurrentDriver = CONTAINING_RECORD(PreviousEntry, struct DriverInfoElement, ListEntry);
+        if (CurrentDriver->DriverRank > Rank ||
+            (CurrentDriver->DriverRank == Rank && CurrentDriver->DriverDate.QuadPart > driverInfo->DriverDate.QuadPart))
         {
             /* Insert before the current item */
             InsertHeadList(PreviousEntry, &driverInfo->ListEntry);
@@ -4519,7 +5097,36 @@ GetVersionInformationFromInfFile(
     }
     /* Get driver version. Invalid version = 0.0.0.0 */
     *DriverVersion = 0;
-    /* FIXME: use pVersion to fill DriverVersion variable */
+    if (pVersion)
+    {
+        WORD Major, Minor = 0, Revision = 0, Build = 0;
+        LPWSTR pMinor = NULL, pRevision = NULL, pBuild = NULL;
+        LARGE_INTEGER fullVersion;
+
+        pMinor = strchrW(pVersion, '.');
+        if (pMinor)
+        {
+            *pMinor = 0;
+            pRevision = strchrW(++pMinor, '.');
+            Minor = atoiW(pMinor);
+        }
+        if (pRevision)
+        {
+            *pRevision = 0;
+            pBuild = strchrW(++pRevision, '.');
+            Revision = atoiW(pRevision);
+        }
+        if (pBuild)
+        {
+            *pBuild = 0;
+            pBuild++;
+            Build = atoiW(pBuild);
+        }
+        Major = atoiW(pVersion);
+        fullVersion.u.HighPart = Major << 16 | Minor;
+        fullVersion.u.LowPart = Revision << 16 | Build;
+        memcpy(DriverVersion, &fullVersion, sizeof(LARGE_INTEGER));
+    }
 
     ret = TRUE;
 
@@ -4948,7 +5555,7 @@ SetupDiDeleteDeviceInfo(
     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
 
     FIXME("not implemented\n");
-    SetLastError(ERROR_GEN_FAILURE);
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
     return FALSE;
 }
 
@@ -5584,7 +6191,7 @@ SetupDiGetDriverInfoDetailA(
     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) ||
@@ -5612,7 +6219,7 @@ SetupDiGetDriverInfoDetailA(
     }
     DriverInfoDataW.DriverType = DriverInfoData->DriverType;
     DriverInfoDataW.Reserved = DriverInfoData->Reserved;
-    
+
     /* convert the strings to unicode */
     if (MultiByteToWideChar(CP_ACP,
                             0,
@@ -5758,7 +6365,7 @@ SetupDiGetDriverInfoDetailA(
             }
         }
     }
-    
+
 Cleanup:
     if (DriverInfoDetailDataW != NULL)
     {
@@ -5823,6 +6430,170 @@ SetupDiGetDriverInfoDetailW(
     return ret;
 }
 
+/* Return the current hardware profile id, or -1 if error */
+static DWORD
+GetCurrentHwProfile(
+    IN HDEVINFO DeviceInfoSet)
+{
+    HKEY hKey = INVALID_HANDLE_VALUE;
+    DWORD dwRegType, dwLength;
+    DWORD hwProfile;
+    LONG rc;
+    DWORD ret = (DWORD)-1;
+
+    rc = RegOpenKeyExW(
+        ((struct DeviceInfoSet *)DeviceInfoSet)->HKLM,
+        REGSTR_PATH_IDCONFIGDB,
+        0, /* Options */
+        KEY_QUERY_VALUE,
+        &hKey);
+    if (rc != ERROR_SUCCESS)
+    {
+        SetLastError(rc);
+        goto cleanup;
+    }
+
+    dwLength = sizeof(DWORD);
+    rc = RegQueryValueExW(
+        hKey,
+        REGSTR_VAL_CURRENTCONFIG,
+        NULL,
+        &dwRegType,
+        (LPBYTE)&hwProfile, &dwLength);
+    if (rc != ERROR_SUCCESS)
+    {
+        SetLastError(rc);
+        goto cleanup;
+    }
+    else if (dwRegType != REG_DWORD || dwLength != sizeof(DWORD))
+    {
+        SetLastError(ERROR_GEN_FAILURE);
+        goto cleanup;
+    }
+
+    ret = hwProfile;
+
+cleanup:
+    if (hKey != INVALID_HANDLE_VALUE)
+        RegCloseKey(hKey);
+
+    return hwProfile;
+}
+
+/***********************************************************************
+ *             SetupDiChangeState (SETUPAPI.@)
+ */
+static BOOL StartDevice(VOID) { FIXME("Stub"); return TRUE; }
+static BOOL StopDevice(VOID) { FIXME("Stub"); return TRUE; }
+BOOL WINAPI
+SetupDiChangeState(
+    IN HDEVINFO DeviceInfoSet,
+    IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
+{
+    PSP_PROPCHANGE_PARAMS PropChange;
+    HKEY hKey = INVALID_HANDLE_VALUE;
+    LPCWSTR RegistryValueName;
+    DWORD dwConfigFlags, dwLength, dwRegType;
+    LONG rc;
+    BOOL ret = FALSE;
+
+    TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
+
+    if (!DeviceInfoData)
+        PropChange = ((struct DeviceInfoSet *)DeviceInfoSet)->ClassInstallParams.PropChange;
+    else
+        PropChange = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->ClassInstallParams.PropChange;
+    if (!PropChange)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        goto cleanup;
+    }
+
+    if (PropChange->Scope == DICS_FLAG_GLOBAL)
+        RegistryValueName = REGSTR_VAL_CONFIGFLAGS;
+    else
+        RegistryValueName = REGSTR_VAL_CSCONFIGFLAGS;
+
+    switch (PropChange->StateChange)
+    {
+        case DICS_ENABLE:
+        case DICS_DISABLE:
+        {
+            /* Enable/disable device in registry */
+            hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, PropChange->Scope, PropChange->HwProfile, DIREG_DEV, KEY_QUERY_VALUE | KEY_SET_VALUE);
+            if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
+                hKey = SetupDiCreateDevRegKey(DeviceInfoSet, DeviceInfoData, PropChange->Scope, PropChange->HwProfile, DIREG_DEV, NULL, NULL);
+            if (hKey == INVALID_HANDLE_VALUE)
+                break;
+            dwLength = sizeof(DWORD);
+            rc = RegQueryValueExW(
+                hKey,
+                RegistryValueName,
+                NULL,
+                &dwRegType,
+                (LPBYTE)&dwConfigFlags, &dwLength);
+            if (rc == ERROR_FILE_NOT_FOUND)
+                dwConfigFlags = 0;
+            else if (rc != ERROR_SUCCESS)
+            {
+                SetLastError(rc);
+                goto cleanup;
+            }
+            else if (dwRegType != REG_DWORD || dwLength != sizeof(DWORD))
+            {
+                SetLastError(ERROR_GEN_FAILURE);
+                goto cleanup;
+            }
+            if (PropChange->StateChange == DICS_ENABLE)
+                dwConfigFlags &= ~(PropChange->Scope == DICS_FLAG_GLOBAL ? CONFIGFLAG_DISABLED : CSCONFIGFLAG_DISABLED);
+            else
+                dwConfigFlags |= (PropChange->Scope == DICS_FLAG_GLOBAL ? CONFIGFLAG_DISABLED : CSCONFIGFLAG_DISABLED);
+            rc = RegSetValueEx(
+                hKey,
+                RegistryValueName,
+                0,
+                REG_DWORD,
+                (LPBYTE)&dwConfigFlags, sizeof(DWORD));
+            if (rc != ERROR_SUCCESS)
+            {
+                SetLastError(rc);
+                goto cleanup;
+            }
+
+            /* Enable/disable device if needed */
+            if (PropChange->Scope == DICS_FLAG_GLOBAL
+                || PropChange->HwProfile == 0
+                || PropChange->HwProfile == GetCurrentHwProfile(DeviceInfoSet))
+            {
+                if (PropChange->StateChange == DICS_ENABLE)
+                    ret = StartDevice();
+                else
+                    ret = StopDevice();
+            }
+            else
+                ret = TRUE;
+            break;
+        }
+        case DICS_PROPCHANGE:
+        {
+            ret = StopDevice() && StartDevice();
+            break;
+        }
+        default:
+        {
+            FIXME("Unknown StateChange 0x%lx\n", PropChange->StateChange);
+            SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+        }
+    }
+
+cleanup:
+    if (hKey != INVALID_HANDLE_VALUE)
+        RegCloseKey(hKey);
+
+    TRACE("Returning %d\n", ret);
+    return ret;
+}
+
 /***********************************************************************
  *             SetupDiSelectBestCompatDrv (SETUPAPI.@)
  */
@@ -6106,6 +6877,7 @@ SetupDiInstallDevice(
     HKEY hKey = INVALID_HANDLE_VALUE;
     HKEY hClassKey = INVALID_HANDLE_VALUE;
     BOOL NeedtoCopyFile;
+    LARGE_INTEGER fullVersion;
     LONG rc;
     BOOL ret = FALSE; /* Return value */
 
@@ -6218,10 +6990,11 @@ SetupDiInstallDevice(
 
     /* Write information to driver key */
     *pSectionName = UNICODE_NULL;
+    memcpy(&fullVersion, &SelectedDriver->Info.DriverVersion, sizeof(LARGE_INTEGER));
     TRACE("Write information to driver key\n");
     TRACE("DriverDate      : '%u-%u-%u'\n", DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
     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("DriverVersion   : '%u.%u.%u.%u'\n", fullVersion.HighPart >> 16, fullVersion.HighPart & 0xffff, fullVersion.LowPart >> 16, fullVersion.LowPart & 0xffff);
     TRACE("InfPath         : '%S'\n", SelectedDriver->Details.InfFileName);
     TRACE("InfSection      : '%S'\n", SelectedDriver->Details.SectionName);
     TRACE("InfSectionExt   : '%S'\n", &SectionName[wcslen(SelectedDriver->Details.SectionName)]);
@@ -6235,7 +7008,7 @@ SetupDiInstallDevice(
         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", SelectedDriver->Info.DriverVersion & 0xff, (SelectedDriver->Info.DriverVersion >> 8) & 0xff, (SelectedDriver->Info.DriverVersion >> 16) & 0xff, (SelectedDriver->Info.DriverVersion >> 24) & 0xff);
+        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)
@@ -6272,7 +7045,7 @@ SetupDiInstallDevice(
             NULL, 0,
             &RequiredSize);
         if (!Result)
-            goto nextfile;
+            goto nextservice;
         if (RequiredSize > 0)
         {
             /* We got the needed size for the buffer */
@@ -6280,7 +7053,7 @@ SetupDiInstallDevice(
             if (!ServiceName)
             {
                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-                goto nextfile;
+                goto nextservice;
             }
             Result = SetupGetStringFieldW(
                 &ContextService,
@@ -6288,7 +7061,7 @@ SetupDiInstallDevice(
                 ServiceName, RequiredSize,
                 &RequiredSize);
             if (!Result)
-                goto nextfile;
+                goto nextservice;
         }
         Result = SetupGetIntField(
             &ContextService,
@@ -6314,7 +7087,7 @@ SetupDiInstallDevice(
                 Result = TRUE;
             }
             else
-                goto nextfile;
+                goto nextservice;
         }
         if (RequiredSize > 0)
         {
@@ -6323,7 +7096,7 @@ SetupDiInstallDevice(
             if (!ServiceSection)
             {
                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-                goto nextfile;
+                goto nextservice;
             }
             Result = SetupGetStringFieldW(
                 &ContextService,
@@ -6331,7 +7104,7 @@ SetupDiInstallDevice(
                 ServiceSection, RequiredSize,
                 &RequiredSize);
             if (!Result)
-                goto nextfile;
+                goto nextservice;
 
             SetLastError(ERROR_SUCCESS);
             Result = SetupInstallServicesFromInfSectionExW(
@@ -6345,7 +7118,7 @@ SetupDiInstallDevice(
             if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED)
                 RebootRequired = TRUE;
         }
-nextfile:
+nextservice:
         HeapFree(GetProcessHeap(), 0, ServiceName);
         HeapFree(GetProcessHeap(), 0, ServiceSection);
         if (!Result)