Extract some code from devinst.c to new files: devclass.c (device class functions...
authorHervé Poussineau <hpoussin@reactos.org>
Fri, 2 Jun 2006 09:06:05 +0000 (09:06 +0000)
committerHervé Poussineau <hpoussin@reactos.org>
Fri, 2 Jun 2006 09:06:05 +0000 (09:06 +0000)
devinst.c is now 123 Kb instead of 285 Kb.
No code change.

svn path=/trunk/; revision=22172

reactos/dll/win32/setupapi/devclass.c [new file with mode: 0644]
reactos/dll/win32/setupapi/devinst.c
reactos/dll/win32/setupapi/driver.c [new file with mode: 0644]
reactos/dll/win32/setupapi/interface.c [new file with mode: 0644]
reactos/dll/win32/setupapi/misc.c
reactos/dll/win32/setupapi/setupapi.rbuild
reactos/dll/win32/setupapi/setupapi_private.h

diff --git a/reactos/dll/win32/setupapi/devclass.c b/reactos/dll/win32/setupapi/devclass.c
new file mode 100644 (file)
index 0000000..d497908
--- /dev/null
@@ -0,0 +1,2219 @@
+/*
+ * SetupAPI device class-related functions
+ *
+ * Copyright 2000 Andreas Mohr for CodeWeavers
+ *           2005-2006 Hervé Poussineau (hpoussin@reactos.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "setupapi_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
+
+/* Unicode constants */
+static const WCHAR BackSlash[] = {'\\',0};
+static const WCHAR Class[]  = {'C','l','a','s','s',0};
+static const WCHAR ClassGUID[]  = {'C','l','a','s','s','G','U','I','D',0};
+static const WCHAR ClassInstall32[]  = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
+static const WCHAR DotServices[]  = {'.','S','e','r','v','i','c','e','s',0};
+static const WCHAR InterfaceInstall32[]  = {'I','n','t','e','r','f','a','c','e','I','n','s','t','a','l','l','3','2',0};
+static const WCHAR Version[]  = {'V','e','r','s','i','o','n',0};
+
+typedef BOOL
+(WINAPI* PROPERTY_PAGE_PROVIDER) (
+    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);
+
+static BOOL
+PropertyChangeHandler(
+    IN HDEVINFO DeviceInfoSet,
+    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
+    IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
+    IN DWORD ClassInstallParamsSize);
+
+static const 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.@)
+ */
+BOOL WINAPI
+SetupDiBuildClassInfoList(
+    IN DWORD Flags,
+    OUT LPGUID ClassGuidList OPTIONAL,
+    IN DWORD ClassGuidListSize,
+    OUT PDWORD RequiredSize)
+{
+    TRACE("\n");
+    return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
+                                        ClassGuidListSize, RequiredSize,
+                                        NULL, NULL);
+}
+
+/***********************************************************************
+ *              SetupDiBuildClassInfoListExA  (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiBuildClassInfoListExA(
+    IN DWORD Flags,
+    OUT LPGUID ClassGuidList OPTIONAL,
+    IN DWORD ClassGuidListSize,
+    OUT PDWORD RequiredSize,
+    IN PCSTR MachineName OPTIONAL,
+    IN PVOID Reserved)
+{
+    LPWSTR MachineNameW = NULL;
+    BOOL bResult;
+
+    TRACE("\n");
+
+    if (MachineName)
+    {
+        MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
+        if (MachineNameW == NULL) return FALSE;
+    }
+
+    bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
+                                           ClassGuidListSize, RequiredSize,
+                                           MachineNameW, Reserved);
+
+    if (MachineNameW)
+        MyFree(MachineNameW);
+
+    return bResult;
+}
+
+/***********************************************************************
+ *             SetupDiBuildClassInfoListExW  (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiBuildClassInfoListExW(
+    IN DWORD Flags,
+    OUT LPGUID ClassGuidList OPTIONAL,
+    IN DWORD ClassGuidListSize,
+    OUT PDWORD RequiredSize,
+    IN PCWSTR MachineName OPTIONAL,
+    IN PVOID Reserved)
+{
+    WCHAR szKeyName[MAX_GUID_STRING_LEN + 1];
+    HKEY hClassesKey = INVALID_HANDLE_VALUE;
+    HKEY hClassKey = NULL;
+    DWORD dwLength;
+    DWORD dwIndex;
+    LONG lError;
+    DWORD dwGuidListIndex = 0;
+    BOOL ret = FALSE;
+
+    TRACE("0x%lx %p %lu %p %s %p\n", Flags, ClassGuidList,
+        ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved);
+
+    if (RequiredSize != NULL)
+        *RequiredSize = 0;
+
+    hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
+                                            KEY_ENUMERATE_SUB_KEYS,
+                                            DIOCR_INSTALLER,
+                                            MachineName,
+                                            Reserved);
+    if (hClassesKey == INVALID_HANDLE_VALUE)
+        goto cleanup;
+
+    for (dwIndex = 0; ; dwIndex++)
+    {
+        dwLength = MAX_GUID_STRING_LEN + 1;
+        lError = RegEnumKeyExW(hClassesKey,
+                               dwIndex,
+                               szKeyName,
+                               &dwLength,
+                               NULL,
+                               NULL,
+                               NULL,
+                               NULL);
+        TRACE("RegEnumKeyExW() returns %ld\n", lError);
+        if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
+        {
+            TRACE("Key name: %s\n", debugstr_w(szKeyName));
+
+            if (hClassKey != NULL)
+                RegCloseKey(hClassKey);
+            if (RegOpenKeyExW(hClassesKey,
+                              szKeyName,
+                              0,
+                              KEY_QUERY_VALUE,
+                              &hClassKey) != ERROR_SUCCESS)
+            {
+                goto cleanup;
+            }
+
+            if (RegQueryValueExW(hClassKey,
+                                 REGSTR_VAL_NOUSECLASS,
+                                 NULL,
+                                 NULL,
+                                 NULL,
+                                 NULL) == ERROR_SUCCESS)
+            {
+                TRACE("'NoUseClass' value found!\n");
+                continue;
+            }
+
+            if ((Flags & DIBCI_NOINSTALLCLASS) &&
+                (!RegQueryValueExW(hClassKey,
+                                   REGSTR_VAL_NOINSTALLCLASS,
+                                   NULL,
+                                   NULL,
+                                   NULL,
+                                   NULL)))
+            {
+                TRACE("'NoInstallClass' value found!\n");
+                continue;
+            }
+
+            if ((Flags & DIBCI_NODISPLAYCLASS) &&
+                (!RegQueryValueExW(hClassKey,
+                                   REGSTR_VAL_NODISPLAYCLASS,
+                                   NULL,
+                                   NULL,
+                                   NULL,
+                                   NULL)))
+            {
+                TRACE("'NoDisplayClass' value found!\n");
+                continue;
+            }
+
+            TRACE("Guid: %s\n", debugstr_w(szKeyName));
+            if (dwGuidListIndex < ClassGuidListSize)
+            {
+                if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
+                    szKeyName[37] = 0;
+                TRACE("Guid: %s\n", debugstr_w(&szKeyName[1]));
+
+                UuidFromStringW(&szKeyName[1],
+                    &ClassGuidList[dwGuidListIndex]);
+            }
+
+            dwGuidListIndex++;
+        }
+
+        if (lError != ERROR_SUCCESS)
+        break;
+    }
+
+    if (RequiredSize != NULL)
+        *RequiredSize = dwGuidListIndex;
+
+    if (ClassGuidListSize < dwGuidListIndex)
+        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+    else
+        ret = TRUE;
+
+cleanup:
+    if (hClassesKey != INVALID_HANDLE_VALUE)
+        RegCloseKey(hClassesKey);
+    if (hClassKey != NULL)
+        RegCloseKey(hClassKey);
+    return ret;
+}
+
+/***********************************************************************
+ *             SetupDiClassGuidsFromNameA  (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiClassGuidsFromNameA(
+    IN PCSTR ClassName,
+    OUT LPGUID ClassGuidList,
+    IN DWORD ClassGuidListSize,
+    OUT PDWORD RequiredSize)
+{
+  return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
+                                      ClassGuidListSize, RequiredSize,
+                                      NULL, NULL);
+}
+
+/***********************************************************************
+ *             SetupDiClassGuidsFromNameW  (SETUPAPI.@)
+ */
+BOOL WINAPI SetupDiClassGuidsFromNameW(
+        IN PCWSTR ClassName,
+        OUT LPGUID ClassGuidList,
+        IN DWORD ClassGuidListSize,
+        OUT PDWORD RequiredSize)
+{
+  return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
+                                      ClassGuidListSize, RequiredSize,
+                                      NULL, NULL);
+}
+
+/***********************************************************************
+ *             SetupDiClassGuidsFromNameExA  (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiClassGuidsFromNameExA(
+    IN PCSTR ClassName,
+    OUT LPGUID ClassGuidList,
+    IN DWORD ClassGuidListSize,
+    OUT PDWORD RequiredSize,
+    IN PCSTR MachineName OPTIONAL,
+    IN PVOID Reserved)
+{
+    LPWSTR ClassNameW = NULL;
+    LPWSTR MachineNameW = NULL;
+    BOOL bResult;
+
+    TRACE("\n");
+
+    ClassNameW = MultiByteToUnicode(ClassName, CP_ACP);
+    if (ClassNameW == NULL)
+        return FALSE;
+
+    if (MachineNameW)
+    {
+        MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
+        if (MachineNameW == NULL)
+        {
+            MyFree(ClassNameW);
+            return FALSE;
+        }
+    }
+
+    bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
+                                           ClassGuidListSize, RequiredSize,
+                                           MachineNameW, Reserved);
+
+    if (MachineNameW)
+        MyFree(MachineNameW);
+
+    MyFree(ClassNameW);
+
+    return bResult;
+}
+
+/***********************************************************************
+ *             SetupDiClassGuidsFromNameExW  (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiClassGuidsFromNameExW(
+    IN PCWSTR ClassName,
+    OUT LPGUID ClassGuidList,
+    IN DWORD ClassGuidListSize,
+    OUT PDWORD RequiredSize,
+    IN PCWSTR MachineName OPTIONAL,
+    IN PVOID Reserved)
+{
+    WCHAR szKeyName[MAX_GUID_STRING_LEN + 1];
+    WCHAR szClassName[256];
+    HKEY hClassesKey = INVALID_HANDLE_VALUE;
+    HKEY hClassKey = NULL;
+    DWORD dwLength;
+    DWORD dwIndex;
+    LONG lError;
+    DWORD dwGuidListIndex = 0;
+    BOOL ret = FALSE;
+
+    TRACE("%s %p %lu %p %s %p\n", debugstr_w(ClassName), ClassGuidList,
+        ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved);
+
+    if (RequiredSize != NULL)
+        *RequiredSize = 0;
+
+    hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
+                                            KEY_ENUMERATE_SUB_KEYS,
+                                            DIOCR_INSTALLER,
+                                            MachineName,
+                                            Reserved);
+    if (hClassesKey == INVALID_HANDLE_VALUE)
+        goto cleanup;
+
+    for (dwIndex = 0; ; dwIndex++)
+    {
+        dwLength = MAX_GUID_STRING_LEN + 1;
+        lError = RegEnumKeyExW(hClassesKey,
+                               dwIndex,
+                               szKeyName,
+                               &dwLength,
+                               NULL,
+                               NULL,
+                               NULL,
+                               NULL);
+        TRACE("RegEnumKeyExW() returns %ld\n", lError);
+        if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
+        {
+            TRACE("Key name: %s\n", debugstr_w(szKeyName));
+
+            if (hClassKey != NULL)
+                RegCloseKey(hClassKey);
+            if (RegOpenKeyExW(hClassesKey,
+                              szKeyName,
+                              0,
+                              KEY_QUERY_VALUE,
+                              &hClassKey) != ERROR_SUCCESS)
+            {
+                goto cleanup;
+            }
+
+            dwLength = 256 * sizeof(WCHAR);
+            if (RegQueryValueExW(hClassKey,
+                                 Class,
+                                 NULL,
+                                 NULL,
+                                 (LPBYTE)szClassName,
+                                 &dwLength) == ERROR_SUCCESS)
+            {
+                TRACE("Class name: %s\n", debugstr_w(szClassName));
+
+                if (strcmpiW(szClassName, ClassName) == 0)
+                {
+                    TRACE("Found matching class name\n");
+
+                    TRACE("Guid: %s\n", debugstr_w(szKeyName));
+                    if (dwGuidListIndex < ClassGuidListSize)
+                    {
+                        if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
+                            szKeyName[37] = 0;
+                        TRACE("Guid: %s\n", debugstr_w(&szKeyName[1]));
+
+                        UuidFromStringW(&szKeyName[1],
+                            &ClassGuidList[dwGuidListIndex]);
+                    }
+
+                    dwGuidListIndex++;
+                }
+            }
+        }
+
+        if (lError != ERROR_SUCCESS)
+            break;
+    }
+
+    if (RequiredSize != NULL)
+        *RequiredSize = dwGuidListIndex;
+
+    if (ClassGuidListSize < dwGuidListIndex)
+        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+    else
+        ret = TRUE;
+
+cleanup:
+    if (hClassesKey != INVALID_HANDLE_VALUE)
+        RegCloseKey(hClassesKey);
+    if (hClassKey != NULL)
+        RegCloseKey(hClassKey);
+    return ret;
+}
+
+/***********************************************************************
+ *              SetupDiClassNameFromGuidA  (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiClassNameFromGuidA(
+    IN CONST GUID* ClassGuid,
+    OUT PSTR ClassName,
+    IN DWORD ClassNameSize,
+    OUT PDWORD RequiredSize OPTIONAL)
+{
+  return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
+                                     ClassNameSize, RequiredSize,
+                                     NULL, NULL);
+}
+
+/***********************************************************************
+ *              SetupDiClassNameFromGuidW  (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiClassNameFromGuidW(
+    IN CONST GUID* ClassGuid,
+    OUT PWSTR ClassName,
+    IN DWORD ClassNameSize,
+    OUT PDWORD RequiredSize OPTIONAL)
+{
+  return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
+                                     ClassNameSize, RequiredSize,
+                                     NULL, NULL);
+}
+
+/***********************************************************************
+ *              SetupDiClassNameFromGuidExA  (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiClassNameFromGuidExA(
+    IN CONST GUID* ClassGuid,
+    OUT PSTR ClassName,
+    IN DWORD ClassNameSize,
+    OUT PDWORD RequiredSize OPTIONAL,
+    IN PCSTR MachineName OPTIONAL,
+    IN PVOID Reserved)
+{
+    WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
+    LPWSTR MachineNameW = NULL;
+    BOOL ret;
+
+    if (MachineName)
+        MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
+    ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
+        NULL, MachineNameW, Reserved);
+    if (ret)
+    {
+        int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
+         ClassNameSize, NULL, NULL);
+
+        if (!ClassNameSize && RequiredSize)
+            *RequiredSize = len;
+    }
+    MyFree(MachineNameW);
+    return ret;
+}
+
+/***********************************************************************
+ *             SetupDiClassNameFromGuidExW  (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiClassNameFromGuidExW(
+    IN CONST GUID* ClassGuid,
+    OUT PWSTR ClassName,
+    IN DWORD ClassNameSize,
+    OUT PDWORD RequiredSize OPTIONAL,
+    IN PCWSTR MachineName OPTIONAL,
+    IN PVOID Reserved)
+{
+    HKEY hKey;
+    DWORD dwLength;
+    LONG rc;
+    BOOL ret = FALSE;
+
+    TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassName,
+        ClassNameSize, RequiredSize, debugstr_w(MachineName), Reserved);
+
+    hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
+                                     KEY_QUERY_VALUE,
+                                     DIOCR_INSTALLER,
+                                     MachineName,
+                                     Reserved);
+    if (hKey == INVALID_HANDLE_VALUE)
+        goto cleanup;
+
+    if (RequiredSize != NULL)
+    {
+        dwLength = 0;
+        rc = RegQueryValueExW(hKey,
+                              Class,
+                              NULL,
+                              NULL,
+                              NULL,
+                              &dwLength);
+        if (rc != ERROR_SUCCESS)
+        {
+            SetLastError(rc);
+            goto cleanup;
+        }
+
+        *RequiredSize = dwLength / sizeof(WCHAR);
+    }
+
+    dwLength = ClassNameSize * sizeof(WCHAR);
+    rc = RegQueryValueExW(hKey,
+                          Class,
+                          NULL,
+                          NULL,
+                          (LPBYTE)ClassName,
+                          &dwLength);
+    if (rc != ERROR_SUCCESS)
+    {
+        SetLastError(rc);
+        goto cleanup;
+    }
+
+    ret = TRUE;
+
+cleanup:
+    if (hKey != INVALID_HANDLE_VALUE)
+        RegCloseKey(hKey);
+    return ret;
+}
+
+/***********************************************************************
+ *             SetupDiGetClassDescriptionA  (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiGetClassDescriptionA(
+    IN CONST GUID *ClassGuid,
+    OUT PSTR ClassDescription,
+    IN DWORD ClassDescriptionSize,
+    OUT PDWORD RequiredSize OPTIONAL)
+{
+  return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
+                                       ClassDescriptionSize,
+                                       RequiredSize, NULL, NULL);
+}
+
+/***********************************************************************
+ *             SetupDiGetClassDescriptionW  (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiGetClassDescriptionW(
+    IN CONST GUID *ClassGuid,
+    OUT PWSTR ClassDescription,
+    IN DWORD ClassDescriptionSize,
+    OUT PDWORD RequiredSize OPTIONAL)
+{
+  return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
+                                       ClassDescriptionSize,
+                                       RequiredSize, NULL, NULL);
+}
+
+/***********************************************************************
+ *             SetupDiGetClassDescriptionExA  (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiGetClassDescriptionExA(
+    IN CONST GUID *ClassGuid,
+    OUT PSTR ClassDescription,
+    IN DWORD ClassDescriptionSize,
+    OUT PDWORD RequiredSize OPTIONAL,
+    IN PCSTR MachineName OPTIONAL,
+    IN PVOID Reserved)
+{
+    PWCHAR ClassDescriptionW;
+    LPWSTR MachineNameW = NULL;
+    BOOL ret;
+
+    TRACE("\n");
+    if (ClassDescriptionSize > 0)
+    {
+        ClassDescriptionW = HeapAlloc(GetProcessHeap(), 0, ClassDescriptionSize * sizeof(WCHAR));
+        if (!ClassDescriptionW)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            ret = FALSE;
+            goto end;
+        }
+    }
+    else
+        ClassDescriptionW = NULL;
+
+    if (MachineName)
+    {
+        MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
+        if (!MachineNameW)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            ret = FALSE;
+            goto end;
+        }
+    }
+
+    ret = SetupDiGetClassDescriptionExW(ClassGuid, ClassDescriptionW, ClassDescriptionSize * sizeof(WCHAR),
+     NULL, MachineNameW, Reserved);
+    if (ret)
+    {
+        int len = WideCharToMultiByte(CP_ACP, 0, ClassDescriptionW, -1, ClassDescription,
+         ClassDescriptionSize, NULL, NULL);
+
+        if (!ClassDescriptionSize && RequiredSize)
+            *RequiredSize = len;
+    }
+
+end:
+    HeapFree(GetProcessHeap(), 0, ClassDescriptionW);
+    MyFree(MachineNameW);
+    return ret;
+}
+
+/***********************************************************************
+ *             SetupDiGetClassDescriptionExW  (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiGetClassDescriptionExW(
+    IN CONST GUID *ClassGuid,
+    OUT PWSTR ClassDescription,
+    IN DWORD ClassDescriptionSize,
+    OUT PDWORD RequiredSize OPTIONAL,
+    IN PCWSTR MachineName OPTIONAL,
+    IN PVOID Reserved)
+{
+    HKEY hKey = INVALID_HANDLE_VALUE;
+    DWORD dwLength;
+    BOOL ret = FALSE;
+
+    TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassDescription,
+        ClassDescriptionSize, RequiredSize, debugstr_w(MachineName), Reserved);
+
+    hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
+                                     KEY_QUERY_VALUE,
+                                     DIOCR_INSTALLER,
+                                     MachineName,
+                                     Reserved);
+    if (hKey == INVALID_HANDLE_VALUE)
+    {
+        WARN("SetupDiOpenClassRegKeyExW() failed (Error %lu)\n", GetLastError());
+        goto cleanup;
+    }
+
+    if (RequiredSize != NULL)
+    {
+        dwLength = 0;
+        if (RegQueryValueExW(hKey,
+                             NULL,
+                             NULL,
+                             NULL,
+                             NULL,
+                             &dwLength) != ERROR_SUCCESS)
+        {
+            goto cleanup;
+        }
+
+        *RequiredSize = dwLength / sizeof(WCHAR);
+    }
+
+    dwLength = ClassDescriptionSize * sizeof(WCHAR);
+    if (RegQueryValueExW(hKey,
+                         NULL,
+                         NULL,
+                         NULL,
+                         (LPBYTE)ClassDescription,
+                         &dwLength) != ERROR_SUCCESS)
+    {
+        goto cleanup;
+    }
+
+    ret = TRUE;
+
+cleanup:
+    if (hKey != INVALID_HANDLE_VALUE)
+        RegCloseKey(hKey);
+
+    return ret;
+}
+
+/***********************************************************************
+ *             SetupDiGetClassDevsA (SETUPAPI.@)
+ */
+HDEVINFO WINAPI
+SetupDiGetClassDevsA(
+    IN CONST GUID *ClassGuid OPTIONAL,
+    IN PCSTR Enumerator OPTIONAL,
+    IN HWND hwndParent OPTIONAL,
+    IN DWORD Flags)
+{
+    return SetupDiGetClassDevsExA(ClassGuid, Enumerator, hwndParent,
+                                  Flags, NULL, NULL, NULL);
+}
+
+/***********************************************************************
+ *             SetupDiGetClassDevsW (SETUPAPI.@)
+ */
+HDEVINFO WINAPI
+SetupDiGetClassDevsW(
+    IN CONST GUID *ClassGuid OPTIONAL,
+    IN PCWSTR Enumerator OPTIONAL,
+    IN HWND hwndParent OPTIONAL,
+    IN DWORD Flags)
+{
+    return SetupDiGetClassDevsExW(ClassGuid, Enumerator, hwndParent,
+                                  Flags, NULL, NULL, NULL);
+}
+
+/***********************************************************************
+ *             SetupDiGetClassDevsExA (SETUPAPI.@)
+ */
+HDEVINFO WINAPI
+SetupDiGetClassDevsExA(
+    IN CONST GUID *ClassGuid OPTIONAL,
+    IN PCSTR Enumerator OPTIONAL,
+    IN HWND hwndParent OPTIONAL,
+    IN DWORD Flags,
+    IN HDEVINFO DeviceInfoSet OPTIONAL,
+    IN PCSTR MachineName OPTIONAL,
+    IN PVOID Reserved)
+{
+    HDEVINFO ret;
+    LPWSTR enumstrW = NULL;
+    LPWSTR machineW = NULL;
+
+    if (Enumerator)
+    {
+        int len = MultiByteToWideChar(CP_ACP, 0, Enumerator, -1, NULL, 0);
+        enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        if (!enumstrW)
+        {
+            ret = (HDEVINFO)INVALID_HANDLE_VALUE;
+            goto end;
+        }
+        MultiByteToWideChar(CP_ACP, 0, Enumerator, -1, enumstrW, len);
+    }
+    if (MachineName)
+    {
+        int len = MultiByteToWideChar(CP_ACP, 0, MachineName, -1, NULL, 0);
+        machineW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        if (!machineW)
+        {
+            ret = (HDEVINFO)INVALID_HANDLE_VALUE;
+            goto end;
+        }
+        MultiByteToWideChar(CP_ACP, 0, MachineName, -1, machineW, len);
+    }
+    ret = SetupDiGetClassDevsExW(ClassGuid, enumstrW, hwndParent, Flags, DeviceInfoSet, machineW, Reserved);
+
+end:
+    HeapFree(GetProcessHeap(), 0, enumstrW);
+    HeapFree(GetProcessHeap(), 0, machineW);
+    return ret;
+}
+
+/***********************************************************************
+ *             Helper functions for SetupDiGetClassDevsExW
+ */
+static LONG
+SETUP_CreateDevListFromEnumerator(
+    struct DeviceInfoSet *list,
+    CONST GUID *pClassGuid OPTIONAL,
+    LPCWSTR Enumerator,
+    HKEY hEnumeratorKey) /* handle to Enumerator registry key */
+{
+    HKEY hDeviceIdKey = NULL, hInstanceIdKey;
+    WCHAR KeyBuffer[MAX_PATH];
+    WCHAR InstancePath[MAX_PATH];
+    LPWSTR pEndOfInstancePath; /* Pointer into InstancePath buffer */
+    struct DeviceInfoElement *deviceInfo;
+    DWORD i = 0, j;
+    DWORD dwLength, dwRegType;
+    DWORD rc;
+
+    /* Enumerate device IDs (subkeys of hEnumeratorKey) */
+    while (TRUE)
+    {
+        dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
+        rc = RegEnumKeyExW(hEnumeratorKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
+        if (rc == ERROR_NO_MORE_ITEMS)
+            break;
+        if (rc != ERROR_SUCCESS)
+            goto cleanup;
+        i++;
+
+        /* Open device id sub key */
+        if (hDeviceIdKey != NULL)
+            RegCloseKey(hDeviceIdKey);
+        rc = RegOpenKeyExW(hEnumeratorKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hDeviceIdKey);
+        if (rc != ERROR_SUCCESS)
+            goto cleanup;
+        strcpyW(InstancePath, Enumerator);
+        strcatW(InstancePath, BackSlash);
+        strcatW(InstancePath, KeyBuffer);
+        strcatW(InstancePath, BackSlash);
+        pEndOfInstancePath = &InstancePath[strlenW(InstancePath)];
+
+        /* Enumerate instance IDs (subkeys of hDeviceIdKey) */
+        j = 0;
+        while (TRUE)
+        {
+            GUID KeyGuid;
+
+            dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
+            rc = RegEnumKeyExW(hDeviceIdKey, j, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
+            if (rc == ERROR_NO_MORE_ITEMS)
+                break;
+            if (rc != ERROR_SUCCESS)
+                goto cleanup;
+            j++;
+
+            /* Open instance id sub key */
+            rc = RegOpenKeyExW(hDeviceIdKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hInstanceIdKey);
+            if (rc != ERROR_SUCCESS)
+                goto cleanup;
+            *pEndOfInstancePath = '\0';
+            strcatW(InstancePath, KeyBuffer);
+
+            /* Read ClassGUID value */
+            dwLength = sizeof(KeyBuffer) - sizeof(WCHAR);
+            rc = RegQueryValueExW(hInstanceIdKey, ClassGUID, NULL, &dwRegType, (LPBYTE)KeyBuffer, &dwLength);
+            RegCloseKey(hInstanceIdKey);
+            if (rc == ERROR_FILE_NOT_FOUND)
+            {
+                if (pClassGuid)
+                    /* Skip this bad entry as we can't verify it */
+                    continue;
+                /* Set a default GUID for this device */
+                memcpy(&KeyGuid, &GUID_NULL, sizeof(GUID));
+            }
+            else if (rc != ERROR_SUCCESS)
+            {
+                goto cleanup;
+            }
+            else if (dwRegType != REG_SZ)
+            {
+                rc = ERROR_GEN_FAILURE;
+                goto cleanup;
+            }
+            else
+            {
+                KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */
+                if (UuidFromStringW(&KeyBuffer[1], &KeyGuid) != RPC_S_OK)
+                    /* Bad GUID, skip the entry */
+                    continue;
+            }
+
+            if (pClassGuid && !IsEqualIID(&KeyGuid, pClassGuid))
+            {
+                /* Skip this entry as it is not the right device class */
+                continue;
+            }
+
+            /* Add the entry to the list */
+            if (!CreateDeviceInfoElement(list, InstancePath, &KeyGuid, &deviceInfo))
+            {
+                rc = GetLastError();
+                goto cleanup;
+            }
+            TRACE("Adding '%s' to device info set %p\n", debugstr_w(InstancePath), list);
+            InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
+        }
+    }
+
+    rc = ERROR_SUCCESS;
+
+cleanup:
+    if (hDeviceIdKey != NULL)
+        RegCloseKey(hDeviceIdKey);
+    return rc;
+}
+
+static LONG
+SETUP_CreateDevList(
+    struct DeviceInfoSet *list,
+    PCWSTR MachineName OPTIONAL,
+    CONST GUID *class OPTIONAL,
+    PCWSTR Enumerator OPTIONAL)
+{
+    HKEY HKLM = HKEY_LOCAL_MACHINE;
+    HKEY hEnumKey = NULL;
+    HKEY hEnumeratorKey = NULL;
+    WCHAR KeyBuffer[MAX_PATH];
+    DWORD i;
+    DWORD dwLength;
+    DWORD rc;
+
+    if (class && IsEqualIID(class, &GUID_NULL))
+        class = NULL;
+
+    /* Open Enum key (if applicable) */
+    if (MachineName != NULL)
+    {
+        rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
+        if (rc != ERROR_SUCCESS)
+            goto cleanup;
+    }
+
+    rc = RegOpenKeyExW(
+        HKLM,
+        REGSTR_PATH_SYSTEMENUM,
+        0,
+        KEY_ENUMERATE_SUB_KEYS,
+        &hEnumKey);
+    if (rc != ERROR_SUCCESS)
+        goto cleanup;
+
+    /* If enumerator is provided, call directly SETUP_CreateDevListFromEnumerator.
+     * Else, enumerate all enumerators and call SETUP_CreateDevListFromEnumerator
+     * for each one.
+     */
+    if (Enumerator)
+    {
+        rc = RegOpenKeyExW(
+            hEnumKey,
+            Enumerator,
+            0,
+            KEY_ENUMERATE_SUB_KEYS,
+            &hEnumeratorKey);
+        if (rc != ERROR_SUCCESS)
+            goto cleanup;
+        rc = SETUP_CreateDevListFromEnumerator(list, class, Enumerator, hEnumeratorKey);
+    }
+    else
+    {
+        /* Enumerate enumerators */
+        i = 0;
+        while (TRUE)
+        {
+            dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
+            rc = RegEnumKeyExW(hEnumKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
+            if (rc == ERROR_NO_MORE_ITEMS)
+                break;
+            else if (rc != ERROR_SUCCESS)
+                goto cleanup;
+            i++;
+
+            /* Open sub key */
+            if (hEnumeratorKey != NULL)
+                RegCloseKey(hEnumeratorKey);
+            rc = RegOpenKeyExW(hEnumKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hEnumeratorKey);
+            if (rc != ERROR_SUCCESS)
+                goto cleanup;
+
+            /* Call SETUP_CreateDevListFromEnumerator */
+            rc = SETUP_CreateDevListFromEnumerator(list, class, KeyBuffer, hEnumeratorKey);
+            if (rc != ERROR_SUCCESS)
+                goto cleanup;
+        }
+        rc = ERROR_SUCCESS;
+    }
+
+cleanup:
+    if (HKLM != HKEY_LOCAL_MACHINE)
+        RegCloseKey(HKLM);
+    if (hEnumKey != NULL)
+        RegCloseKey(hEnumKey);
+    if (hEnumeratorKey != NULL)
+        RegCloseKey(hEnumeratorKey);
+    return rc;
+}
+
+/***********************************************************************
+ *             SetupDiGetClassDevsExW (SETUPAPI.@)
+ */
+HDEVINFO WINAPI
+SetupDiGetClassDevsExW(
+    IN CONST GUID *ClassGuid OPTIONAL,
+    IN PCWSTR Enumerator OPTIONAL,
+    IN HWND hwndParent OPTIONAL,
+    IN DWORD Flags,
+    IN HDEVINFO DeviceInfoSet OPTIONAL,
+    IN PCWSTR MachineName OPTIONAL,
+    IN PVOID Reserved)
+{
+    HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
+    struct DeviceInfoSet *list;
+    CONST GUID *pClassGuid;
+    LONG rc;
+    HDEVINFO ret = INVALID_HANDLE_VALUE;
+
+    TRACE("%s %s %p 0x%08lx %p %s %p\n", debugstr_guid(ClassGuid), debugstr_w(Enumerator),
+        hwndParent, Flags, DeviceInfoSet, debugstr_w(MachineName), Reserved);
+
+    /* Create the deviceset if not set */
+    if (DeviceInfoSet)
+    {
+        list = (struct DeviceInfoSet *)DeviceInfoSet;
+        if (list->magic != SETUP_DEV_INFO_SET_MAGIC)
+        {
+            SetLastError(ERROR_INVALID_HANDLE);
+            goto cleanup;
+        }
+        hDeviceInfo = DeviceInfoSet;
+    }
+    else
+    {
+         hDeviceInfo = SetupDiCreateDeviceInfoListExW(
+             Flags & DIGCF_DEVICEINTERFACE ? NULL : ClassGuid,
+             NULL, MachineName, NULL);
+         if (hDeviceInfo == INVALID_HANDLE_VALUE)
+             goto cleanup;
+         list = (struct DeviceInfoSet *)hDeviceInfo;
+    }
+
+    if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
+        pClassGuid = NULL;
+    else
+        pClassGuid = &list->ClassGuid;
+
+    if (Flags & DIGCF_PROFILE)
+        FIXME(": flag DIGCF_PROFILE ignored\n");
+
+    if (Flags & DIGCF_ALLCLASSES)
+    {
+        rc = SETUP_CreateDevList(list, MachineName, pClassGuid, Enumerator);
+        if (rc != ERROR_SUCCESS)
+        {
+            SetLastError(rc);
+            goto cleanup;
+        }
+        ret = hDeviceInfo;
+    }
+    else if (Flags & DIGCF_DEVICEINTERFACE)
+    {
+        if (ClassGuid == NULL)
+        {
+            SetLastError(ERROR_INVALID_PARAMETER);
+            goto cleanup;
+        }
+
+        rc = SETUP_CreateInterfaceList(list, MachineName, ClassGuid, Enumerator, Flags & DIGCF_PRESENT);
+        if (rc != ERROR_SUCCESS)
+        {
+            SetLastError(rc);
+            goto cleanup;
+        }
+        ret = hDeviceInfo;
+    }
+    else
+    {
+        rc = SETUP_CreateDevList(list, MachineName, ClassGuid, Enumerator);
+        if (rc != ERROR_SUCCESS)
+        {
+            SetLastError(rc);
+            goto cleanup;
+        }
+        ret = hDeviceInfo;
+    }
+
+cleanup:
+    if (!DeviceInfoSet && hDeviceInfo != INVALID_HANDLE_VALUE && hDeviceInfo != ret)
+        SetupDiDestroyDeviceInfoList(hDeviceInfo);
+    return ret;
+}
+
+/***********************************************************************
+ *             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, REGSTR_VAL_INSICON, 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, REGSTR_VAL_INSICON, 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 += (strlenW(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 = (ULONG_PTR)list;
+        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, REGSTR_VAL_INSTALLER_32, 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, REGSTR_VAL_INSTALLER_32, 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, REGSTR_VAL_ENUMPROPPAGES_32, 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, REGSTR_VAL_ENUMPROPPAGES_32, 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;
+}
+
+/***********************************************************************
+ *             SetupDiInstallClassA (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiInstallClassA(
+    IN HWND hwndParent OPTIONAL,
+    IN PCSTR InfFileName,
+    IN DWORD Flags,
+    IN HSPFILEQ FileQueue OPTIONAL)
+{
+    return SetupDiInstallClassExA(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
+}
+
+/***********************************************************************
+ *             SetupDiInstallClassW (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiInstallClassW(
+    IN HWND hwndParent OPTIONAL,
+    IN PCWSTR InfFileName,
+    IN DWORD Flags,
+    IN HSPFILEQ FileQueue OPTIONAL)
+{
+    return SetupDiInstallClassExW(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
+}
+
+/***********************************************************************
+ *             SetupDiInstallClassExA (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiInstallClassExA(
+    IN HWND hwndParent OPTIONAL,
+    IN PCSTR InfFileName OPTIONAL,
+    IN DWORD Flags,
+    IN HSPFILEQ FileQueue OPTIONAL,
+    IN CONST GUID *InterfaceClassGuid OPTIONAL,
+    IN PVOID Reserved1,
+    IN PVOID Reserved2)
+{
+    PWSTR InfFileNameW = NULL;
+    BOOL Result;
+
+    if (InfFileName)
+    {
+        InfFileNameW = MultiByteToUnicode(InfFileName, CP_ACP);
+        if (InfFileNameW == NULL)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            return FALSE;
+        }
+    }
+
+    Result = SetupDiInstallClassExW(hwndParent, InfFileNameW, Flags,
+        FileQueue, InterfaceClassGuid, Reserved1, Reserved2);
+
+    MyFree(InfFileNameW);
+
+    return Result;
+}
+
+/***********************************************************************
+ *             Helper function for SetupDiInstallClassExW
+ */
+static HKEY
+CreateClassKey(HINF hInf)
+{
+    WCHAR FullBuffer[MAX_PATH];
+    WCHAR Buffer[MAX_PATH];
+    DWORD RequiredSize;
+    HKEY hClassKey = NULL;
+    HKEY ret = INVALID_HANDLE_VALUE;
+
+    FullBuffer[0] = '\0';
+    Buffer[0] = '\\';
+    if (!SetupGetLineTextW(NULL,
+                           hInf,
+                           Version,
+                           ClassGUID,
+                           &Buffer[1],
+                           MAX_PATH - 1,
+                           &RequiredSize))
+    {
+        goto cleanup;
+    }
+
+    lstrcpyW(FullBuffer, REGSTR_PATH_CLASS_NT);
+    lstrcatW(FullBuffer, Buffer);
+
+    if (!SetupGetLineTextW(NULL,
+                           hInf,
+                           Version,
+                           Class,
+                           Buffer,
+                           MAX_PATH,
+                           &RequiredSize))
+    {
+        RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
+        goto cleanup;
+    }
+
+    if (ERROR_SUCCESS != RegCreateKeyExW(HKEY_LOCAL_MACHINE,
+                                         FullBuffer,
+                                         0,
+                                         NULL,
+                                         REG_OPTION_NON_VOLATILE,
+                                         KEY_SET_VALUE,
+                                         NULL,
+                                         &hClassKey,
+                                         NULL))
+    {
+        goto cleanup;
+    }
+
+    if (ERROR_SUCCESS != RegSetValueExW(hClassKey,
+                                        Class,
+                                        0,
+                                        REG_SZ,
+                                        (LPBYTE)Buffer,
+                                        RequiredSize * sizeof(WCHAR)))
+    {
+        goto cleanup;
+    }
+
+    ret = hClassKey;
+
+cleanup:
+    if (hClassKey != NULL && hClassKey != ret)
+        RegCloseKey(hClassKey);
+    if (ret == INVALID_HANDLE_VALUE && FullBuffer[0] != '\0')
+        RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
+    return ret;
+}
+
+/***********************************************************************
+ *             SetupDiInstallClassExW (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiInstallClassExW(
+    IN HWND hwndParent OPTIONAL,
+    IN PCWSTR InfFileName OPTIONAL,
+    IN DWORD Flags,
+    IN HSPFILEQ FileQueue OPTIONAL,
+    IN CONST GUID *InterfaceClassGuid OPTIONAL,
+    IN PVOID Reserved1,
+    IN PVOID Reserved2)
+{
+    BOOL ret = FALSE;
+
+    TRACE("%p %s 0x%lx %p %s %p %p\n", hwndParent, debugstr_w(InfFileName), Flags,
+        FileQueue, debugstr_guid(InterfaceClassGuid), Reserved1, Reserved2);
+
+    if (!InfFileName)
+    {
+        FIXME("Case not implemented: InfFileName NULL\n");
+        SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    }
+    else if (Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL))
+    {
+        TRACE("Unknown flags: 0x%08lx\n", Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL));
+        SetLastError(ERROR_INVALID_FLAGS);
+    }
+    else if ((Flags & DI_NOVCP) && FileQueue == NULL)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (Reserved1 != NULL)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (Reserved2 != NULL)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else
+    {
+        HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
+        SP_DEVINSTALL_PARAMS_W InstallParams;
+        WCHAR SectionName[MAX_PATH];
+        HINF hInf = INVALID_HANDLE_VALUE;
+        HKEY hRootKey = INVALID_HANDLE_VALUE;
+        PVOID callback_context = NULL;
+
+        hDeviceInfo = SetupDiCreateDeviceInfoList(NULL, NULL);
+
+        InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+        if (!SetupDiGetDeviceInstallParamsW(hDeviceInfo, NULL, &InstallParams))
+            goto cleanup;
+        InstallParams.Flags &= ~(DI_NOVCP | DI_NOBROWSE | DI_QUIETINSTALL);
+        InstallParams.Flags |= Flags & (DI_NOVCP | DI_NOBROWSE | DI_QUIETINSTALL);
+        if (Flags & DI_NOVCP)
+            InstallParams.FileQueue = FileQueue;
+        if (!SetupDiSetDeviceInstallParamsW(hDeviceInfo, NULL, &InstallParams))
+            goto cleanup;
+
+        /* Open the .inf file */
+        hInf = SetupOpenInfFileW(
+            InfFileName,
+            NULL,
+            INF_STYLE_WIN4,
+            NULL);
+        if (hInf == INVALID_HANDLE_VALUE)
+            goto cleanup;
+
+        /* Try to append a layout file */
+        ret = SetupOpenAppendInfFileW(NULL, hInf, NULL);
+        if (!ret)
+            goto cleanup;
+
+        if (InterfaceClassGuid)
+        {
+            /* Retrieve the actual section name */
+            ret = SetupDiGetActualSectionToInstallW(
+                hInf,
+                InterfaceInstall32,
+                SectionName,
+                MAX_PATH,
+                NULL,
+                NULL);
+            if (!ret)
+                goto cleanup;
+
+            /* Open registry key related to this interface */
+            /* FIXME: What happens if the key doesn't exist? */
+            hRootKey = SetupDiOpenClassRegKeyExW(InterfaceClassGuid, KEY_ENUMERATE_SUB_KEYS, DIOCR_INTERFACE, NULL, NULL);
+            if (hRootKey == INVALID_HANDLE_VALUE)
+                goto cleanup;
+
+            /* SetupDiCreateDeviceInterface??? */
+            FIXME("Installing an interface is not implemented\n");
+            SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+        }
+        else
+        {
+            /* Create or open the class registry key 'HKLM\CurrentControlSet\Class\{GUID}' */
+            hRootKey = CreateClassKey(hInf);
+            if (hRootKey == INVALID_HANDLE_VALUE)
+                goto cleanup;
+
+            /* Retrieve the actual section name */
+            ret = SetupDiGetActualSectionToInstallW(
+                hInf,
+                ClassInstall32,
+                SectionName,
+                MAX_PATH - strlenW(DotServices),
+                NULL,
+                NULL);
+            if (!ret)
+                goto cleanup;
+
+            callback_context = SetupInitDefaultQueueCallback(hwndParent);
+            if (!callback_context)
+                goto cleanup;
+
+            ret = SetupInstallFromInfSectionW(
+                hwndParent,
+                hInf,
+                SectionName,
+                SPINST_REGISTRY | SPINST_FILES | SPINST_BITREG | SPINST_INIFILES | SPINST_INI2REG,
+                hRootKey,
+                NULL, /* FIXME: SourceRootPath */
+                !(Flags & DI_NOVCP) && (Flags & DI_FORCECOPY) ? SP_COPY_FORCE_IN_USE : 0, /* CopyFlags */
+                SetupDefaultQueueCallbackW,
+                callback_context,
+                hDeviceInfo,
+                NULL);
+            if (!ret)
+                goto cleanup;
+
+            /* Install .Services section */
+            lstrcatW(SectionName, DotServices);
+            ret = SetupInstallServicesFromInfSectionExW(
+                hInf,
+                SectionName,
+                0,
+                hDeviceInfo,
+                NULL,
+                NULL,
+                NULL);
+            if (!ret)
+                goto cleanup;
+
+            ret = TRUE;
+        }
+
+cleanup:
+        if (hDeviceInfo != INVALID_HANDLE_VALUE)
+            SetupDiDestroyDeviceInfoList(hDeviceInfo);
+        if (hInf != INVALID_HANDLE_VALUE)
+            SetupCloseInfFile(hInf);
+        if (hRootKey != INVALID_HANDLE_VALUE)
+            RegCloseKey(hRootKey);
+        SetupTermDefaultQueueCallback(callback_context);
+    }
+
+    TRACE("Returning %d\n", ret);
+    return ret;
+}
+
+/***********************************************************************
+ *             SetupDiOpenClassRegKey  (SETUPAPI.@)
+ */
+HKEY WINAPI
+SetupDiOpenClassRegKey(
+    IN CONST GUID *ClassGuid OPTIONAL,
+    IN REGSAM samDesired)
+{
+    return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
+                                     DIOCR_INSTALLER, NULL, NULL);
+}
+
+/***********************************************************************
+ *             SetupDiOpenClassRegKeyExA  (SETUPAPI.@)
+ */
+HKEY WINAPI
+SetupDiOpenClassRegKeyExA(
+    IN CONST GUID *ClassGuid OPTIONAL,
+    IN REGSAM samDesired,
+    IN DWORD Flags,
+    IN PCSTR MachineName OPTIONAL,
+    IN PVOID Reserved)
+{
+    PWSTR MachineNameW = NULL;
+    HKEY hKey;
+
+    TRACE("\n");
+
+    if (MachineName)
+    {
+        MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
+        if (MachineNameW == NULL)
+            return INVALID_HANDLE_VALUE;
+    }
+
+    hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
+                                     Flags, MachineNameW, Reserved);
+
+    if (MachineNameW)
+        MyFree(MachineNameW);
+
+    return hKey;
+}
+
+/***********************************************************************
+ *             SetupDiOpenClassRegKeyExW  (SETUPAPI.@)
+ */
+HKEY WINAPI
+SetupDiOpenClassRegKeyExW(
+    IN CONST GUID* ClassGuid OPTIONAL,
+    IN REGSAM samDesired,
+    IN DWORD Flags,
+    IN PCWSTR MachineName OPTIONAL,
+    IN PVOID Reserved)
+{
+    LPWSTR lpGuidString = NULL;
+    LPWSTR lpFullGuidString = NULL;
+    DWORD dwLength;
+    HKEY HKLM;
+    HKEY hClassesKey = NULL;
+    HKEY hClassKey = NULL;
+    HKEY ret = INVALID_HANDLE_VALUE;
+    DWORD rc;
+    LPCWSTR lpKeyName;
+
+    TRACE("%s 0x%lx 0x%lx %s %p\n", debugstr_guid(ClassGuid), samDesired,
+        Flags, debugstr_w(MachineName), Reserved);
+
+    if (Flags == DIOCR_INSTALLER)
+        lpKeyName = REGSTR_PATH_CLASS_NT;
+    else if (Flags == DIOCR_INTERFACE)
+        lpKeyName = REGSTR_PATH_DEVICE_CLASSES;
+    else
+    {
+        ERR("Invalid Flags parameter!\n");
+        SetLastError(ERROR_INVALID_FLAGS);
+        goto cleanup;
+    }
+
+    if (MachineName != NULL)
+    {
+        rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
+        if (rc != ERROR_SUCCESS)
+        {
+            SetLastError(rc);
+            goto cleanup;
+        }
+    }
+    else
+        HKLM = HKEY_LOCAL_MACHINE;
+
+    rc = RegOpenKeyExW(HKLM,
+                      lpKeyName,
+                      0,
+                      ClassGuid ? 0 : samDesired,
+                      &hClassesKey);
+    if (MachineName != NULL) RegCloseKey(HKLM);
+    if (rc != ERROR_SUCCESS)
+    {
+        SetLastError(rc);
+        goto cleanup;
+    }
+
+    if (ClassGuid == NULL)
+    {
+        /* Stop here. We don't need to open a subkey */
+        ret = hClassesKey;
+        goto cleanup;
+    }
+
+    if (UuidToStringW((UUID*)ClassGuid, &lpGuidString) != RPC_S_OK)
+    {
+        SetLastError(ERROR_GEN_FAILURE);
+        goto cleanup;
+    }
+
+    dwLength = lstrlenW(lpGuidString);
+    lpFullGuidString = HeapAlloc(GetProcessHeap(), 0, (dwLength + 3) * sizeof(WCHAR));
+    if (!lpFullGuidString)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        goto cleanup;
+    }
+    lpFullGuidString[0] = '{';
+    memcpy(&lpFullGuidString[1], lpGuidString, dwLength * sizeof(WCHAR));
+    lpFullGuidString[dwLength + 1] = '}';
+    lpFullGuidString[dwLength + 2] = '\0';
+
+    rc = RegOpenKeyExW(hClassesKey,
+                       lpFullGuidString,
+                       0,
+                       samDesired,
+                       &hClassKey);
+    if (rc != ERROR_SUCCESS)
+    {
+        SetLastError(rc);
+        goto cleanup;
+    }
+    ret = hClassKey;
+
+cleanup:
+    if (hClassKey != NULL && hClassKey != ret)
+        RegCloseKey(hClassKey);
+    if (hClassesKey != NULL && hClassesKey != ret)
+        RegCloseKey(hClassesKey);
+    if (lpGuidString)
+        RpcStringFreeW(&lpGuidString);
+    HeapFree(GetProcessHeap(), 0, lpFullGuidString);
+
+    return ret;
+}
+
+/***********************************************************************
+ *             SetupDiSetClassInstallParamsA (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiSetClassInstallParamsA(
+    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;
+}
+
+/***********************************************************************
+ *             Helper functions for SetupDiSetClassInstallParamsW
+ */
+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;
+}
+
+/***********************************************************************
+ *             SetupDiSetClassInstallParamsW (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiSetClassInstallParamsW(
+    IN HDEVINFO DeviceInfoSet,
+    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
+    IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
+    IN DWORD ClassInstallParamsSize)
+{
+    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_W);
+        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)
+            {
+                ERR("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;
+}
+
+/***********************************************************************
+ *             SetupDiGetClassDevPropertySheetsA(SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiGetClassDevPropertySheetsA(
+    IN HDEVINFO DeviceInfoSet,
+    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
+    IN LPPROPSHEETHEADERA PropertySheetHeader,
+    IN DWORD PropertySheetHeaderPageListSize,
+    OUT PDWORD RequiredSize OPTIONAL,
+    IN DWORD PropertySheetType)
+{
+    PROPSHEETHEADERW psh;
+    BOOL ret = FALSE;
+
+    TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
+        PropertySheetHeader, PropertySheetHeaderPageListSize,
+        RequiredSize, PropertySheetType);
+
+    psh.dwFlags = PropertySheetHeader->dwFlags;
+    psh.phpage = PropertySheetHeader->phpage;
+    psh.nPages = PropertySheetHeader->nPages;
+
+    ret = SetupDiGetClassDevPropertySheetsW(DeviceInfoSet, DeviceInfoData, PropertySheetHeader ? &psh : NULL,
+                                            PropertySheetHeaderPageListSize, RequiredSize,
+                                            PropertySheetType);
+    if (ret)
+    {
+        PropertySheetHeader->nPages = psh.nPages;
+    }
+
+    TRACE("Returning %d\n", ret);
+    return ret;
+}
+
+struct ClassDevPropertySheetsData
+{
+    HPROPSHEETPAGE *PropertySheetPages;
+    DWORD MaximumNumberOfPages;
+    DWORD NumberOfPages;
+};
+
+static BOOL WINAPI
+GetClassDevPropertySheetsCallback(
+    IN HPROPSHEETPAGE hPropSheetPage,
+    IN OUT LPARAM lParam)
+{
+    struct ClassDevPropertySheetsData *PropPageData;
+
+    PropPageData = (struct ClassDevPropertySheetsData *)lParam;
+
+    if (PropPageData->NumberOfPages < PropPageData->MaximumNumberOfPages)
+    {
+        *PropPageData->PropertySheetPages = hPropSheetPage;
+        PropPageData->PropertySheetPages++;
+    }
+
+    PropPageData->NumberOfPages++;
+    return TRUE;
+}
+
+/***********************************************************************
+ *             SetupDiGetClassDevPropertySheetsW(SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiGetClassDevPropertySheetsW(
+    IN HDEVINFO DeviceInfoSet,
+    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
+    IN OUT LPPROPSHEETHEADERW PropertySheetHeader,
+    IN DWORD PropertySheetHeaderPageListSize,
+    OUT PDWORD RequiredSize OPTIONAL,
+    IN DWORD PropertySheetType)
+{
+    struct DeviceInfoSet *list;
+    BOOL ret = FALSE;
+
+    TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
+        PropertySheetHeader, PropertySheetHeaderPageListSize,
+        RequiredSize, PropertySheetType);
+
+    if (!DeviceInfoSet)
+        SetLastError(ERROR_INVALID_HANDLE);
+    else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
+        SetLastError(ERROR_INVALID_HANDLE);
+    else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
+        SetLastError(ERROR_INVALID_HANDLE);
+    else if (!PropertySheetHeader)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (PropertySheetHeader->dwFlags & PSH_PROPSHEETPAGE)
+        SetLastError(ERROR_INVALID_FLAGS);
+    else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else if (!DeviceInfoData && IsEqualIID(&list->ClassGuid, &GUID_NULL))
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (!PropertySheetHeader)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (PropertySheetType != DIGCDP_FLAG_ADVANCED
+          && PropertySheetType != DIGCDP_FLAG_BASIC
+          && PropertySheetType != DIGCDP_FLAG_REMOTE_ADVANCED
+          && PropertySheetType != DIGCDP_FLAG_REMOTE_BASIC)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else
+    {
+        HKEY hKey = INVALID_HANDLE_VALUE;
+        SP_PROPSHEETPAGE_REQUEST Request;
+        LPWSTR PropPageProvider = NULL;
+        HMODULE hModule = NULL;
+        PROPERTY_PAGE_PROVIDER pPropPageProvider = NULL;
+        struct ClassDevPropertySheetsData PropPageData;
+        DWORD dwLength, dwRegType;
+        DWORD rc;
+
+        if (DeviceInfoData)
+            hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
+        else
+        {
+            hKey = SetupDiOpenClassRegKeyExW(&list->ClassGuid, KEY_QUERY_VALUE,
+                DIOCR_INSTALLER, list->MachineName + 2, NULL);
+        }
+        if (hKey == INVALID_HANDLE_VALUE)
+            goto cleanup;
+
+        rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, &dwRegType, NULL, &dwLength);
+        if (rc == ERROR_FILE_NOT_FOUND)
+        {
+            /* No registry key. As it is optional, don't say it's a bad error */
+            if (RequiredSize)
+                *RequiredSize = 0;
+            ret = TRUE;
+            goto cleanup;
+        }
+        else if (rc != ERROR_SUCCESS && dwRegType != REG_SZ)
+        {
+            SetLastError(rc);
+            goto cleanup;
+        }
+
+        PropPageProvider = HeapAlloc(GetProcessHeap(), 0, dwLength + sizeof(WCHAR));
+        if (!PropPageProvider)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            goto cleanup;
+        }
+        rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, NULL, (LPBYTE)PropPageProvider, &dwLength);
+        if (rc != ERROR_SUCCESS)
+        {
+            SetLastError(rc);
+            goto cleanup;
+        }
+        PropPageProvider[dwLength / sizeof(WCHAR)] = 0;
+
+        rc = GetFunctionPointer(PropPageProvider, &hModule, (PVOID*)&pPropPageProvider);
+        if (rc != ERROR_SUCCESS)
+        {
+            SetLastError(ERROR_INVALID_PROPPAGE_PROVIDER);
+            goto cleanup;
+        }
+
+        Request.cbSize = sizeof(SP_PROPSHEETPAGE_REQUEST);
+        Request.PageRequested = SPPSR_ENUM_ADV_DEVICE_PROPERTIES;
+        Request.DeviceInfoSet = DeviceInfoSet;
+        Request.DeviceInfoData = DeviceInfoData;
+        PropPageData.PropertySheetPages = &PropertySheetHeader->phpage[PropertySheetHeader->nPages];
+        PropPageData.MaximumNumberOfPages = PropertySheetHeaderPageListSize - PropertySheetHeader->nPages;
+        PropPageData.NumberOfPages = 0;
+        ret = pPropPageProvider(&Request, GetClassDevPropertySheetsCallback, (LPARAM)&PropPageData);
+        if (!ret)
+            goto cleanup;
+
+        if (RequiredSize)
+            *RequiredSize = PropPageData.NumberOfPages + PropertySheetHeader->nPages;
+        if (PropPageData.NumberOfPages <= PropPageData.MaximumNumberOfPages)
+        {
+            PropertySheetHeader->nPages += PropPageData.NumberOfPages;
+            ret = TRUE;
+        }
+        else
+        {
+            PropertySheetHeader->nPages += PropPageData.MaximumNumberOfPages;
+            SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        }
+
+cleanup:
+        if (hKey != INVALID_HANDLE_VALUE)
+            RegCloseKey(hKey);
+        HeapFree(GetProcessHeap(), 0, PropPageProvider);
+        FreeFunctionPointer(hModule, pPropPageProvider);
+    }
+
+    TRACE("Returning %d\n", ret);
+    return ret;
+}
index 3a17477..15c14ad 100644 (file)
 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
 
 /* Unicode constants */
-static const WCHAR AddInterface[]  = {'A','d','d','I','n','t','e','r','f','a','c','e',0};
 static const WCHAR BackSlash[] = {'\\',0};
 static const WCHAR ClassGUID[]  = {'C','l','a','s','s','G','U','I','D',0};
 static const WCHAR Class[]  = {'C','l','a','s','s',0};
-static const WCHAR ClassInstall32[]  = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
-static const WCHAR Control[]  = {'C','o','n','t','r','o','l',0};
-static const WCHAR DeviceInstance[]  = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
 static const WCHAR DotCoInstallers[]  = {'.','C','o','I','n','s','t','a','l','l','e','r','s',0};
 static const WCHAR DotHW[]  = {'.','H','W',0};
-static const WCHAR DotInterfaces[]  = {'.','I','n','t','e','r','f','a','c','e','s',0};
 static const WCHAR DotServices[]  = {'.','S','e','r','v','i','c','e','s',0};
 static const WCHAR InfDirectory[] = {'i','n','f','\\',0};
-static const WCHAR InterfaceInstall32[]  = {'I','n','t','e','r','f','a','c','e','I','n','s','t','a','l','l','3','2',0};
-static const WCHAR Linked[]  = {'L','i','n','k','e','d',0};
-static const WCHAR SymbolicLink[]  = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
-static const WCHAR Version[]  = {'V','e','r','s','i','o','n',0};
 
 static const WCHAR REGSTR_DRIVER_DATE[]  = {'D','r','i','v','e','r','D','a','t','e',0};
 static const WCHAR REGSTR_DRIVER_DATE_DATA[]  = {'D','r','i','v','e','r','D','a','t','e','D','a','t','a',0};
@@ -47,10 +38,6 @@ static const WCHAR REGSTR_DRIVER_VERSION[]  = {'D','r','i','v','e','r','V','e','
 static const WCHAR REGSTR_SECURITY[]  = {'S','e','c','u','r','i','t','y',0};
 static const WCHAR REGSTR_UI_NUMBER_DESC_FORMAT[]  = {'U','I','N','u','m','b','e','r','D','e','s','c','F','o','r','m','a','t',0};
 
-static const WCHAR INF_MANUFACTURER[]  = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
-static const WCHAR INF_PROVIDER[]  = {'P','r','o','v','i','d','e','r',0};
-static const WCHAR INF_DRIVER_VER[]  = {'D','r','i','v','e','r','V','e','r',0};
-
 typedef DWORD
 (CALLBACK* CLASS_INSTALL_PROC) (
     IN DI_FUNCTION InstallFunction,
@@ -66,17 +53,6 @@ typedef DWORD
     IN HDEVINFO DeviceInfoSet,
     IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
     IN OUT PCOINSTALLER_CONTEXT_DATA Context);
-typedef BOOL
-(WINAPI* PROPERTY_PAGE_PROVIDER) (
-    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
 {
@@ -98,552 +74,6 @@ struct GetSectionCallbackInfo
     DWORD BestScore1, BestScore2, BestScore3, BestScore4, BestScore5;
 };
 
-static BOOL
-PropertyChangeHandler(
-    IN HDEVINFO DeviceInfoSet,
-    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
-    IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
-    IN DWORD ClassInstallParamsSize);
-
-static const 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.@)
- */
-BOOL WINAPI
-SetupDiBuildClassInfoList(
-    IN DWORD Flags,
-    OUT LPGUID ClassGuidList OPTIONAL,
-    IN DWORD ClassGuidListSize,
-    OUT PDWORD RequiredSize)
-{
-    TRACE("\n");
-    return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
-                                        ClassGuidListSize, RequiredSize,
-                                        NULL, NULL);
-}
-
-/***********************************************************************
- *              SetupDiBuildClassInfoListExA  (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiBuildClassInfoListExA(
-    IN DWORD Flags,
-    OUT LPGUID ClassGuidList OPTIONAL,
-    IN DWORD ClassGuidListSize,
-    OUT PDWORD RequiredSize,
-    IN PCSTR MachineName OPTIONAL,
-    IN PVOID Reserved)
-{
-    LPWSTR MachineNameW = NULL;
-    BOOL bResult;
-
-    TRACE("\n");
-
-    if (MachineName)
-    {
-        MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
-        if (MachineNameW == NULL) return FALSE;
-    }
-
-    bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
-                                           ClassGuidListSize, RequiredSize,
-                                           MachineNameW, Reserved);
-
-    if (MachineNameW)
-        MyFree(MachineNameW);
-
-    return bResult;
-}
-
-/***********************************************************************
- *             SetupDiBuildClassInfoListExW  (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiBuildClassInfoListExW(
-    IN DWORD Flags,
-    OUT LPGUID ClassGuidList OPTIONAL,
-    IN DWORD ClassGuidListSize,
-    OUT PDWORD RequiredSize,
-    IN PCWSTR MachineName OPTIONAL,
-    IN PVOID Reserved)
-{
-    WCHAR szKeyName[MAX_GUID_STRING_LEN + 1];
-    HKEY hClassesKey = INVALID_HANDLE_VALUE;
-    HKEY hClassKey = NULL;
-    DWORD dwLength;
-    DWORD dwIndex;
-    LONG lError;
-    DWORD dwGuidListIndex = 0;
-    BOOL ret = FALSE;
-
-    TRACE("0x%lx %p %lu %p %s %p\n", Flags, ClassGuidList,
-        ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved);
-
-    if (RequiredSize != NULL)
-        *RequiredSize = 0;
-
-    hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
-                                            KEY_ENUMERATE_SUB_KEYS,
-                                            DIOCR_INSTALLER,
-                                            MachineName,
-                                            Reserved);
-    if (hClassesKey == INVALID_HANDLE_VALUE)
-        goto cleanup;
-
-    for (dwIndex = 0; ; dwIndex++)
-    {
-        dwLength = MAX_GUID_STRING_LEN + 1;
-        lError = RegEnumKeyExW(hClassesKey,
-                               dwIndex,
-                               szKeyName,
-                               &dwLength,
-                               NULL,
-                               NULL,
-                               NULL,
-                               NULL);
-        TRACE("RegEnumKeyExW() returns %ld\n", lError);
-        if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
-        {
-            TRACE("Key name: %s\n", debugstr_w(szKeyName));
-
-            if (hClassKey != NULL)
-                RegCloseKey(hClassKey);
-            if (RegOpenKeyExW(hClassesKey,
-                              szKeyName,
-                              0,
-                              KEY_QUERY_VALUE,
-                              &hClassKey) != ERROR_SUCCESS)
-            {
-                goto cleanup;
-            }
-
-            if (RegQueryValueExW(hClassKey,
-                                 REGSTR_VAL_NOUSECLASS,
-                                 NULL,
-                                 NULL,
-                                 NULL,
-                                 NULL) == ERROR_SUCCESS)
-            {
-                TRACE("'NoUseClass' value found!\n");
-                continue;
-            }
-
-            if ((Flags & DIBCI_NOINSTALLCLASS) &&
-                (!RegQueryValueExW(hClassKey,
-                                   REGSTR_VAL_NOINSTALLCLASS,
-                                   NULL,
-                                   NULL,
-                                   NULL,
-                                   NULL)))
-            {
-                TRACE("'NoInstallClass' value found!\n");
-                continue;
-            }
-
-            if ((Flags & DIBCI_NODISPLAYCLASS) &&
-                (!RegQueryValueExW(hClassKey,
-                                   REGSTR_VAL_NODISPLAYCLASS,
-                                   NULL,
-                                   NULL,
-                                   NULL,
-                                   NULL)))
-            {
-                TRACE("'NoDisplayClass' value found!\n");
-                continue;
-            }
-
-            TRACE("Guid: %s\n", debugstr_w(szKeyName));
-            if (dwGuidListIndex < ClassGuidListSize)
-            {
-                if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
-                    szKeyName[37] = 0;
-                TRACE("Guid: %s\n", debugstr_w(&szKeyName[1]));
-
-                UuidFromStringW(&szKeyName[1],
-                    &ClassGuidList[dwGuidListIndex]);
-            }
-
-            dwGuidListIndex++;
-        }
-
-        if (lError != ERROR_SUCCESS)
-        break;
-    }
-
-    if (RequiredSize != NULL)
-        *RequiredSize = dwGuidListIndex;
-
-    if (ClassGuidListSize < dwGuidListIndex)
-        SetLastError(ERROR_INSUFFICIENT_BUFFER);
-    else
-        ret = TRUE;
-
-cleanup:
-    if (hClassesKey != INVALID_HANDLE_VALUE)
-        RegCloseKey(hClassesKey);
-    if (hClassKey != NULL)
-        RegCloseKey(hClassKey);
-    return ret;
-}
-
-/***********************************************************************
- *             SetupDiClassGuidsFromNameA  (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiClassGuidsFromNameA(
-    IN PCSTR ClassName,
-    OUT LPGUID ClassGuidList,
-    IN DWORD ClassGuidListSize,
-    OUT PDWORD RequiredSize)
-{
-  return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
-                                      ClassGuidListSize, RequiredSize,
-                                      NULL, NULL);
-}
-
-/***********************************************************************
- *             SetupDiClassGuidsFromNameW  (SETUPAPI.@)
- */
-BOOL WINAPI SetupDiClassGuidsFromNameW(
-        IN PCWSTR ClassName,
-        OUT LPGUID ClassGuidList,
-        IN DWORD ClassGuidListSize,
-        OUT PDWORD RequiredSize)
-{
-  return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
-                                      ClassGuidListSize, RequiredSize,
-                                      NULL, NULL);
-}
-
-/***********************************************************************
- *             SetupDiClassGuidsFromNameExA  (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiClassGuidsFromNameExA(
-    IN PCSTR ClassName,
-    OUT LPGUID ClassGuidList,
-    IN DWORD ClassGuidListSize,
-    OUT PDWORD RequiredSize,
-    IN PCSTR MachineName OPTIONAL,
-    IN PVOID Reserved)
-{
-    LPWSTR ClassNameW = NULL;
-    LPWSTR MachineNameW = NULL;
-    BOOL bResult;
-
-    TRACE("\n");
-
-    ClassNameW = MultiByteToUnicode(ClassName, CP_ACP);
-    if (ClassNameW == NULL)
-        return FALSE;
-
-    if (MachineNameW)
-    {
-        MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
-        if (MachineNameW == NULL)
-        {
-            MyFree(ClassNameW);
-            return FALSE;
-        }
-    }
-
-    bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
-                                           ClassGuidListSize, RequiredSize,
-                                           MachineNameW, Reserved);
-
-    if (MachineNameW)
-        MyFree(MachineNameW);
-
-    MyFree(ClassNameW);
-
-    return bResult;
-}
-
-/***********************************************************************
- *             SetupDiClassGuidsFromNameExW  (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiClassGuidsFromNameExW(
-    IN PCWSTR ClassName,
-    OUT LPGUID ClassGuidList,
-    IN DWORD ClassGuidListSize,
-    OUT PDWORD RequiredSize,
-    IN PCWSTR MachineName OPTIONAL,
-    IN PVOID Reserved)
-{
-    WCHAR szKeyName[MAX_GUID_STRING_LEN + 1];
-    WCHAR szClassName[256];
-    HKEY hClassesKey = INVALID_HANDLE_VALUE;
-    HKEY hClassKey = NULL;
-    DWORD dwLength;
-    DWORD dwIndex;
-    LONG lError;
-    DWORD dwGuidListIndex = 0;
-    BOOL ret = FALSE;
-
-    TRACE("%s %p %lu %p %s %p\n", debugstr_w(ClassName), ClassGuidList,
-        ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved);
-
-    if (RequiredSize != NULL)
-        *RequiredSize = 0;
-
-    hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
-                                            KEY_ENUMERATE_SUB_KEYS,
-                                            DIOCR_INSTALLER,
-                                            MachineName,
-                                            Reserved);
-    if (hClassesKey == INVALID_HANDLE_VALUE)
-        goto cleanup;
-
-    for (dwIndex = 0; ; dwIndex++)
-    {
-        dwLength = MAX_GUID_STRING_LEN + 1;
-        lError = RegEnumKeyExW(hClassesKey,
-                               dwIndex,
-                               szKeyName,
-                               &dwLength,
-                               NULL,
-                               NULL,
-                               NULL,
-                               NULL);
-        TRACE("RegEnumKeyExW() returns %ld\n", lError);
-        if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
-        {
-            TRACE("Key name: %s\n", debugstr_w(szKeyName));
-
-            if (hClassKey != NULL)
-                RegCloseKey(hClassKey);
-            if (RegOpenKeyExW(hClassesKey,
-                              szKeyName,
-                              0,
-                              KEY_QUERY_VALUE,
-                              &hClassKey) != ERROR_SUCCESS)
-            {
-                goto cleanup;
-            }
-
-            dwLength = 256 * sizeof(WCHAR);
-            if (RegQueryValueExW(hClassKey,
-                                 Class,
-                                 NULL,
-                                 NULL,
-                                 (LPBYTE)szClassName,
-                                 &dwLength) == ERROR_SUCCESS)
-            {
-                TRACE("Class name: %s\n", debugstr_w(szClassName));
-
-                if (strcmpiW(szClassName, ClassName) == 0)
-                {
-                    TRACE("Found matching class name\n");
-
-                    TRACE("Guid: %s\n", debugstr_w(szKeyName));
-                    if (dwGuidListIndex < ClassGuidListSize)
-                    {
-                        if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
-                            szKeyName[37] = 0;
-                        TRACE("Guid: %s\n", debugstr_w(&szKeyName[1]));
-
-                        UuidFromStringW(&szKeyName[1],
-                            &ClassGuidList[dwGuidListIndex]);
-                    }
-
-                    dwGuidListIndex++;
-                }
-            }
-        }
-
-        if (lError != ERROR_SUCCESS)
-            break;
-    }
-
-    if (RequiredSize != NULL)
-        *RequiredSize = dwGuidListIndex;
-
-    if (ClassGuidListSize < dwGuidListIndex)
-        SetLastError(ERROR_INSUFFICIENT_BUFFER);
-    else
-        ret = TRUE;
-
-cleanup:
-    if (hClassesKey != INVALID_HANDLE_VALUE)
-        RegCloseKey(hClassesKey);
-    if (hClassKey != NULL)
-        RegCloseKey(hClassKey);
-    return ret;
-}
-
-/***********************************************************************
- *              SetupDiClassNameFromGuidA  (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiClassNameFromGuidA(
-    IN CONST GUID* ClassGuid,
-    OUT PSTR ClassName,
-    IN DWORD ClassNameSize,
-    OUT PDWORD RequiredSize OPTIONAL)
-{
-  return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
-                                     ClassNameSize, RequiredSize,
-                                     NULL, NULL);
-}
-
-/***********************************************************************
- *              SetupDiClassNameFromGuidW  (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiClassNameFromGuidW(
-    IN CONST GUID* ClassGuid,
-    OUT PWSTR ClassName,
-    IN DWORD ClassNameSize,
-    OUT PDWORD RequiredSize OPTIONAL)
-{
-  return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
-                                     ClassNameSize, RequiredSize,
-                                     NULL, NULL);
-}
-
-/***********************************************************************
- *              SetupDiClassNameFromGuidExA  (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiClassNameFromGuidExA(
-    IN CONST GUID* ClassGuid,
-    OUT PSTR ClassName,
-    IN DWORD ClassNameSize,
-    OUT PDWORD RequiredSize OPTIONAL,
-    IN PCSTR MachineName OPTIONAL,
-    IN PVOID Reserved)
-{
-    WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
-    LPWSTR MachineNameW = NULL;
-    BOOL ret;
-
-    if (MachineName)
-        MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
-    ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
-        NULL, MachineNameW, Reserved);
-    if (ret)
-    {
-        int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
-         ClassNameSize, NULL, NULL);
-
-        if (!ClassNameSize && RequiredSize)
-            *RequiredSize = len;
-    }
-    MyFree(MachineNameW);
-    return ret;
-}
-
-/***********************************************************************
- *             SetupDiClassNameFromGuidExW  (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiClassNameFromGuidExW(
-    IN CONST GUID* ClassGuid,
-    OUT PWSTR ClassName,
-    IN DWORD ClassNameSize,
-    OUT PDWORD RequiredSize OPTIONAL,
-    IN PCWSTR MachineName OPTIONAL,
-    IN PVOID Reserved)
-{
-    HKEY hKey;
-    DWORD dwLength;
-    LONG rc;
-    BOOL ret = FALSE;
-
-    TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassName,
-        ClassNameSize, RequiredSize, debugstr_w(MachineName), Reserved);
-
-    hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
-                                     KEY_QUERY_VALUE,
-                                     DIOCR_INSTALLER,
-                                     MachineName,
-                                     Reserved);
-    if (hKey == INVALID_HANDLE_VALUE)
-        goto cleanup;
-
-    if (RequiredSize != NULL)
-    {
-        dwLength = 0;
-        rc = RegQueryValueExW(hKey,
-                              Class,
-                              NULL,
-                              NULL,
-                              NULL,
-                              &dwLength);
-        if (rc != ERROR_SUCCESS)
-        {
-            SetLastError(rc);
-            goto cleanup;
-        }
-
-        *RequiredSize = dwLength / sizeof(WCHAR);
-    }
-
-    dwLength = ClassNameSize * sizeof(WCHAR);
-    rc = RegQueryValueExW(hKey,
-                          Class,
-                          NULL,
-                          NULL,
-                          (LPBYTE)ClassName,
-                          &dwLength);
-    if (rc != ERROR_SUCCESS)
-    {
-        SetLastError(rc);
-        goto cleanup;
-    }
-
-    ret = TRUE;
-
-cleanup:
-    if (hKey != INVALID_HANDLE_VALUE)
-        RegCloseKey(hKey);
-    return ret;
-}
 
 /***********************************************************************
  *             SetupDiCreateDeviceInfoList (SETUPAPI.@)
@@ -1367,245 +797,16 @@ done:
 }
 
 
-/***********************************************************************
- *             SetupDiGetClassDescriptionA  (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiGetClassDescriptionA(
-    IN CONST GUID *ClassGuid,
-    OUT PSTR ClassDescription,
-    IN DWORD ClassDescriptionSize,
-    OUT PDWORD RequiredSize OPTIONAL)
+BOOL
+CreateDeviceInfoElement(
+    IN struct DeviceInfoSet *list,
+    IN LPCWSTR InstancePath,
+    IN LPCGUID pClassGuid,
+    OUT struct DeviceInfoElement **pDeviceInfo)
 {
-  return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
-                                       ClassDescriptionSize,
-                                       RequiredSize, NULL, NULL);
-}
-
-/***********************************************************************
- *             SetupDiGetClassDescriptionW  (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiGetClassDescriptionW(
-    IN CONST GUID *ClassGuid,
-    OUT PWSTR ClassDescription,
-    IN DWORD ClassDescriptionSize,
-    OUT PDWORD RequiredSize OPTIONAL)
-{
-  return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
-                                       ClassDescriptionSize,
-                                       RequiredSize, NULL, NULL);
-}
-
-/***********************************************************************
- *             SetupDiGetClassDescriptionExA  (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiGetClassDescriptionExA(
-    IN CONST GUID *ClassGuid,
-    OUT PSTR ClassDescription,
-    IN DWORD ClassDescriptionSize,
-    OUT PDWORD RequiredSize OPTIONAL,
-    IN PCSTR MachineName OPTIONAL,
-    IN PVOID Reserved)
-{
-    PWCHAR ClassDescriptionW;
-    LPWSTR MachineNameW = NULL;
-    BOOL ret;
-
-    TRACE("\n");
-    if (ClassDescriptionSize > 0)
-    {
-        ClassDescriptionW = HeapAlloc(GetProcessHeap(), 0, ClassDescriptionSize * sizeof(WCHAR));
-        if (!ClassDescriptionW)
-        {
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            ret = FALSE;
-            goto end;
-        }
-    }
-    else
-        ClassDescriptionW = NULL;
-
-    if (MachineName)
-    {
-        MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
-        if (!MachineNameW)
-        {
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            ret = FALSE;
-            goto end;
-        }
-    }
-
-    ret = SetupDiGetClassDescriptionExW(ClassGuid, ClassDescriptionW, ClassDescriptionSize * sizeof(WCHAR),
-     NULL, MachineNameW, Reserved);
-    if (ret)
-    {
-        int len = WideCharToMultiByte(CP_ACP, 0, ClassDescriptionW, -1, ClassDescription,
-         ClassDescriptionSize, NULL, NULL);
-
-        if (!ClassDescriptionSize && RequiredSize)
-            *RequiredSize = len;
-    }
-
-end:
-    HeapFree(GetProcessHeap(), 0, ClassDescriptionW);
-    MyFree(MachineNameW);
-    return ret;
-}
-
-/***********************************************************************
- *             SetupDiGetClassDescriptionExW  (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiGetClassDescriptionExW(
-    IN CONST GUID *ClassGuid,
-    OUT PWSTR ClassDescription,
-    IN DWORD ClassDescriptionSize,
-    OUT PDWORD RequiredSize OPTIONAL,
-    IN PCWSTR MachineName OPTIONAL,
-    IN PVOID Reserved)
-{
-    HKEY hKey = INVALID_HANDLE_VALUE;
-    DWORD dwLength;
-    BOOL ret = FALSE;
-
-    TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassDescription,
-        ClassDescriptionSize, RequiredSize, debugstr_w(MachineName), Reserved);
-
-    hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
-                                     KEY_QUERY_VALUE,
-                                     DIOCR_INSTALLER,
-                                     MachineName,
-                                     Reserved);
-    if (hKey == INVALID_HANDLE_VALUE)
-    {
-        WARN("SetupDiOpenClassRegKeyExW() failed (Error %lu)\n", GetLastError());
-        goto cleanup;
-    }
-
-    if (RequiredSize != NULL)
-    {
-        dwLength = 0;
-        if (RegQueryValueExW(hKey,
-                             NULL,
-                             NULL,
-                             NULL,
-                             NULL,
-                             &dwLength) != ERROR_SUCCESS)
-        {
-            goto cleanup;
-        }
-
-        *RequiredSize = dwLength / sizeof(WCHAR);
-    }
-
-    dwLength = ClassDescriptionSize * sizeof(WCHAR);
-    if (RegQueryValueExW(hKey,
-                         NULL,
-                         NULL,
-                         NULL,
-                         (LPBYTE)ClassDescription,
-                         &dwLength) != ERROR_SUCCESS)
-    {
-        goto cleanup;
-    }
-
-    ret = TRUE;
-
-cleanup:
-    if (hKey != INVALID_HANDLE_VALUE)
-        RegCloseKey(hKey);
-
-    return ret;
-}
-
-/***********************************************************************
- *             SetupDiGetClassDevsA (SETUPAPI.@)
- */
-HDEVINFO WINAPI
-SetupDiGetClassDevsA(
-    IN CONST GUID *ClassGuid OPTIONAL,
-    IN PCSTR Enumerator OPTIONAL,
-    IN HWND hwndParent OPTIONAL,
-    IN DWORD Flags)
-{
-    return SetupDiGetClassDevsExA(ClassGuid, Enumerator, hwndParent,
-                                  Flags, NULL, NULL, NULL);
-}
-
-/***********************************************************************
- *             SetupDiGetClassDevsW (SETUPAPI.@)
- */
-HDEVINFO WINAPI
-SetupDiGetClassDevsW(
-    IN CONST GUID *ClassGuid OPTIONAL,
-    IN PCWSTR Enumerator OPTIONAL,
-    IN HWND hwndParent OPTIONAL,
-    IN DWORD Flags)
-{
-    return SetupDiGetClassDevsExW(ClassGuid, Enumerator, hwndParent,
-                                  Flags, NULL, NULL, NULL);
-}
-
-/***********************************************************************
- *             SetupDiGetClassDevsExA (SETUPAPI.@)
- */
-HDEVINFO WINAPI
-SetupDiGetClassDevsExA(
-    IN CONST GUID *ClassGuid OPTIONAL,
-    IN PCSTR Enumerator OPTIONAL,
-    IN HWND hwndParent OPTIONAL,
-    IN DWORD Flags,
-    IN HDEVINFO DeviceInfoSet OPTIONAL,
-    IN PCSTR MachineName OPTIONAL,
-    IN PVOID Reserved)
-{
-    HDEVINFO ret;
-    LPWSTR enumstrW = NULL;
-    LPWSTR machineW = NULL;
-
-    if (Enumerator)
-    {
-        int len = MultiByteToWideChar(CP_ACP, 0, Enumerator, -1, NULL, 0);
-        enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
-        if (!enumstrW)
-        {
-            ret = (HDEVINFO)INVALID_HANDLE_VALUE;
-            goto end;
-        }
-        MultiByteToWideChar(CP_ACP, 0, Enumerator, -1, enumstrW, len);
-    }
-    if (MachineName)
-    {
-        int len = MultiByteToWideChar(CP_ACP, 0, MachineName, -1, NULL, 0);
-        machineW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
-        if (!machineW)
-        {
-            ret = (HDEVINFO)INVALID_HANDLE_VALUE;
-            goto end;
-        }
-        MultiByteToWideChar(CP_ACP, 0, MachineName, -1, machineW, len);
-    }
-    ret = SetupDiGetClassDevsExW(ClassGuid, enumstrW, hwndParent, Flags, DeviceInfoSet, machineW, Reserved);
-
-end:
-    HeapFree(GetProcessHeap(), 0, enumstrW);
-    HeapFree(GetProcessHeap(), 0, machineW);
-    return ret;
-}
-
-static BOOL
-CreateDeviceInfoElement(
-    IN struct DeviceInfoSet *list,
-    IN LPCWSTR InstancePath,
-    IN LPCGUID pClassGuid,
-    OUT struct DeviceInfoElement **pDeviceInfo)
-{
-    DWORD size;
-    CONFIGRET cr;
-    struct DeviceInfoElement *deviceInfo;
+    DWORD size;
+    CONFIGRET cr;
+    struct DeviceInfoElement *deviceInfo;
 
     *pDeviceInfo = NULL;
 
@@ -1639,5185 +840,1805 @@ CreateDeviceInfoElement(
     return TRUE;
 }
 
+
 static BOOL
-CreateDeviceInterface(
-    IN struct DeviceInfoElement* deviceInfo,
-    IN LPCWSTR SymbolicLink,
-    IN LPCGUID pInterfaceGuid,
-    OUT struct DeviceInterface **pDeviceInterface)
+DestroyClassInstallParams(struct ClassInstallParams* installParams)
 {
-    struct DeviceInterface *deviceInterface;
+    return HeapFree(GetProcessHeap(), 0, installParams->PropChange);
+}
 
-    *pDeviceInterface = NULL;
+static BOOL
+DestroyDeviceInfoElement(struct DeviceInfoElement* deviceInfo)
+{
+    PLIST_ENTRY ListEntry;
+    struct DriverInfoElement *driverInfo;
+    struct DeviceInterface *deviceInterface;
 
-    deviceInterface = HeapAlloc(GetProcessHeap(), 0,
-        FIELD_OFFSET(struct DeviceInterface, SymbolicLink) + (strlenW(SymbolicLink) + 1) * sizeof(WCHAR));
-    if (!deviceInterface)
+    while (!IsListEmpty(&deviceInfo->DriverListHead))
     {
-        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-        return FALSE;
+        ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
+        driverInfo = CONTAINING_RECORD(ListEntry, struct DriverInfoElement, ListEntry);
+        if (!DestroyDriverInfoElement(driverInfo))
+            return FALSE;
     }
-    deviceInterface->DeviceInfo = deviceInfo;
-    strcpyW(deviceInterface->SymbolicLink, SymbolicLink);
-    deviceInterface->Flags = 0; /* Flags will be updated later */
-    memcpy(&deviceInterface->InterfaceClassGuid, pInterfaceGuid, sizeof(GUID));
-
-    *pDeviceInterface = deviceInterface;
-    return TRUE;
+    while (!IsListEmpty(&deviceInfo->InterfaceListHead))
+    {
+        ListEntry = RemoveHeadList(&deviceInfo->InterfaceListHead);
+        deviceInterface = CONTAINING_RECORD(ListEntry, struct DeviceInterface, ListEntry);
+        if (!DestroyDeviceInterface(deviceInterface))
+            return FALSE;
+    }
+    DestroyClassInstallParams(&deviceInfo->ClassInstallParams);
+    return HeapFree(GetProcessHeap(), 0, deviceInfo);
 }
 
-static LONG
-SETUP_CreateDevListFromEnumerator(
-    struct DeviceInfoSet *list,
-    CONST GUID *pClassGuid OPTIONAL,
-    LPCWSTR Enumerator,
-    HKEY hEnumeratorKey) /* handle to Enumerator registry key */
+static BOOL
+DestroyDeviceInfoSet(struct DeviceInfoSet* list)
 {
-    HKEY hDeviceIdKey = NULL, hInstanceIdKey;
-    WCHAR KeyBuffer[MAX_PATH];
-    WCHAR InstancePath[MAX_PATH];
-    LPWSTR pEndOfInstancePath; /* Pointer into InstancePath buffer */
+    PLIST_ENTRY ListEntry;
     struct DeviceInfoElement *deviceInfo;
-    DWORD i = 0, j;
-    DWORD dwLength, dwRegType;
-    DWORD rc;
 
-    /* Enumerate device IDs (subkeys of hEnumeratorKey) */
-    while (TRUE)
+    while (!IsListEmpty(&list->ListHead))
     {
-        dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
-        rc = RegEnumKeyExW(hEnumeratorKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
-        if (rc == ERROR_NO_MORE_ITEMS)
-            break;
-        if (rc != ERROR_SUCCESS)
-            goto cleanup;
-        i++;
-
-        /* Open device id sub key */
-        if (hDeviceIdKey != NULL)
-            RegCloseKey(hDeviceIdKey);
-        rc = RegOpenKeyExW(hEnumeratorKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hDeviceIdKey);
-        if (rc != ERROR_SUCCESS)
-            goto cleanup;
-        strcpyW(InstancePath, Enumerator);
-        strcatW(InstancePath, BackSlash);
-        strcatW(InstancePath, KeyBuffer);
-        strcatW(InstancePath, BackSlash);
-        pEndOfInstancePath = &InstancePath[strlenW(InstancePath)];
-
-        /* Enumerate instance IDs (subkeys of hDeviceIdKey) */
-        j = 0;
-        while (TRUE)
-        {
-            GUID KeyGuid;
-
-            dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
-            rc = RegEnumKeyExW(hDeviceIdKey, j, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
-            if (rc == ERROR_NO_MORE_ITEMS)
-                break;
-            if (rc != ERROR_SUCCESS)
-                goto cleanup;
-            j++;
-
-            /* Open instance id sub key */
-            rc = RegOpenKeyExW(hDeviceIdKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hInstanceIdKey);
-            if (rc != ERROR_SUCCESS)
-                goto cleanup;
-            *pEndOfInstancePath = '\0';
-            strcatW(InstancePath, KeyBuffer);
+        ListEntry = RemoveHeadList(&list->ListHead);
+        deviceInfo = CONTAINING_RECORD(ListEntry, struct DeviceInfoElement, ListEntry);
+        if (!DestroyDeviceInfoElement(deviceInfo))
+            return FALSE;
+    }
+    if (list->HKLM != HKEY_LOCAL_MACHINE)
+        RegCloseKey(list->HKLM);
+    CM_Disconnect_Machine(list->hMachine);
+    DestroyClassInstallParams(&list->ClassInstallParams);
+    return HeapFree(GetProcessHeap(), 0, list);
+}
 
-            /* Read ClassGUID value */
-            dwLength = sizeof(KeyBuffer) - sizeof(WCHAR);
-            rc = RegQueryValueExW(hInstanceIdKey, ClassGUID, NULL, &dwRegType, (LPBYTE)KeyBuffer, &dwLength);
-            RegCloseKey(hInstanceIdKey);
-            if (rc == ERROR_FILE_NOT_FOUND)
-            {
-                if (pClassGuid)
-                    /* Skip this bad entry as we can't verify it */
-                    continue;
-                /* Set a default GUID for this device */
-                memcpy(&KeyGuid, &GUID_NULL, sizeof(GUID));
-            }
-            else if (rc != ERROR_SUCCESS)
-            {
-                goto cleanup;
-            }
-            else if (dwRegType != REG_SZ)
-            {
-                rc = ERROR_GEN_FAILURE;
-                goto cleanup;
-            }
-            else
-            {
-                KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */
-                if (UuidFromStringW(&KeyBuffer[1], &KeyGuid) != RPC_S_OK)
-                    /* Bad GUID, skip the entry */
-                    continue;
-            }
+/***********************************************************************
+ *             SetupDiDestroyDeviceInfoList (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiDestroyDeviceInfoList(
+    IN HDEVINFO DeviceInfoSet)
+{
+    BOOL ret = FALSE;
 
-            if (pClassGuid && !IsEqualIID(&KeyGuid, pClassGuid))
-            {
-                /* Skip this entry as it is not the right device class */
-                continue;
-            }
+    TRACE("%p\n", DeviceInfoSet);
+    if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
+    {
+        struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
 
-            /* Add the entry to the list */
-            if (!CreateDeviceInfoElement(list, InstancePath, &KeyGuid, &deviceInfo))
-            {
-                rc = GetLastError();
-                goto cleanup;
-            }
-            TRACE("Adding '%s' to device info set %p\n", debugstr_w(InstancePath), list);
-            InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
-        }
+        if (list->magic == SETUP_DEV_INFO_SET_MAGIC)
+            ret = DestroyDeviceInfoSet(list);
+        else
+            SetLastError(ERROR_INVALID_HANDLE);
     }
+    else
+        SetLastError(ERROR_INVALID_HANDLE);
 
-    rc = ERROR_SUCCESS;
-
-cleanup:
-    if (hDeviceIdKey != NULL)
-        RegCloseKey(hDeviceIdKey);
-    return rc;
+    TRACE("Returning %d\n", ret);
+    return ret;
 }
 
-static LONG
-SETUP_CreateDevList(
-    struct DeviceInfoSet *list,
-    PCWSTR MachineName OPTIONAL,
-    CONST GUID *class OPTIONAL,
-    PCWSTR Enumerator OPTIONAL)
+/***********************************************************************
+ *             SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiGetDeviceRegistryPropertyA(
+    IN HDEVINFO DeviceInfoSet,
+    IN PSP_DEVINFO_DATA DeviceInfoData,
+    IN DWORD Property,
+    OUT PDWORD PropertyRegDataType OPTIONAL,
+    OUT PBYTE PropertyBuffer OPTIONAL,
+    IN DWORD PropertyBufferSize,
+    OUT PDWORD  RequiredSize OPTIONAL)
 {
-    HKEY HKLM = HKEY_LOCAL_MACHINE;
-    HKEY hEnumKey = NULL;
-    HKEY hEnumeratorKey = NULL;
-    WCHAR KeyBuffer[MAX_PATH];
-    DWORD i;
-    DWORD dwLength;
-    DWORD rc;
+    BOOL bResult;
+    BOOL bIsStringProperty;
+    DWORD RegType;
+    DWORD RequiredSizeA, RequiredSizeW;
+    DWORD PropertyBufferSizeW = 0;
+    PBYTE PropertyBufferW = NULL;
 
-    if (class && IsEqualIID(class, &GUID_NULL))
-        class = NULL;
+    TRACE("%p %p %ld %p %p %ld %p\n", DeviceInfoSet, DeviceInfoData,
+        Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
+        RequiredSize);
 
-    /* Open Enum key (if applicable) */
-    if (MachineName != NULL)
+    if (PropertyBufferSize != 0)
     {
-        rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
-        if (rc != ERROR_SUCCESS)
-            goto cleanup;
+        PropertyBufferSizeW = PropertyBufferSize * 2;
+        PropertyBufferW = HeapAlloc(GetProcessHeap(), 0, PropertyBufferSizeW);
+        if (!PropertyBufferW)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            return FALSE;
+        }
     }
 
-    rc = RegOpenKeyExW(
-        HKLM,
-        REGSTR_PATH_SYSTEMENUM,
-        0,
-        KEY_ENUMERATE_SUB_KEYS,
-        &hEnumKey);
-    if (rc != ERROR_SUCCESS)
-        goto cleanup;
+    bResult = SetupDiGetDeviceRegistryPropertyW(
+        DeviceInfoSet,
+        DeviceInfoData,
+        Property,
+        &RegType,
+        PropertyBufferW,
+        PropertyBufferSizeW,
+        &RequiredSizeW);
 
-    /* If enumerator is provided, call directly SETUP_CreateDevListFromEnumerator.
-     * Else, enumerate all enumerators and call SETUP_CreateDevListFromEnumerator
-     * for each one.
-     */
-    if (Enumerator)
-    {
-        rc = RegOpenKeyExW(
-            hEnumKey,
-            Enumerator,
-            0,
-            KEY_ENUMERATE_SUB_KEYS,
-            &hEnumeratorKey);
-        if (rc != ERROR_SUCCESS)
-            goto cleanup;
-        rc = SETUP_CreateDevListFromEnumerator(list, class, Enumerator, hEnumeratorKey);
-    }
-    else
+    if (bResult || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
     {
-        /* Enumerate enumerators */
-        i = 0;
-        while (TRUE)
-        {
-            dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
-            rc = RegEnumKeyExW(hEnumKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
-            if (rc == ERROR_NO_MORE_ITEMS)
-                break;
-            else if (rc != ERROR_SUCCESS)
-                goto cleanup;
-            i++;
-
-            /* Open sub key */
-            if (hEnumeratorKey != NULL)
-                RegCloseKey(hEnumeratorKey);
-            rc = RegOpenKeyExW(hEnumKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hEnumeratorKey);
-            if (rc != ERROR_SUCCESS)
-                goto cleanup;
+        bIsStringProperty = (RegType == REG_SZ || RegType == REG_MULTI_SZ || RegType == REG_EXPAND_SZ);
 
-            /* Call SETUP_CreateDevListFromEnumerator */
-            rc = SETUP_CreateDevListFromEnumerator(list, class, KeyBuffer, hEnumeratorKey);
-            if (rc != ERROR_SUCCESS)
-                goto cleanup;
-        }
-        rc = ERROR_SUCCESS;
+        if (bIsStringProperty)
+           RequiredSizeA = RequiredSizeW / sizeof(WCHAR);
+        else
+            RequiredSizeA = RequiredSizeW;
+        if (RequiredSize)
+            *RequiredSize = RequiredSizeA;
+        if (PropertyRegDataType)
+            *PropertyRegDataType = RegType;
     }
 
-cleanup:
-    if (HKLM != HKEY_LOCAL_MACHINE)
-        RegCloseKey(HKLM);
-    if (hEnumKey != NULL)
-        RegCloseKey(hEnumKey);
-    if (hEnumeratorKey != NULL)
-        RegCloseKey(hEnumeratorKey);
-    return rc;
-}
-
-static BOOL
-DestroyDeviceInterface(
-    struct DeviceInterface* deviceInterface)
-{
-    return HeapFree(GetProcessHeap(), 0, deviceInterface);
-}
-
-static LONG
-SETUP_CreateInterfaceList(
-    struct DeviceInfoSet *list,
-    PCWSTR MachineName,
-    CONST GUID *InterfaceGuid,
-    PCWSTR DeviceInstanceW /* OPTIONAL */,
-    BOOL OnlyPresentInterfaces)
-{
-    HKEY hInterfaceKey;      /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
-    HKEY hDeviceInstanceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath} */
-    HKEY hReferenceKey;      /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath}\#{ReferenceString} */
-    HKEY hControlKey;        /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath}\#{ReferenceString}\Control */
-    HKEY hEnumKey;           /* HKLM\SYSTEM\CurrentControlSet\Enum */
-    HKEY hKey;               /* HKLM\SYSTEM\CurrentControlSet\Enum\{Instance\Path} */
-    LONG rc;
-    WCHAR KeyBuffer[max(MAX_PATH, MAX_GUID_STRING_LEN) + 1];
-    PWSTR pSymbolicLink = NULL;
-    PWSTR InstancePath = NULL;
-    DWORD i, j;
-    DWORD dwLength, dwInstancePathLength;
-    DWORD dwRegType;
-    DWORD LinkedValue;
-    GUID ClassGuid;
-    struct DeviceInfoElement *deviceInfo;
-
-    hInterfaceKey = INVALID_HANDLE_VALUE;
-    hDeviceInstanceKey = NULL;
-    hReferenceKey = NULL;
-
-    /* Open registry key related to this interface */
-    hInterfaceKey = SetupDiOpenClassRegKeyExW(InterfaceGuid, KEY_ENUMERATE_SUB_KEYS, DIOCR_INTERFACE, MachineName, NULL);
-    if (hInterfaceKey == INVALID_HANDLE_VALUE)
+    if (!bResult)
     {
-        rc = GetLastError();
-        goto cleanup;
+        HeapFree(GetProcessHeap(), 0, PropertyBufferW);
+        return bResult;
     }
 
-    /* Enumerate sub keys of hInterfaceKey */
-    i = 0;
-    while (TRUE)
+    if (RequiredSizeA <= PropertyBufferSize)
     {
-        dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
-        rc = RegEnumKeyExW(hInterfaceKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
-        if (rc == ERROR_NO_MORE_ITEMS)
-            break;
-        if (rc != ERROR_SUCCESS)
-            goto cleanup;
-        i++;
-
-        /* Open sub key */
-        if (hDeviceInstanceKey != NULL)
-            RegCloseKey(hDeviceInstanceKey);
-        rc = RegOpenKeyExW(hInterfaceKey, KeyBuffer, 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hDeviceInstanceKey);
-        if (rc != ERROR_SUCCESS)
-            goto cleanup;
-
-        /* Read DeviceInstance */
-        rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, &dwRegType, NULL, &dwInstancePathLength);
-        if (rc != ERROR_SUCCESS)
-            goto cleanup;
-        if (dwRegType != REG_SZ)
-        {
-            rc = ERROR_GEN_FAILURE;
-            goto cleanup;
-        }
-        HeapFree(GetProcessHeap(), 0, InstancePath);
-        InstancePath = HeapAlloc(GetProcessHeap(), 0, dwInstancePathLength + sizeof(WCHAR));
-        if (!InstancePath)
-        {
-            rc = ERROR_NOT_ENOUGH_MEMORY;
-            goto cleanup;
-        }
-        rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, NULL, (LPBYTE)InstancePath, &dwInstancePathLength);
-        if (rc != ERROR_SUCCESS)
-            goto cleanup;
-        InstancePath[dwInstancePathLength / sizeof(WCHAR)] = '\0';
-        TRACE("DeviceInstance %s\n", debugstr_w(InstancePath));
-
-        if (DeviceInstanceW)
-        {
-            /* Check if device enumerator is not the right one */
-            if (strcmpW(DeviceInstanceW, InstancePath) != 0)
-                continue;
-        }
-
-        /* Find class GUID associated to the device instance */
-        rc = RegOpenKeyExW(
-            list->HKLM,
-            REGSTR_PATH_SYSTEMENUM,
-            0, /* Options */
-            0,
-            &hEnumKey);
-        if (rc != ERROR_SUCCESS)
-            goto cleanup;
-        rc = RegOpenKeyExW(
-            hEnumKey,
-            InstancePath,
-            0, /* Options */
-            KEY_QUERY_VALUE,
-            &hKey);
-        RegCloseKey(hEnumKey);
-        if (rc != ERROR_SUCCESS)
-            goto cleanup;
-        dwLength = sizeof(KeyBuffer) - sizeof(WCHAR);
-        rc = RegQueryValueExW(hKey, ClassGUID, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
-        RegCloseKey(hKey);
-        if (rc != ERROR_SUCCESS)
-            goto cleanup;
-        KeyBuffer[dwLength / sizeof(WCHAR)] = '\0';
-        KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */
-        if (UuidFromStringW(&KeyBuffer[1], &ClassGuid) != RPC_S_OK)
-        {
-            rc = ERROR_GEN_FAILURE;
-            goto cleanup;
-        }
-        TRACE("ClassGUID %s\n", debugstr_guid(&ClassGuid));
-
-        /* If current device doesn't match the list GUID (if any), skip this entry */
-        if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, &ClassGuid))
-            continue;
-
-        /* Enumerate subkeys of hDeviceInstanceKey (ie "#ReferenceString" in IoRegisterDeviceInterface). Skip entries that don't start with '#' */
-        j = 0;
-        while (TRUE)
+        if (bIsStringProperty && PropertyBufferSize > 0)
         {
-            struct DeviceInterface *interfaceInfo;
-
-            dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
-            rc = RegEnumKeyExW(hDeviceInstanceKey, j, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
-            if (rc == ERROR_NO_MORE_ITEMS)
-                break;
-            if (rc != ERROR_SUCCESS)
-                goto cleanup;
-            j++;
-            if (KeyBuffer[0] != '#')
-                /* This entry doesn't represent an interesting entry */
-                continue;
-
-            /* Open sub key */
-            if (hReferenceKey != NULL)
-                RegCloseKey(hReferenceKey);
-            rc = RegOpenKeyExW(hDeviceInstanceKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hReferenceKey);
-            if (rc != ERROR_SUCCESS)
-                goto cleanup;
-
-            /* Read SymbolicLink value */
-            rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, &dwRegType, NULL, &dwLength);
-            if (rc != ERROR_SUCCESS )
-                goto cleanup;
-            if (dwRegType != REG_SZ)
-            {
-                rc = ERROR_GEN_FAILURE;
-                goto cleanup;
-            }
-
-            /* We have found a device */
-            /* Step 1. Create a device info element */
-            if (!CreateDeviceInfoElement(list, InstancePath, &ClassGuid, &deviceInfo))
-            {
-                rc = GetLastError();
-                goto cleanup;
-            }
-            TRACE("Adding device %s to list\n", debugstr_w(InstancePath));
-            InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
-
-            /* Step 2. Create an interface list for this element */
-            HeapFree(GetProcessHeap(), 0, pSymbolicLink);
-            pSymbolicLink = HeapAlloc(GetProcessHeap(), 0, (dwLength + 1) * sizeof(WCHAR));
-            if (!pSymbolicLink)
-            {
-                rc = ERROR_NOT_ENOUGH_MEMORY;
-                goto cleanup;
-            }
-            rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, NULL, (LPBYTE)pSymbolicLink, &dwLength);
-            pSymbolicLink[dwLength / sizeof(WCHAR)] = '\0';
-            if (rc != ERROR_SUCCESS)
-                goto cleanup;
-            if (!CreateDeviceInterface(deviceInfo, pSymbolicLink, InterfaceGuid, &interfaceInfo))
-            {
-                rc = GetLastError();
-                goto cleanup;
-            }
-
-            /* Step 3. Update flags */
-            if (KeyBuffer[1] == '\0')
-                interfaceInfo->Flags |= SPINT_DEFAULT;
-            rc = RegOpenKeyExW(hReferenceKey, Control, 0, KEY_QUERY_VALUE, &hControlKey);
-            if (rc != ERROR_SUCCESS)
-            {
-                if (OnlyPresentInterfaces)
-                {
-                    DestroyDeviceInterface(interfaceInfo);
-                    continue;
-                }
-                else
-                    interfaceInfo->Flags |= SPINT_REMOVED;
-            }
-            else
+            if (WideCharToMultiByte(CP_ACP, 0, (LPWSTR)PropertyBufferW, RequiredSizeW / sizeof(WCHAR), (LPSTR)PropertyBuffer, PropertyBufferSize, NULL, NULL) == 0)
             {
-                dwLength = sizeof(DWORD);
-                if (RegQueryValueExW(hControlKey, Linked, NULL, &dwRegType, (LPBYTE)&LinkedValue, &dwLength)
-                    && dwRegType == REG_DWORD && LinkedValue)
-                    interfaceInfo->Flags |= SPINT_ACTIVE;
-                RegCloseKey(hControlKey);
+                /* Last error is already set by WideCharToMultiByte */
+                bResult = FALSE;
             }
-
-            TRACE("Adding interface %s to list\n", debugstr_w(pSymbolicLink));
-            InsertTailList(&deviceInfo->InterfaceListHead, &interfaceInfo->ListEntry);
-        }
-    }
-    rc = ERROR_SUCCESS;
-
-cleanup:
-    if (hReferenceKey != NULL)
-        RegCloseKey(hReferenceKey);
-    if (hDeviceInstanceKey != NULL)
-        RegCloseKey(hDeviceInstanceKey);
-    if (hInterfaceKey != INVALID_HANDLE_VALUE)
-        RegCloseKey(hInterfaceKey);
-    HeapFree(GetProcessHeap(), 0, InstancePath);
-    HeapFree(GetProcessHeap(), 0, pSymbolicLink);
-    return rc;
-}
-
-/***********************************************************************
- *             SetupDiGetClassDevsExW (SETUPAPI.@)
- */
-HDEVINFO WINAPI
-SetupDiGetClassDevsExW(
-    IN CONST GUID *ClassGuid OPTIONAL,
-    IN PCWSTR Enumerator OPTIONAL,
-    IN HWND hwndParent OPTIONAL,
-    IN DWORD Flags,
-    IN HDEVINFO DeviceInfoSet OPTIONAL,
-    IN PCWSTR MachineName OPTIONAL,
-    IN PVOID Reserved)
-{
-    HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
-    struct DeviceInfoSet *list;
-    CONST GUID *pClassGuid;
-    LONG rc;
-    HDEVINFO ret = INVALID_HANDLE_VALUE;
-
-    TRACE("%s %s %p 0x%08lx %p %s %p\n", debugstr_guid(ClassGuid), debugstr_w(Enumerator),
-        hwndParent, Flags, DeviceInfoSet, debugstr_w(MachineName), Reserved);
-
-    /* Create the deviceset if not set */
-    if (DeviceInfoSet)
-    {
-        list = (struct DeviceInfoSet *)DeviceInfoSet;
-        if (list->magic != SETUP_DEV_INFO_SET_MAGIC)
-        {
-            SetLastError(ERROR_INVALID_HANDLE);
-            goto cleanup;
-        }
-        hDeviceInfo = DeviceInfoSet;
-    }
-    else
-    {
-         hDeviceInfo = SetupDiCreateDeviceInfoListExW(
-             Flags & DIGCF_DEVICEINTERFACE ? NULL : ClassGuid,
-             NULL, MachineName, NULL);
-         if (hDeviceInfo == INVALID_HANDLE_VALUE)
-             goto cleanup;
-         list = (struct DeviceInfoSet *)hDeviceInfo;
-    }
-
-    if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
-        pClassGuid = NULL;
-    else
-        pClassGuid = &list->ClassGuid;
-
-    if (Flags & DIGCF_PROFILE)
-        FIXME(": flag DIGCF_PROFILE ignored\n");
-
-    if (Flags & DIGCF_ALLCLASSES)
-    {
-        rc = SETUP_CreateDevList(list, MachineName, pClassGuid, Enumerator);
-        if (rc != ERROR_SUCCESS)
-        {
-            SetLastError(rc);
-            goto cleanup;
-        }
-        ret = hDeviceInfo;
-    }
-    else if (Flags & DIGCF_DEVICEINTERFACE)
-    {
-        if (ClassGuid == NULL)
-        {
-            SetLastError(ERROR_INVALID_PARAMETER);
-            goto cleanup;
-        }
-
-        rc = SETUP_CreateInterfaceList(list, MachineName, ClassGuid, Enumerator, Flags & DIGCF_PRESENT);
-        if (rc != ERROR_SUCCESS)
-        {
-            SetLastError(rc);
-            goto cleanup;
         }
-        ret = hDeviceInfo;
+        else
+            memcpy(PropertyBuffer, PropertyBufferW, RequiredSizeA);
     }
     else
     {
-        rc = SETUP_CreateDevList(list, MachineName, ClassGuid, Enumerator);
-        if (rc != ERROR_SUCCESS)
-        {
-            SetLastError(rc);
-            goto cleanup;
-        }
-        ret = hDeviceInfo;
+        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        bResult = FALSE;
     }
 
-cleanup:
-    if (!DeviceInfoSet && hDeviceInfo != INVALID_HANDLE_VALUE && hDeviceInfo != ret)
-        SetupDiDestroyDeviceInfoList(hDeviceInfo);
-    return ret;
+    HeapFree(GetProcessHeap(), 0, PropertyBufferW);
+    return bResult;
 }
 
 /***********************************************************************
- *             SetupDiGetClassImageIndex (SETUPAPI.@)
+ *             SetupDiGetDeviceRegistryPropertyW (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, REGSTR_VAL_INSICON, 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, REGSTR_VAL_INSICON, 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)
+SetupDiGetDeviceRegistryPropertyW(
+    IN HDEVINFO DeviceInfoSet,
+    IN PSP_DEVINFO_DATA DeviceInfoData,
+    IN DWORD Property,
+    OUT PDWORD PropertyRegDataType OPTIONAL,
+    OUT PBYTE PropertyBuffer OPTIONAL,
+    IN DWORD PropertyBufferSize,
+    OUT PDWORD  RequiredSize OPTIONAL)
 {
-    struct ClassImageList *list;
+    HKEY hEnumKey, hKey;
+    DWORD rc;
     BOOL ret = FALSE;
 
-    TRACE("%p %s %p\n", ClassImageListData, debugstr_guid(ClassGuid), ImageIndex);
+    TRACE("%p %p %ld %p %p %ld %p\n", DeviceInfoSet, DeviceInfoData,
+        Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
+        RequiredSize);
 
-    if (!ClassImageListData || !ClassGuid || !ImageIndex)
+    if (!DeviceInfoSet || 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 (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)
+    else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
         SetLastError(ERROR_INVALID_USER_BUFFER);
-    else if (!ImageIndex)
+    else if (Property >= SPDRP_MAXIMUM_PROPERTY)
         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;
+        struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
+        struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
 
-        if (iconIndex >= 0)
+        switch (Property)
         {
-            SetLastError(ERROR_INVALID_INDEX);
-            goto cleanup;
-        }
+            case SPDRP_CAPABILITIES:
+            case SPDRP_CLASS:
+            case SPDRP_CLASSGUID:
+            case SPDRP_COMPATIBLEIDS:
+            case SPDRP_CONFIGFLAGS:
+            case SPDRP_DEVICEDESC:
+            case SPDRP_DRIVER:
+            case SPDRP_FRIENDLYNAME:
+            case SPDRP_HARDWAREID:
+            case SPDRP_LOCATION_INFORMATION:
+            case SPDRP_LOWERFILTERS:
+            case SPDRP_MFG:
+            case SPDRP_SECURITY:
+            case SPDRP_SERVICE:
+            case SPDRP_UI_NUMBER:
+            case SPDRP_UI_NUMBER_DESC_FORMAT:
+            case SPDRP_UPPERFILTERS:
+            {
+                LPCWSTR RegistryPropertyName;
+                DWORD BufferSize;
 
-        *ImageIndex = -iconIndex;
-        ret = TRUE;
+                switch (Property)
+                {
+                    case SPDRP_CAPABILITIES:
+                        RegistryPropertyName = REGSTR_VAL_CAPABILITIES; break;
+                    case SPDRP_CLASS:
+                        RegistryPropertyName = REGSTR_VAL_CLASS; break;
+                    case SPDRP_CLASSGUID:
+                        RegistryPropertyName = REGSTR_VAL_CLASSGUID; break;
+                    case SPDRP_COMPATIBLEIDS:
+                        RegistryPropertyName = REGSTR_VAL_COMPATIBLEIDS; break;
+                    case SPDRP_CONFIGFLAGS:
+                        RegistryPropertyName = REGSTR_VAL_CONFIGFLAGS; break;
+                    case SPDRP_DEVICEDESC:
+                        RegistryPropertyName = REGSTR_VAL_DEVDESC; break;
+                    case SPDRP_DRIVER:
+                        RegistryPropertyName = REGSTR_VAL_DRIVER; break;
+                    case SPDRP_FRIENDLYNAME:
+                        RegistryPropertyName = REGSTR_VAL_FRIENDLYNAME; break;
+                    case SPDRP_HARDWAREID:
+                        RegistryPropertyName = REGSTR_VAL_HARDWAREID; break;
+                    case SPDRP_LOCATION_INFORMATION:
+                        RegistryPropertyName = REGSTR_VAL_LOCATION_INFORMATION; break;
+                    case SPDRP_LOWERFILTERS:
+                        RegistryPropertyName = REGSTR_VAL_LOWERFILTERS; break;
+                    case SPDRP_MFG:
+                        RegistryPropertyName = REGSTR_VAL_MFG; break;
+                    case SPDRP_SECURITY:
+                        RegistryPropertyName = REGSTR_SECURITY; break;
+                    case SPDRP_SERVICE:
+                        RegistryPropertyName = REGSTR_VAL_SERVICE; break;
+                    case SPDRP_UI_NUMBER:
+                        RegistryPropertyName = REGSTR_VAL_UI_NUMBER; break;
+                    case SPDRP_UI_NUMBER_DESC_FORMAT:
+                        RegistryPropertyName = REGSTR_UI_NUMBER_DESC_FORMAT; break;
+                    case SPDRP_UPPERFILTERS:
+                        RegistryPropertyName = REGSTR_VAL_UPPERFILTERS; break;
+                    default:
+                        /* Should not happen */
+                        RegistryPropertyName = NULL; break;
+                }
 
-cleanup:
-        if (hKey != INVALID_HANDLE_VALUE)
-            RegCloseKey(hKey);
-    }
+                /* Open registry key name */
+                rc = RegOpenKeyExW(
+                    list->HKLM,
+                    REGSTR_PATH_SYSTEMENUM,
+                    0, /* Options */
+                    0,
+                    &hEnumKey);
+                if (rc != ERROR_SUCCESS)
+                {
+                    SetLastError(rc);
+                    break;
+                }
+                rc = RegOpenKeyExW(
+                    hEnumKey,
+                    DevInfo->Data,
+                    0, /* Options */
+                    KEY_QUERY_VALUE,
+                    &hKey);
+                RegCloseKey(hEnumKey);
+                if (rc != ERROR_SUCCESS)
+                {
+                    SetLastError(rc);
+                    break;
+                }
+                /* Read registry entry */
+                BufferSize = PropertyBufferSize;
+                rc = RegQueryValueExW(
+                    hKey,
+                    RegistryPropertyName,
+                    NULL, /* Reserved */
+                    PropertyRegDataType,
+                    PropertyBuffer,
+                    &BufferSize);
+                if (RequiredSize)
+                    *RequiredSize = BufferSize;
+                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;
+            }
 
-    TRACE("Returning %d\n", ret);
-    return ret;
-}
+            case SPDRP_PHYSICAL_DEVICE_OBJECT_NAME:
+            {
+                DWORD required = (strlenW(DevInfo->Data) + 1) * sizeof(WCHAR);
 
-/***********************************************************************
- *             SetupDiGetClassImageList(SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiGetClassImageList(
-    OUT PSP_CLASSIMAGELIST_DATA ClassImageListData)
-{
-    return SetupDiGetClassImageListExW(ClassImageListData, NULL, NULL);
-}
+                if (PropertyRegDataType)
+                    *PropertyRegDataType = REG_SZ;
+                if (RequiredSize)
+                    *RequiredSize = required;
+                if (PropertyBufferSize >= required)
+                {
+                    strcpyW((LPWSTR)PropertyBuffer, DevInfo->Data);
+                    ret = TRUE;
+                }
+                else
+                    SetLastError(ERROR_INSUFFICIENT_BUFFER);
+                break;
+            }
 
-/***********************************************************************
- *             SetupDiGetClassImageListExA(SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiGetClassImageListExA(
-    OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
-    IN PCSTR MachineName OPTIONAL,
-    IN PVOID Reserved)
-{
-    PWSTR MachineNameW = NULL;
-    BOOL ret;
+            /*case SPDRP_BUSTYPEGUID:
+            case SPDRP_LEGACYBUSTYPE:
+            case SPDRP_BUSNUMBER:
+            case SPDRP_ENUMERATOR_NAME:
+            case SPDRP_SECURITY_SDS:
+            case SPDRP_DEVTYPE:
+            case SPDRP_EXCLUSIVE:
+            case SPDRP_CHARACTERISTICS:
+            case SPDRP_ADDRESS:
+            case SPDRP_DEVICE_POWER_DATA:*/
+#if (WINVER >= 0x501)
+            /*case SPDRP_REMOVAL_POLICY:
+            case SPDRP_REMOVAL_POLICY_HW_DEFAULT:
+            case SPDRP_REMOVAL_POLICY_OVERRIDE:
+            case SPDRP_INSTALL_STATE:*/
+#endif
 
-    if (MachineName)
-    {
-        MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
-        if (MachineNameW == NULL)
-            return FALSE;
+            default:
+            {
+                ERR("Property 0x%lx not implemented\n", Property);
+                SetLastError(ERROR_NOT_SUPPORTED);
+            }
+        }
     }
 
-    ret = SetupDiGetClassImageListExW(ClassImageListData, MachineNameW, Reserved);
-
-    if (MachineNameW)
-        MyFree(MachineNameW);
-
+    TRACE("Returning %d\n", ret);
     return ret;
 }
 
 /***********************************************************************
- *             SetupDiGetClassImageListExW(SETUPAPI.@)
+ *             SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
  */
 BOOL WINAPI
-SetupDiGetClassImageListExW(
-    OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
-    IN PCWSTR MachineName OPTIONAL,
-    IN PVOID Reserved)
+SetupDiSetDeviceRegistryPropertyA(
+    IN HDEVINFO DeviceInfoSet,
+    IN OUT PSP_DEVINFO_DATA DeviceInfoData,
+    IN DWORD Property,
+    IN CONST BYTE *PropertyBuffer OPTIONAL,
+    IN DWORD PropertyBufferSize)
 {
-    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 += (strlenW(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 = (ULONG_PTR)list;
-        ret = TRUE;
-
-cleanup:
-        if (!ret)
-            MyFree(list);
-    }
-
-    TRACE("Returning %d\n", ret);
-    return ret;
+    FIXME("%p %p 0x%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
+        Property, PropertyBuffer, PropertyBufferSize);
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return FALSE;
 }
 
 /***********************************************************************
- *             SetupDiLoadClassIcon(SETUPAPI.@)
+ *             SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
  */
 BOOL WINAPI
-SetupDiLoadClassIcon(
-    IN CONST GUID *ClassGuid,
-    OUT HICON *LargeIcon OPTIONAL,
-    OUT PINT MiniIconIndex OPTIONAL)
+SetupDiSetDeviceRegistryPropertyW(
+    IN HDEVINFO DeviceInfoSet,
+    IN OUT PSP_DEVINFO_DATA DeviceInfoData,
+    IN DWORD Property,
+    IN CONST BYTE *PropertyBuffer OPTIONAL,
+    IN DWORD PropertyBufferSize)
 {
+    struct DeviceInfoSet *list;
     BOOL ret = FALSE;
 
-    if (!ClassGuid)
-        SetLastError(ERROR_INVALID_PARAMETER);
+    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
     {
-        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)
+        switch (Property)
         {
-            /* Look up icon in dll specified by Installer32 or EnumPropPages32 key */
-            PWCHAR Comma;
-            LONG rc;
-            DWORD dwRegType, dwLength;
-            rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, 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, REGSTR_VAL_INSTALLER_32, 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, REGSTR_VAL_ENUMPROPPAGES_32, NULL, &dwRegType, NULL, &dwLength))
-                && dwRegType == REG_SZ)
+            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:
             {
-                Buffer = MyMalloc(dwLength + sizeof(WCHAR));
-                if (Buffer == NULL)
+                LPCWSTR RegistryPropertyName;
+                DWORD RegistryDataType;
+                HKEY hKey;
+                LONG rc;
+
+                switch (Property)
                 {
-                    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-                    goto cleanup;
+                    case SPDRP_COMPATIBLEIDS:
+                        RegistryPropertyName = REGSTR_VAL_COMPATIBLEIDS;
+                        RegistryDataType = REG_MULTI_SZ;
+                        break;
+                    case SPDRP_CONFIGFLAGS:
+                        RegistryPropertyName = REGSTR_VAL_CONFIGFLAGS;
+                        RegistryDataType = REG_DWORD;
+                        break;
+                    case SPDRP_FRIENDLYNAME:
+                        RegistryPropertyName = REGSTR_VAL_FRIENDLYNAME;
+                        RegistryDataType = REG_SZ;
+                        break;
+                    case SPDRP_HARDWAREID:
+                        RegistryPropertyName = REGSTR_VAL_HARDWAREID;
+                        RegistryDataType = REG_MULTI_SZ;
+                        break;
+                    case SPDRP_LOCATION_INFORMATION:
+                        RegistryPropertyName = REGSTR_VAL_LOCATION_INFORMATION;
+                        RegistryDataType = REG_SZ;
+                        break;
+                    case SPDRP_LOWERFILTERS:
+                        RegistryPropertyName = REGSTR_VAL_LOWERFILTERS;
+                        RegistryDataType = REG_MULTI_SZ;
+                        break;
+                    case SPDRP_SECURITY:
+                        RegistryPropertyName = REGSTR_SECURITY;
+                        RegistryDataType = REG_BINARY;
+                        break;
+                    case SPDRP_SERVICE:
+                        RegistryPropertyName = REGSTR_VAL_SERVICE;
+                        RegistryDataType = REG_SZ;
+                        break;
+                    case SPDRP_UI_NUMBER_DESC_FORMAT:
+                        RegistryPropertyName = REGSTR_UI_NUMBER_DESC_FORMAT;
+                        RegistryDataType = REG_SZ;
+                        break;
+                    case SPDRP_UPPERFILTERS:
+                        RegistryPropertyName = REGSTR_VAL_UPPERFILTERS;
+                        RegistryDataType = REG_MULTI_SZ;
+                        break;
+                    default:
+                        /* Should not happen */
+                        RegistryPropertyName = NULL;
+                        RegistryDataType = REG_BINARY;
+                        break;
                 }
-                rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, NULL, (LPBYTE)Buffer, &dwLength);
-                if (rc != ERROR_SUCCESS)
+                /* Open device registry key */
+                hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE);
+                if (hKey != INVALID_HANDLE_VALUE)
                 {
-                    SetLastError(rc);
-                    goto cleanup;
+                    /* Write new data */
+                    rc = RegSetValueExW(
+                        hKey,
+                        RegistryPropertyName,
+                        0, /* Reserved */
+                        RegistryDataType,
+                        PropertyBuffer,
+                        PropertyBufferSize);
+                    if (rc == ERROR_SUCCESS)
+                        ret = TRUE;
+                    else
+                        SetLastError(rc);
+                    RegCloseKey(hKey);
                 }
-                /* 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;
+                break;
             }
-            *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))
+            /*case SPDRP_CHARACTERISTICS:
+            case SPDRP_DEVTYPE:
+            case SPDRP_EXCLUSIVE:*/
+#if (WINVER >= 0x501)
+            //case SPDRP_REMOVAL_POLICY_OVERRIDE:
+#endif
+            //case SPDRP_SECURITY_SDS:
+
+            default:
             {
-                SetLastError(ERROR_INVALID_INDEX);
-                goto cleanup;
+                ERR("Property 0x%lx not implemented\n", Property);
+                SetLastError(ERROR_NOT_SUPPORTED);
             }
         }
-        if (MiniIconIndex)
-            *MiniIconIndex = iconIndex;
-        ret = TRUE;
-
-cleanup:
-        if (hKey != INVALID_HANDLE_VALUE)
-            RegCloseKey(hKey);
-        MyFree(Buffer);
     }
 
     TRACE("Returning %d\n", ret);
     return ret;
 }
 
+
+static BOOL WINAPI
+IntSetupDiRegisterDeviceInfo(
+    IN HDEVINFO DeviceInfoSet,
+    IN OUT PSP_DEVINFO_DATA DeviceInfoData)
+{
+    return SetupDiRegisterDeviceInfo(DeviceInfoSet, DeviceInfoData, 0, NULL, NULL, NULL);
+}
+
 /***********************************************************************
- *             SetupDiEnumDeviceInterfaces (SETUPAPI.@)
+ *             SetupDiCallClassInstaller (SETUPAPI.@)
  */
 BOOL WINAPI
-SetupDiEnumDeviceInterfaces(
+SetupDiCallClassInstaller(
+    IN DI_FUNCTION InstallFunction,
     IN HDEVINFO DeviceInfoSet,
-    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
-    IN CONST GUID *InterfaceClassGuid,
-    IN DWORD MemberIndex,
-    OUT PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
+    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
 {
     BOOL ret = FALSE;
 
-    TRACE("%p, %p, %s, %ld, %p\n", DeviceInfoSet, DeviceInfoData,
-     debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData);
+    TRACE("%u %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
 
-    if (!DeviceInterfaceData)
+    if (!DeviceInfoSet)
         SetLastError(ERROR_INVALID_PARAMETER);
-    else if (DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
+    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 (((struct DeviceInfoSet *)DeviceInfoSet)->HKLM != HKEY_LOCAL_MACHINE)
+        SetLastError(ERROR_INVALID_HANDLE);
+    else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
         SetLastError(ERROR_INVALID_USER_BUFFER);
-    else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
+    else
     {
-        struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
+        SP_DEVINSTALL_PARAMS_W InstallParams;
+#define CLASS_COINSTALLER  0x1
+#define DEVICE_COINSTALLER 0x2
+#define CLASS_INSTALLER    0x4
+        UCHAR CanHandle = 0;
+        DEFAULT_CLASS_INSTALL_PROC DefaultHandler = NULL;
 
-        if (list->magic == SETUP_DEV_INFO_SET_MAGIC)
+        switch (InstallFunction)
         {
-            PLIST_ENTRY ItemList = list->ListHead.Flink;
-            BOOL Found = FALSE;
-            while (ItemList != &list->ListHead && !Found)
-            {
-                PLIST_ENTRY InterfaceListEntry;
-                struct DeviceInfoElement *DevInfo = CONTAINING_RECORD(ItemList, struct DeviceInfoElement, ListEntry);
-                if (DeviceInfoData && (struct DeviceInfoElement *)DeviceInfoData->Reserved != DevInfo)
-                {
-                    /* We are not searching for this element */
-                    ItemList = ItemList->Flink;
-                    continue;
-                }
-                InterfaceListEntry = DevInfo->InterfaceListHead.Flink;
-                while (InterfaceListEntry != &DevInfo->InterfaceListHead && !Found)
-                {
-                    struct DeviceInterface *DevItf = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
-                    if (!IsEqualIID(&DevItf->InterfaceClassGuid, InterfaceClassGuid))
-                    {
-                        InterfaceListEntry = InterfaceListEntry->Flink;
-                        continue;
-                    }
-                    if (MemberIndex-- == 0)
-                    {
-                        /* return this item */
-                        memcpy(&DeviceInterfaceData->InterfaceClassGuid,
-                            &DevItf->InterfaceClassGuid,
-                            sizeof(GUID));
-                        DeviceInterfaceData->Flags = DevItf->Flags;
-                        DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
-                        Found = TRUE;
-                    }
-                    InterfaceListEntry = InterfaceListEntry->Flink;
-                }
-                ItemList = ItemList->Flink;
-            }
-            if (!Found)
-                SetLastError(ERROR_NO_MORE_ITEMS);
-            else
-                ret = TRUE;
+            case DIF_ADDPROPERTYPAGE_ADVANCED:
+                CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
+                break;
+            case DIF_ADDREMOTEPROPERTYPAGE_ADVANCED:
+                CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
+                break;
+            case DIF_ALLOW_INSTALL:
+                CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
+                break;
+            case DIF_DETECT:
+                CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
+                break;
+            case DIF_DESTROYPRIVATEDATA:
+                CanHandle = CLASS_INSTALLER;
+                break;
+            case DIF_INSTALLDEVICE:
+                CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
+                DefaultHandler = SetupDiInstallDevice;
+                break;
+            case DIF_INSTALLDEVICEFILES:
+                CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
+                DefaultHandler = SetupDiInstallDriverFiles;
+                break;
+            case DIF_INSTALLINTERFACES:
+                CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
+                DefaultHandler = SetupDiInstallDeviceInterfaces;
+                break;
+            case DIF_NEWDEVICEWIZARD_FINISHINSTALL:
+                CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
+                break;
+            case DIF_NEWDEVICEWIZARD_POSTANALYZE:
+                CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
+                break;
+            case DIF_NEWDEVICEWIZARD_PREANALYZE:
+                CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
+                break;
+            case DIF_NEWDEVICEWIZARD_PRESELECT:
+                CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
+                break;
+            case DIF_NEWDEVICEWIZARD_SELECT:
+                CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
+                break;
+            case DIF_POWERMESSAGEWAKE:
+                CanHandle = CLASS_COINSTALLER | DEVICE_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;
+                break;
+            case DIF_REGISTERDEVICE:
+                CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
+                DefaultHandler = IntSetupDiRegisterDeviceInfo;
+                break;
+            case DIF_REMOVE:
+                CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
+                DefaultHandler = SetupDiRemoveDevice;
+                break;
+            case DIF_SELECTBESTCOMPATDRV:
+                CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
+                DefaultHandler = SetupDiSelectBestCompatDrv;
+                break;
+            case DIF_SELECTDEVICE:
+                CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
+                DefaultHandler = SetupDiSelectDevice;
+                break;
+            case DIF_TROUBLESHOOTER:
+                CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
+                break;
+            case DIF_UNREMOVE:
+                CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
+                DefaultHandler = SetupDiUnremoveDevice;
+                break;
+            default:
+                ERR("Install function %u not supported\n", InstallFunction);
+                SetLastError(ERROR_NOT_SUPPORTED);
         }
-        else
-            SetLastError(ERROR_INVALID_HANDLE);
-    }
-    else
-        SetLastError(ERROR_INVALID_HANDLE);
-    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
-DestroyClassInstallParams(struct ClassInstallParams* installParams)
-{
-    return HeapFree(GetProcessHeap(), 0, installParams->PropChange);
-}
-
-static BOOL
-DestroyDeviceInfoElement(struct DeviceInfoElement* deviceInfo)
-{
-    PLIST_ENTRY ListEntry;
-    struct DriverInfoElement *driverInfo;
-    struct DeviceInterface *deviceInterface;
-
-    while (!IsListEmpty(&deviceInfo->DriverListHead))
-    {
-        ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
-        driverInfo = CONTAINING_RECORD(ListEntry, struct DriverInfoElement, ListEntry);
-        if (!DestroyDriverInfoElement(driverInfo))
-            return FALSE;
-    }
-    while (!IsListEmpty(&deviceInfo->InterfaceListHead))
-    {
-        ListEntry = RemoveHeadList(&deviceInfo->InterfaceListHead);
-        deviceInterface = CONTAINING_RECORD(ListEntry, struct DeviceInterface, ListEntry);
-        if (!DestroyDeviceInterface(deviceInterface))
-            return FALSE;
-    }
-    DestroyClassInstallParams(&deviceInfo->ClassInstallParams);
-    return HeapFree(GetProcessHeap(), 0, deviceInfo);
-}
-
-static BOOL
-DestroyDeviceInfoSet(struct DeviceInfoSet* list)
-{
-    PLIST_ENTRY ListEntry;
-    struct DeviceInfoElement *deviceInfo;
-
-    while (!IsListEmpty(&list->ListHead))
-    {
-        ListEntry = RemoveHeadList(&list->ListHead);
-        deviceInfo = CONTAINING_RECORD(ListEntry, struct DeviceInfoElement, ListEntry);
-        if (!DestroyDeviceInfoElement(deviceInfo))
-            return FALSE;
-    }
-    if (list->HKLM != HKEY_LOCAL_MACHINE)
-        RegCloseKey(list->HKLM);
-    CM_Disconnect_Machine(list->hMachine);
-    DestroyClassInstallParams(&list->ClassInstallParams);
-    return HeapFree(GetProcessHeap(), 0, list);
-}
-
-/***********************************************************************
- *             SetupDiDestroyDeviceInfoList (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiDestroyDeviceInfoList(
-    IN HDEVINFO DeviceInfoSet)
-{
-    BOOL ret = FALSE;
-
-    TRACE("%p\n", DeviceInfoSet);
-    if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
-    {
-        struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
-
-        if (list->magic == SETUP_DEV_INFO_SET_MAGIC)
-            ret = DestroyDeviceInfoSet(list);
-        else
-            SetLastError(ERROR_INVALID_HANDLE);
-    }
-    else
-        SetLastError(ERROR_INVALID_HANDLE);
 
-    TRACE("Returning %d\n", ret);
-    return ret;
-}
+        InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
+        if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
+            /* Don't process this call, as a parameter is invalid */
+            CanHandle = 0;
 
-/***********************************************************************
- *             SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiGetDeviceInterfaceDetailA(
-    IN HDEVINFO DeviceInfoSet,
-    IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
-    OUT PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData OPTIONAL,
-    IN DWORD DeviceInterfaceDetailDataSize,
-    OUT PDWORD RequiredSize OPTIONAL,
-    OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
-{
-    PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailDataW = NULL;
-    DWORD sizeW = 0, sizeA;
-    BOOL ret = FALSE;
+        if (CanHandle != 0)
+        {
+            LIST_ENTRY ClassCoInstallersListHead;
+            LIST_ENTRY DeviceCoInstallersListHead;
+            HMODULE ClassInstallerLibrary = NULL;
+            CLASS_INSTALL_PROC ClassInstaller = NULL;
+            COINSTALLER_CONTEXT_DATA Context;
+            PLIST_ENTRY ListEntry;
+            HKEY hKey;
+            DWORD dwRegType, dwLength;
+            DWORD rc = NO_ERROR;
 
-    TRACE("%p %p %p %lu %p %p\n", DeviceInfoSet,
-        DeviceInterfaceData, DeviceInterfaceDetailData,
-        DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
+            InitializeListHead(&ClassCoInstallersListHead);
+            InitializeListHead(&DeviceCoInstallersListHead);
 
-    if (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A))
-        SetLastError(ERROR_INVALID_USER_BUFFER);
-    else if (DeviceInterfaceDetailData == NULL && DeviceInterfaceDetailDataSize != 0)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else if (DeviceInterfaceDetailData != NULL && DeviceInterfaceDetailDataSize < FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + 1)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else
-    {
-        if (DeviceInterfaceDetailData != NULL)
-        {
-            sizeW = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
-                + (DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath)) * sizeof(WCHAR);
-            DeviceInterfaceDetailDataW = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)HeapAlloc(GetProcessHeap(), 0, sizeW);
-            if (!DeviceInterfaceDetailDataW)
+            if (CanHandle & DEVICE_COINSTALLER)
             {
-                SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
+                if (hKey != INVALID_HANDLE_VALUE)
+                {
+                    rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, &dwRegType, NULL, &dwLength);
+                    if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
+                    {
+                        LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
+                        if (KeyBuffer != NULL)
+                        {
+                            rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, 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 (!DeviceInterfaceDetailData || (DeviceInterfaceDetailData && DeviceInterfaceDetailDataW))
-        {
-            DeviceInterfaceDetailDataW->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
-            ret = SetupDiGetDeviceInterfaceDetailW(
-                DeviceInfoSet,
-                DeviceInterfaceData,
-                DeviceInterfaceDetailDataW,
-                sizeW,
-                &sizeW,
-                DeviceInfoData);
-            sizeA = (sizeW - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)) / sizeof(WCHAR)
-                + FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath);
-            if (RequiredSize)
-                *RequiredSize = sizeA;
-            if (ret && DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize <= sizeA)
+            if (CanHandle & CLASS_COINSTALLER)
             {
-                if (!WideCharToMultiByte(
-                    CP_ACP, 0,
-                    DeviceInterfaceDetailDataW->DevicePath, -1,
-                    DeviceInterfaceDetailData->DevicePath, DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
-                    NULL, NULL))
+                rc = RegOpenKeyEx(
+                    HKEY_LOCAL_MACHINE,
+                    REGSTR_PATH_CODEVICEINSTALLERS,
+                    0, /* Options */
+                    KEY_QUERY_VALUE,
+                    &hKey);
+                if (rc == ERROR_SUCCESS)
                 {
-                    ret = FALSE;
+                    LPWSTR lpGuidString;
+                    if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) == RPC_S_OK)
+                    {
+                        rc = RegQueryValueExW(hKey, lpGuidString, NULL, &dwRegType, NULL, &dwLength);
+                        if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
+                        {
+                            LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
+                            if (KeyBuffer != NULL)
+                            {
+                                rc = RegQueryValueExW(hKey, lpGuidString, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
+                                if (rc == ERROR_SUCCESS)
+                                {
+                                    LPWSTR ptr;
+                                    for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
+                                    {
+                                        /* Add coinstaller to ClassCoInstallersListHead list */
+                                        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);
+                            }
+                        }
+                        RpcStringFreeW(&lpGuidString);
+                    }
+                    RegCloseKey(hKey);
                 }
             }
-        }
-        HeapFree(GetProcessHeap(), 0, DeviceInterfaceDetailDataW);
-    }
-
-    TRACE("Returning %d\n", ret);
-    return ret;
-}
-
-/***********************************************************************
- *             SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiGetDeviceInterfaceDetailW(
-    IN HDEVINFO DeviceInfoSet,
-    IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
-    OUT PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData OPTIONAL,
-    IN DWORD DeviceInterfaceDetailDataSize,
-    OUT PDWORD RequiredSize OPTIONAL,
-    OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
-{
-    BOOL ret = FALSE;
-
-    TRACE("%p %p %p %lu %p %p\n", DeviceInfoSet,
-        DeviceInterfaceData, DeviceInterfaceDetailData,
-        DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
-
-    if (!DeviceInfoSet || !DeviceInterfaceData)
-        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 (DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
-        SetLastError(ERROR_INVALID_USER_BUFFER);
-    else if (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W))
-        SetLastError(ERROR_INVALID_USER_BUFFER);
-    else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
-        SetLastError(ERROR_INVALID_USER_BUFFER);
-    else if (DeviceInterfaceDetailData == NULL && DeviceInterfaceDetailDataSize != 0)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else if (DeviceInterfaceDetailData != NULL && DeviceInterfaceDetailDataSize < FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR))
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else
-    {
-        struct DeviceInterface *deviceInterface = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
-        LPCWSTR devName = deviceInterface->SymbolicLink;
-        DWORD sizeRequired = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) +
-            (lstrlenW(devName) + 1) * sizeof(WCHAR);
-
-        if (sizeRequired > DeviceInterfaceDetailDataSize)
-        {
-            SetLastError(ERROR_INSUFFICIENT_BUFFER);
-            if (RequiredSize)
-                *RequiredSize = sizeRequired;
-        }
-        else
-        {
-            strcpyW(DeviceInterfaceDetailData->DevicePath, devName);
-            TRACE("DevicePath is %s\n", debugstr_w(DeviceInterfaceDetailData->DevicePath));
-            if (DeviceInfoData)
+            if ((CanHandle & CLASS_INSTALLER) && !(InstallParams.FlagsEx & DI_FLAGSEX_CI_FAILED))
             {
-                memcpy(&DeviceInfoData->ClassGuid,
-                    &deviceInterface->DeviceInfo->ClassGuid,
-                    sizeof(GUID));
-                DeviceInfoData->DevInst = deviceInterface->DeviceInfo->dnDevInst;
-                DeviceInfoData->Reserved = (ULONG_PTR)deviceInterface->DeviceInfo;
-            }
-            ret = TRUE;
-        }
-    }
-
-    TRACE("Returning %d\n", ret);
-    return ret;
-}
-
-/***********************************************************************
- *             SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiGetDeviceRegistryPropertyA(
-    IN HDEVINFO DeviceInfoSet,
-    IN PSP_DEVINFO_DATA DeviceInfoData,
-    IN DWORD Property,
-    OUT PDWORD PropertyRegDataType OPTIONAL,
-    OUT PBYTE PropertyBuffer OPTIONAL,
-    IN DWORD PropertyBufferSize,
-    OUT PDWORD  RequiredSize OPTIONAL)
-{
-    BOOL bResult;
-    BOOL bIsStringProperty;
-    DWORD RegType;
-    DWORD RequiredSizeA, RequiredSizeW;
-    DWORD PropertyBufferSizeW = 0;
-    PBYTE PropertyBufferW = NULL;
-
-    TRACE("%p %p %ld %p %p %ld %p\n", DeviceInfoSet, DeviceInfoData,
-        Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
-        RequiredSize);
-
-    if (PropertyBufferSize != 0)
-    {
-        PropertyBufferSizeW = PropertyBufferSize * 2;
-        PropertyBufferW = HeapAlloc(GetProcessHeap(), 0, PropertyBufferSizeW);
-        if (!PropertyBufferW)
-        {
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            return FALSE;
-        }
-    }
-
-    bResult = SetupDiGetDeviceRegistryPropertyW(
-        DeviceInfoSet,
-        DeviceInfoData,
-        Property,
-        &RegType,
-        PropertyBufferW,
-        PropertyBufferSizeW,
-        &RequiredSizeW);
-
-    if (bResult || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
-    {
-        bIsStringProperty = (RegType == REG_SZ || RegType == REG_MULTI_SZ || RegType == REG_EXPAND_SZ);
-
-        if (bIsStringProperty)
-           RequiredSizeA = RequiredSizeW / sizeof(WCHAR);
-        else
-            RequiredSizeA = RequiredSizeW;
-        if (RequiredSize)
-            *RequiredSize = RequiredSizeA;
-        if (PropertyRegDataType)
-            *PropertyRegDataType = RegType;
-    }
-
-    if (!bResult)
-    {
-        HeapFree(GetProcessHeap(), 0, PropertyBufferW);
-        return bResult;
-    }
-
-    if (RequiredSizeA <= PropertyBufferSize)
-    {
-        if (bIsStringProperty && PropertyBufferSize > 0)
-        {
-            if (WideCharToMultiByte(CP_ACP, 0, (LPWSTR)PropertyBufferW, RequiredSizeW / sizeof(WCHAR), (LPSTR)PropertyBuffer, PropertyBufferSize, NULL, NULL) == 0)
-            {
-                /* Last error is already set by WideCharToMultiByte */
-                bResult = FALSE;
-            }
-        }
-        else
-            memcpy(PropertyBuffer, PropertyBufferW, RequiredSizeA);
-    }
-    else
-    {
-        SetLastError(ERROR_INSUFFICIENT_BUFFER);
-        bResult = FALSE;
-    }
-
-    HeapFree(GetProcessHeap(), 0, PropertyBufferW);
-    return bResult;
-}
-
-/***********************************************************************
- *             SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiGetDeviceRegistryPropertyW(
-    IN HDEVINFO DeviceInfoSet,
-    IN PSP_DEVINFO_DATA DeviceInfoData,
-    IN DWORD Property,
-    OUT PDWORD PropertyRegDataType OPTIONAL,
-    OUT PBYTE PropertyBuffer OPTIONAL,
-    IN DWORD PropertyBufferSize,
-    OUT PDWORD  RequiredSize OPTIONAL)
-{
-    HKEY hEnumKey, hKey;
-    DWORD rc;
-    BOOL ret = FALSE;
-
-    TRACE("%p %p %ld %p %p %ld %p\n", DeviceInfoSet, DeviceInfoData,
-        Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
-        RequiredSize);
-
-    if (!DeviceInfoSet || 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 if (Property >= SPDRP_MAXIMUM_PROPERTY)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else
-    {
-        struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
-        struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
-
-        switch (Property)
-        {
-            case SPDRP_CAPABILITIES:
-            case SPDRP_CLASS:
-            case SPDRP_CLASSGUID:
-            case SPDRP_COMPATIBLEIDS:
-            case SPDRP_CONFIGFLAGS:
-            case SPDRP_DEVICEDESC:
-            case SPDRP_DRIVER:
-            case SPDRP_FRIENDLYNAME:
-            case SPDRP_HARDWAREID:
-            case SPDRP_LOCATION_INFORMATION:
-            case SPDRP_LOWERFILTERS:
-            case SPDRP_MFG:
-            case SPDRP_SECURITY:
-            case SPDRP_SERVICE:
-            case SPDRP_UI_NUMBER:
-            case SPDRP_UI_NUMBER_DESC_FORMAT:
-            case SPDRP_UPPERFILTERS:
-            {
-                LPCWSTR RegistryPropertyName;
-                DWORD BufferSize;
-
-                switch (Property)
+                hKey = SetupDiOpenClassRegKey(&DeviceInfoData->ClassGuid, KEY_QUERY_VALUE);
+                if (hKey != INVALID_HANDLE_VALUE)
                 {
-                    case SPDRP_CAPABILITIES:
-                        RegistryPropertyName = REGSTR_VAL_CAPABILITIES; break;
-                    case SPDRP_CLASS:
-                        RegistryPropertyName = REGSTR_VAL_CLASS; break;
-                    case SPDRP_CLASSGUID:
-                        RegistryPropertyName = REGSTR_VAL_CLASSGUID; break;
-                    case SPDRP_COMPATIBLEIDS:
-                        RegistryPropertyName = REGSTR_VAL_COMPATIBLEIDS; break;
-                    case SPDRP_CONFIGFLAGS:
-                        RegistryPropertyName = REGSTR_VAL_CONFIGFLAGS; break;
-                    case SPDRP_DEVICEDESC:
-                        RegistryPropertyName = REGSTR_VAL_DEVDESC; break;
-                    case SPDRP_DRIVER:
-                        RegistryPropertyName = REGSTR_VAL_DRIVER; break;
-                    case SPDRP_FRIENDLYNAME:
-                        RegistryPropertyName = REGSTR_VAL_FRIENDLYNAME; break;
-                    case SPDRP_HARDWAREID:
-                        RegistryPropertyName = REGSTR_VAL_HARDWAREID; break;
-                    case SPDRP_LOCATION_INFORMATION:
-                        RegistryPropertyName = REGSTR_VAL_LOCATION_INFORMATION; break;
-                    case SPDRP_LOWERFILTERS:
-                        RegistryPropertyName = REGSTR_VAL_LOWERFILTERS; break;
-                    case SPDRP_MFG:
-                        RegistryPropertyName = REGSTR_VAL_MFG; break;
-                    case SPDRP_SECURITY:
-                        RegistryPropertyName = REGSTR_SECURITY; break;
-                    case SPDRP_SERVICE:
-                        RegistryPropertyName = REGSTR_VAL_SERVICE; break;
-                    case SPDRP_UI_NUMBER:
-                        RegistryPropertyName = REGSTR_VAL_UI_NUMBER; break;
-                    case SPDRP_UI_NUMBER_DESC_FORMAT:
-                        RegistryPropertyName = REGSTR_UI_NUMBER_DESC_FORMAT; break;
-                    case SPDRP_UPPERFILTERS:
-                        RegistryPropertyName = REGSTR_VAL_UPPERFILTERS; break;
-                    default:
-                        /* Should not happen */
-                        RegistryPropertyName = NULL; break;
+                    rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength);
+                    if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
+                    {
+                        LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
+                        if (KeyBuffer != NULL)
+                        {
+                            rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
+                            if (rc == ERROR_SUCCESS)
+                            {
+                                /* Get ClassInstaller function pointer */
+                                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);
+                        }
+                    }
+                    RegCloseKey(hKey);
                 }
+            }
 
-                /* Open registry key name */
-                rc = RegOpenKeyExW(
-                    list->HKLM,
-                    REGSTR_PATH_SYSTEMENUM,
-                    0, /* Options */
-                    0,
-                    &hEnumKey);
-                if (rc != ERROR_SUCCESS)
-                {
-                    SetLastError(rc);
-                    break;
-                }
-                rc = RegOpenKeyExW(
-                    hEnumKey,
-                    DevInfo->Data,
-                    0, /* Options */
-                    KEY_QUERY_VALUE,
-                    &hKey);
-                RegCloseKey(hEnumKey);
-                if (rc != ERROR_SUCCESS)
+            /* Call Class co-installers */
+            Context.PostProcessing = FALSE;
+            rc = NO_ERROR;
+            ListEntry = ClassCoInstallersListHead.Flink;
+            while (rc == NO_ERROR && ListEntry != &ClassCoInstallersListHead)
+            {
+                struct CoInstallerElement *coinstaller;
+                coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
+                rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
+                coinstaller->PrivateData = Context.PrivateData;
+                if (rc == ERROR_DI_POSTPROCESSING_REQUIRED)
                 {
-                    SetLastError(rc);
-                    break;
+                    coinstaller->DoPostProcessing = TRUE;
+                    rc = NO_ERROR;
                 }
-                /* Read registry entry */
-                BufferSize = PropertyBufferSize;
-                rc = RegQueryValueExW(
-                    hKey,
-                    RegistryPropertyName,
-                    NULL, /* Reserved */
-                    PropertyRegDataType,
-                    PropertyBuffer,
-                    &BufferSize);
-                if (RequiredSize)
-                    *RequiredSize = BufferSize;
-                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;
-            }
-
-            case SPDRP_PHYSICAL_DEVICE_OBJECT_NAME:
-            {
-                DWORD required = (strlenW(DevInfo->Data) + 1) * sizeof(WCHAR);
-
-                if (PropertyRegDataType)
-                    *PropertyRegDataType = REG_SZ;
-                if (RequiredSize)
-                    *RequiredSize = required;
-                if (PropertyBufferSize >= required)
-                {
-                    strcpyW((LPWSTR)PropertyBuffer, DevInfo->Data);
-                    ret = TRUE;
-                }
-                else
-                    SetLastError(ERROR_INSUFFICIENT_BUFFER);
-                break;
-            }
-
-            /*case SPDRP_BUSTYPEGUID:
-            case SPDRP_LEGACYBUSTYPE:
-            case SPDRP_BUSNUMBER:
-            case SPDRP_ENUMERATOR_NAME:
-            case SPDRP_SECURITY_SDS:
-            case SPDRP_DEVTYPE:
-            case SPDRP_EXCLUSIVE:
-            case SPDRP_CHARACTERISTICS:
-            case SPDRP_ADDRESS:
-            case SPDRP_DEVICE_POWER_DATA:*/
-#if (WINVER >= 0x501)
-            /*case SPDRP_REMOVAL_POLICY:
-            case SPDRP_REMOVAL_POLICY_HW_DEFAULT:
-            case SPDRP_REMOVAL_POLICY_OVERRIDE:
-            case SPDRP_INSTALL_STATE:*/
-#endif
-
-            default:
-            {
-                ERR("Property 0x%lx not implemented\n", Property);
-                SetLastError(ERROR_NOT_SUPPORTED);
-            }
-        }
-    }
-
-    TRACE("Returning %d\n", ret);
-    return ret;
-}
-
-/***********************************************************************
- *             SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiSetDeviceRegistryPropertyA(
-    IN HDEVINFO DeviceInfoSet,
-    IN OUT PSP_DEVINFO_DATA DeviceInfoData,
-    IN DWORD Property,
-    IN CONST BYTE *PropertyBuffer OPTIONAL,
-    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 OPTIONAL,
-    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 = REGSTR_VAL_COMPATIBLEIDS;
-                        RegistryDataType = REG_MULTI_SZ;
-                        break;
-                    case SPDRP_CONFIGFLAGS:
-                        RegistryPropertyName = REGSTR_VAL_CONFIGFLAGS;
-                        RegistryDataType = REG_DWORD;
-                        break;
-                    case SPDRP_FRIENDLYNAME:
-                        RegistryPropertyName = REGSTR_VAL_FRIENDLYNAME;
-                        RegistryDataType = REG_SZ;
-                        break;
-                    case SPDRP_HARDWAREID:
-                        RegistryPropertyName = REGSTR_VAL_HARDWAREID;
-                        RegistryDataType = REG_MULTI_SZ;
-                        break;
-                    case SPDRP_LOCATION_INFORMATION:
-                        RegistryPropertyName = REGSTR_VAL_LOCATION_INFORMATION;
-                        RegistryDataType = REG_SZ;
-                        break;
-                    case SPDRP_LOWERFILTERS:
-                        RegistryPropertyName = REGSTR_VAL_LOWERFILTERS;
-                        RegistryDataType = REG_MULTI_SZ;
-                        break;
-                    case SPDRP_SECURITY:
-                        RegistryPropertyName = REGSTR_SECURITY;
-                        RegistryDataType = REG_BINARY;
-                        break;
-                    case SPDRP_SERVICE:
-                        RegistryPropertyName = REGSTR_VAL_SERVICE;
-                        RegistryDataType = REG_SZ;
-                        break;
-                    case SPDRP_UI_NUMBER_DESC_FORMAT:
-                        RegistryPropertyName = REGSTR_UI_NUMBER_DESC_FORMAT;
-                        RegistryDataType = REG_SZ;
-                        break;
-                    case SPDRP_UPPERFILTERS:
-                        RegistryPropertyName = REGSTR_VAL_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:
-            {
-                ERR("Property 0x%lx not implemented\n", Property);
-                SetLastError(ERROR_NOT_SUPPORTED);
-            }
-        }
-    }
-
-    TRACE("Returning %d\n", ret);
-    return ret;
-}
-
-
-/***********************************************************************
- *             SetupDiInstallClassA (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiInstallClassA(
-    IN HWND hwndParent OPTIONAL,
-    IN PCSTR InfFileName,
-    IN DWORD Flags,
-    IN HSPFILEQ FileQueue OPTIONAL)
-{
-    return SetupDiInstallClassExA(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
-}
-
-
-/***********************************************************************
- *             SetupDiInstallClassW (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiInstallClassW(
-    IN HWND hwndParent OPTIONAL,
-    IN PCWSTR InfFileName,
-    IN DWORD Flags,
-    IN HSPFILEQ FileQueue OPTIONAL)
-{
-    return SetupDiInstallClassExW(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
-}
-
-
-/***********************************************************************
- *             SetupDiInstallClassExA (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiInstallClassExA(
-    IN HWND hwndParent OPTIONAL,
-    IN PCSTR InfFileName OPTIONAL,
-    IN DWORD Flags,
-    IN HSPFILEQ FileQueue OPTIONAL,
-    IN CONST GUID *InterfaceClassGuid OPTIONAL,
-    IN PVOID Reserved1,
-    IN PVOID Reserved2)
-{
-    PWSTR InfFileNameW = NULL;
-    BOOL Result;
-
-    if (InfFileName)
-    {
-        InfFileNameW = MultiByteToUnicode(InfFileName, CP_ACP);
-        if (InfFileNameW == NULL)
-        {
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            return FALSE;
-        }
-    }
-
-    Result = SetupDiInstallClassExW(hwndParent, InfFileNameW, Flags,
-        FileQueue, InterfaceClassGuid, Reserved1, Reserved2);
-
-    MyFree(InfFileNameW);
-
-    return Result;
-}
-
-
-static HKEY
-CreateClassKey(HINF hInf)
-{
-    WCHAR FullBuffer[MAX_PATH];
-    WCHAR Buffer[MAX_PATH];
-    DWORD RequiredSize;
-    HKEY hClassKey = NULL;
-    HKEY ret = INVALID_HANDLE_VALUE;
-
-    FullBuffer[0] = '\0';
-    Buffer[0] = '\\';
-    if (!SetupGetLineTextW(NULL,
-                           hInf,
-                           Version,
-                           ClassGUID,
-                           &Buffer[1],
-                           MAX_PATH - 1,
-                           &RequiredSize))
-    {
-        goto cleanup;
-    }
-
-    lstrcpyW(FullBuffer, REGSTR_PATH_CLASS_NT);
-    lstrcatW(FullBuffer, Buffer);
-
-    if (!SetupGetLineTextW(NULL,
-                           hInf,
-                           Version,
-                           Class,
-                           Buffer,
-                           MAX_PATH,
-                           &RequiredSize))
-    {
-        RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
-        goto cleanup;
-    }
-
-    if (ERROR_SUCCESS != RegCreateKeyExW(HKEY_LOCAL_MACHINE,
-                                         FullBuffer,
-                                         0,
-                                         NULL,
-                                         REG_OPTION_NON_VOLATILE,
-                                         KEY_SET_VALUE,
-                                         NULL,
-                                         &hClassKey,
-                                         NULL))
-    {
-        goto cleanup;
-    }
-
-    if (ERROR_SUCCESS != RegSetValueExW(hClassKey,
-                                        Class,
-                                        0,
-                                        REG_SZ,
-                                        (LPBYTE)Buffer,
-                                        RequiredSize * sizeof(WCHAR)))
-    {
-        goto cleanup;
-    }
-
-    ret = hClassKey;
-
-cleanup:
-    if (hClassKey != NULL && hClassKey != ret)
-        RegCloseKey(hClassKey);
-    if (ret == INVALID_HANDLE_VALUE && FullBuffer[0] != '\0')
-        RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
-    return ret;
-}
-
-
-/***********************************************************************
- *             SetupDiInstallClassExW (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiInstallClassExW(
-    IN HWND hwndParent OPTIONAL,
-    IN PCWSTR InfFileName OPTIONAL,
-    IN DWORD Flags,
-    IN HSPFILEQ FileQueue OPTIONAL,
-    IN CONST GUID *InterfaceClassGuid OPTIONAL,
-    IN PVOID Reserved1,
-    IN PVOID Reserved2)
-{
-    BOOL ret = FALSE;
-
-    TRACE("%p %s 0x%lx %p %s %p %p\n", hwndParent, debugstr_w(InfFileName), Flags,
-        FileQueue, debugstr_guid(InterfaceClassGuid), Reserved1, Reserved2);
-
-    if (!InfFileName)
-    {
-        FIXME("Case not implemented: InfFileName NULL\n");
-        SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    }
-    else if (Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL))
-    {
-        TRACE("Unknown flags: 0x%08lx\n", Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL));
-        SetLastError(ERROR_INVALID_FLAGS);
-    }
-    else if ((Flags & DI_NOVCP) && FileQueue == NULL)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else if (Reserved1 != NULL)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else if (Reserved2 != NULL)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else
-    {
-        HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
-        SP_DEVINSTALL_PARAMS_W InstallParams;
-        WCHAR SectionName[MAX_PATH];
-        HINF hInf = INVALID_HANDLE_VALUE;
-        HKEY hRootKey = INVALID_HANDLE_VALUE;
-        PVOID callback_context = NULL;
-
-        hDeviceInfo = SetupDiCreateDeviceInfoList(NULL, NULL);
-
-        InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
-        if (!SetupDiGetDeviceInstallParamsW(hDeviceInfo, NULL, &InstallParams))
-            goto cleanup;
-        InstallParams.Flags &= ~(DI_NOVCP | DI_NOBROWSE | DI_QUIETINSTALL);
-        InstallParams.Flags |= Flags & (DI_NOVCP | DI_NOBROWSE | DI_QUIETINSTALL);
-        if (Flags & DI_NOVCP)
-            InstallParams.FileQueue = FileQueue;
-        if (!SetupDiSetDeviceInstallParamsW(hDeviceInfo, NULL, &InstallParams))
-            goto cleanup;
-
-        /* Open the .inf file */
-        hInf = SetupOpenInfFileW(
-            InfFileName,
-            NULL,
-            INF_STYLE_WIN4,
-            NULL);
-        if (hInf == INVALID_HANDLE_VALUE)
-            goto cleanup;
-
-        /* Try to append a layout file */
-        ret = SetupOpenAppendInfFileW(NULL, hInf, NULL);
-        if (!ret)
-            goto cleanup;
-
-        if (InterfaceClassGuid)
-        {
-            /* Retrieve the actual section name */
-            ret = SetupDiGetActualSectionToInstallW(
-                hInf,
-                InterfaceInstall32,
-                SectionName,
-                MAX_PATH,
-                NULL,
-                NULL);
-            if (!ret)
-                goto cleanup;
-
-            /* Open registry key related to this interface */
-            /* FIXME: What happens if the key doesn't exist? */
-            hRootKey = SetupDiOpenClassRegKeyExW(InterfaceClassGuid, KEY_ENUMERATE_SUB_KEYS, DIOCR_INTERFACE, NULL, NULL);
-            if (hRootKey == INVALID_HANDLE_VALUE)
-                goto cleanup;
-
-            /* SetupDiCreateDeviceInterface??? */
-            FIXME("Installing an interface is not implemented\n");
-            SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-        }
-        else
-        {
-            /* Create or open the class registry key 'HKLM\CurrentControlSet\Class\{GUID}' */
-            hRootKey = CreateClassKey(hInf);
-            if (hRootKey == INVALID_HANDLE_VALUE)
-                goto cleanup;
-
-            /* Retrieve the actual section name */
-            ret = SetupDiGetActualSectionToInstallW(
-                hInf,
-                ClassInstall32,
-                SectionName,
-                MAX_PATH - strlenW(DotServices),
-                NULL,
-                NULL);
-            if (!ret)
-                goto cleanup;
-
-            callback_context = SetupInitDefaultQueueCallback(hwndParent);
-            if (!callback_context)
-                goto cleanup;
-
-            ret = SetupInstallFromInfSectionW(
-                hwndParent,
-                hInf,
-                SectionName,
-                SPINST_REGISTRY | SPINST_FILES | SPINST_BITREG | SPINST_INIFILES | SPINST_INI2REG,
-                hRootKey,
-                NULL, /* FIXME: SourceRootPath */
-                !(Flags & DI_NOVCP) && (Flags & DI_FORCECOPY) ? SP_COPY_FORCE_IN_USE : 0, /* CopyFlags */
-                SetupDefaultQueueCallbackW,
-                callback_context,
-                hDeviceInfo,
-                NULL);
-            if (!ret)
-                goto cleanup;
-
-            /* Install .Services section */
-            lstrcatW(SectionName, DotServices);
-            ret = SetupInstallServicesFromInfSectionExW(
-                hInf,
-                SectionName,
-                0,
-                hDeviceInfo,
-                NULL,
-                NULL,
-                NULL);
-            if (!ret)
-                goto cleanup;
-
-            ret = TRUE;
-        }
-
-cleanup:
-        if (hDeviceInfo != INVALID_HANDLE_VALUE)
-            SetupDiDestroyDeviceInfoList(hDeviceInfo);
-        if (hInf != INVALID_HANDLE_VALUE)
-            SetupCloseInfFile(hInf);
-        if (hRootKey != INVALID_HANDLE_VALUE)
-            RegCloseKey(hRootKey);
-        SetupTermDefaultQueueCallback(callback_context);
-    }
-
-    TRACE("Returning %d\n", ret);
-    return ret;
-}
-
-
-/***********************************************************************
- *             SetupDiOpenClassRegKey  (SETUPAPI.@)
- */
-HKEY WINAPI
-SetupDiOpenClassRegKey(
-    IN CONST GUID *ClassGuid OPTIONAL,
-    IN REGSAM samDesired)
-{
-    return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
-                                     DIOCR_INSTALLER, NULL, NULL);
-}
-
-
-/***********************************************************************
- *             SetupDiOpenClassRegKeyExA  (SETUPAPI.@)
- */
-HKEY WINAPI
-SetupDiOpenClassRegKeyExA(
-    IN CONST GUID *ClassGuid OPTIONAL,
-    IN REGSAM samDesired,
-    IN DWORD Flags,
-    IN PCSTR MachineName OPTIONAL,
-    IN PVOID Reserved)
-{
-    PWSTR MachineNameW = NULL;
-    HKEY hKey;
-
-    TRACE("\n");
-
-    if (MachineName)
-    {
-        MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
-        if (MachineNameW == NULL)
-            return INVALID_HANDLE_VALUE;
-    }
-
-    hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
-                                     Flags, MachineNameW, Reserved);
-
-    if (MachineNameW)
-        MyFree(MachineNameW);
-
-    return hKey;
-}
-
-
-/***********************************************************************
- *             SetupDiOpenClassRegKeyExW  (SETUPAPI.@)
- */
-HKEY WINAPI
-SetupDiOpenClassRegKeyExW(
-    IN CONST GUID* ClassGuid OPTIONAL,
-    IN REGSAM samDesired,
-    IN DWORD Flags,
-    IN PCWSTR MachineName OPTIONAL,
-    IN PVOID Reserved)
-{
-    LPWSTR lpGuidString = NULL;
-    LPWSTR lpFullGuidString = NULL;
-    DWORD dwLength;
-    HKEY HKLM;
-    HKEY hClassesKey = NULL;
-    HKEY hClassKey = NULL;
-    HKEY ret = INVALID_HANDLE_VALUE;
-    DWORD rc;
-    LPCWSTR lpKeyName;
-
-    TRACE("%s 0x%lx 0x%lx %s %p\n", debugstr_guid(ClassGuid), samDesired,
-        Flags, debugstr_w(MachineName), Reserved);
-
-    if (Flags == DIOCR_INSTALLER)
-        lpKeyName = REGSTR_PATH_CLASS_NT;
-    else if (Flags == DIOCR_INTERFACE)
-        lpKeyName = REGSTR_PATH_DEVICE_CLASSES;
-    else
-    {
-        ERR("Invalid Flags parameter!\n");
-        SetLastError(ERROR_INVALID_FLAGS);
-        goto cleanup;
-    }
-
-    if (MachineName != NULL)
-    {
-        rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
-        if (rc != ERROR_SUCCESS)
-        {
-            SetLastError(rc);
-            goto cleanup;
-        }
-    }
-    else
-        HKLM = HKEY_LOCAL_MACHINE;
-
-    rc = RegOpenKeyExW(HKLM,
-                      lpKeyName,
-                      0,
-                      ClassGuid ? 0 : samDesired,
-                      &hClassesKey);
-    if (MachineName != NULL) RegCloseKey(HKLM);
-    if (rc != ERROR_SUCCESS)
-    {
-        SetLastError(rc);
-        goto cleanup;
-    }
-
-    if (ClassGuid == NULL)
-    {
-        /* Stop here. We don't need to open a subkey */
-        ret = hClassesKey;
-        goto cleanup;
-    }
-
-    if (UuidToStringW((UUID*)ClassGuid, &lpGuidString) != RPC_S_OK)
-    {
-        SetLastError(ERROR_GEN_FAILURE);
-        goto cleanup;
-    }
-
-    dwLength = lstrlenW(lpGuidString);
-    lpFullGuidString = HeapAlloc(GetProcessHeap(), 0, (dwLength + 3) * sizeof(WCHAR));
-    if (!lpFullGuidString)
-    {
-        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-        goto cleanup;
-    }
-    lpFullGuidString[0] = '{';
-    memcpy(&lpFullGuidString[1], lpGuidString, dwLength * sizeof(WCHAR));
-    lpFullGuidString[dwLength + 1] = '}';
-    lpFullGuidString[dwLength + 2] = '\0';
-
-    rc = RegOpenKeyExW(hClassesKey,
-                       lpFullGuidString,
-                       0,
-                       samDesired,
-                       &hClassKey);
-    if (rc != ERROR_SUCCESS)
-    {
-        SetLastError(rc);
-        goto cleanup;
-    }
-    ret = hClassKey;
-
-cleanup:
-    if (hClassKey != NULL && hClassKey != ret)
-        RegCloseKey(hClassKey);
-    if (hClassesKey != NULL && hClassesKey != ret)
-        RegCloseKey(hClassesKey);
-    if (lpGuidString)
-        RpcStringFreeW(&lpGuidString);
-    HeapFree(GetProcessHeap(), 0, lpFullGuidString);
-
-    return ret;
-}
-
-/***********************************************************************
- *             SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiOpenDeviceInterfaceW(
-    IN HDEVINFO DeviceInfoSet,
-    IN PCWSTR DevicePath,
-    IN DWORD OpenFlags,
-    OUT PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData OPTIONAL)
-{
-    FIXME("%p %s %08lx %p\n",
-        DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
-    return FALSE;
-}
-
-/***********************************************************************
- *             SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiOpenDeviceInterfaceA(
-    IN HDEVINFO DeviceInfoSet,
-    IN PCSTR DevicePath,
-    IN DWORD OpenFlags,
-    OUT PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData OPTIONAL)
-{
-    LPWSTR DevicePathW = NULL;
-    BOOL bResult;
-
-    TRACE("%p %s %08lx %p\n", DeviceInfoSet, debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
-
-    DevicePathW = MultiByteToUnicode(DevicePath, CP_ACP);
-    if (DevicePathW == NULL)
-        return FALSE;
-
-    bResult = SetupDiOpenDeviceInterfaceW(DeviceInfoSet,
-        DevicePathW, OpenFlags, DeviceInterfaceData);
-
-    MyFree(DevicePathW);
-
-    return bResult;
-}
-
-/***********************************************************************
- *             SetupDiSetClassInstallParamsA (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiSetClassInstallParamsA(
-    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;
-}
-
-/***********************************************************************
- *             SetupDiSetClassInstallParamsW (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiSetClassInstallParamsW(
-    IN HDEVINFO DeviceInfoSet,
-    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
-    IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
-    IN DWORD ClassInstallParamsSize)
-{
-    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_W);
-        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)
-            {
-                ERR("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
-GetFunctionPointer(
-    IN PWSTR InstallerName,
-    OUT HMODULE* ModulePointer,
-    OUT PVOID* FunctionPointer)
-{
-    HMODULE hModule = NULL;
-    LPSTR FunctionNameA = NULL;
-    PWCHAR Comma;
-    DWORD rc;
-
-    *ModulePointer = NULL;
-    *FunctionPointer = NULL;
-
-    Comma = strchrW(InstallerName, ',');
-    if (!Comma)
-    {
-        rc = ERROR_INVALID_PARAMETER;
-        goto cleanup;
-    }
-
-    /* Load library */
-    *Comma = '\0';
-    hModule = LoadLibraryW(InstallerName);
-    *Comma = ',';
-    if (!hModule)
-    {
-        rc = GetLastError();
-        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)
-    {
-        rc = GetLastError();
-        goto cleanup;
-    }
-
-    *ModulePointer = hModule;
-    rc = ERROR_SUCCESS;
-
-cleanup:
-    if (rc != ERROR_SUCCESS && hModule)
-        FreeLibrary(hModule);
-    MyFree(FunctionNameA);
-    return rc;
-}
-
-static DWORD
-FreeFunctionPointer(
-    IN HMODULE ModulePointer,
-    IN PVOID FunctionPointer)
-{
-    if (ModulePointer == NULL)
-        return ERROR_SUCCESS;
-    if (FreeLibrary(ModulePointer))
-       return ERROR_SUCCESS;
-    else
-       return GetLastError();
-}
-
-static BOOL WINAPI
-IntSetupDiRegisterDeviceInfo(
-    IN HDEVINFO DeviceInfoSet,
-    IN OUT PSP_DEVINFO_DATA DeviceInfoData)
-{
-    return SetupDiRegisterDeviceInfo(DeviceInfoSet, DeviceInfoData, 0, NULL, NULL, NULL);
-}
-
-/***********************************************************************
- *             SetupDiCallClassInstaller (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiCallClassInstaller(
-    IN DI_FUNCTION InstallFunction,
-    IN HDEVINFO DeviceInfoSet,
-    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
-{
-    BOOL ret = FALSE;
-
-    TRACE("%u %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
-
-    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 (((struct DeviceInfoSet *)DeviceInfoSet)->HKLM != HKEY_LOCAL_MACHINE)
-        SetLastError(ERROR_INVALID_HANDLE);
-    else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
-        SetLastError(ERROR_INVALID_USER_BUFFER);
-    else
-    {
-        SP_DEVINSTALL_PARAMS_W InstallParams;
-#define CLASS_COINSTALLER  0x1
-#define DEVICE_COINSTALLER 0x2
-#define CLASS_INSTALLER    0x4
-        UCHAR CanHandle = 0;
-        DEFAULT_CLASS_INSTALL_PROC DefaultHandler = NULL;
-
-        switch (InstallFunction)
-        {
-            case DIF_ADDPROPERTYPAGE_ADVANCED:
-                CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
-                break;
-            case DIF_ADDREMOTEPROPERTYPAGE_ADVANCED:
-                CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
-                break;
-            case DIF_ALLOW_INSTALL:
-                CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
-                break;
-            case DIF_DETECT:
-                CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
-                break;
-            case DIF_DESTROYPRIVATEDATA:
-                CanHandle = CLASS_INSTALLER;
-                break;
-            case DIF_INSTALLDEVICE:
-                CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
-                DefaultHandler = SetupDiInstallDevice;
-                break;
-            case DIF_INSTALLDEVICEFILES:
-                CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
-                DefaultHandler = SetupDiInstallDriverFiles;
-                break;
-            case DIF_INSTALLINTERFACES:
-                CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
-                DefaultHandler = SetupDiInstallDeviceInterfaces;
-                break;
-            case DIF_NEWDEVICEWIZARD_FINISHINSTALL:
-                CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
-                break;
-            case DIF_NEWDEVICEWIZARD_POSTANALYZE:
-                CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
-                break;
-            case DIF_NEWDEVICEWIZARD_PREANALYZE:
-                CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
-                break;
-            case DIF_NEWDEVICEWIZARD_PRESELECT:
-                CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
-                break;
-            case DIF_NEWDEVICEWIZARD_SELECT:
-                CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
-                break;
-            case DIF_POWERMESSAGEWAKE:
-                CanHandle = CLASS_COINSTALLER | DEVICE_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;
-                break;
-            case DIF_REGISTERDEVICE:
-                CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
-                DefaultHandler = IntSetupDiRegisterDeviceInfo;
-                break;
-            case DIF_REMOVE:
-                CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
-                DefaultHandler = SetupDiRemoveDevice;
-                break;
-            case DIF_SELECTBESTCOMPATDRV:
-                CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
-                DefaultHandler = SetupDiSelectBestCompatDrv;
-                break;
-            case DIF_SELECTDEVICE:
-                CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
-                DefaultHandler = SetupDiSelectDevice;
-                break;
-            case DIF_TROUBLESHOOTER:
-                CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
-                break;
-            case DIF_UNREMOVE:
-                CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
-                DefaultHandler = SetupDiUnremoveDevice;
-                break;
-            default:
-                ERR("Install function %u not supported\n", InstallFunction);
-                SetLastError(ERROR_NOT_SUPPORTED);
-        }
-
-        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;
-            LIST_ENTRY DeviceCoInstallersListHead;
-            HMODULE ClassInstallerLibrary = NULL;
-            CLASS_INSTALL_PROC ClassInstaller = NULL;
-            COINSTALLER_CONTEXT_DATA Context;
-            PLIST_ENTRY ListEntry;
-            HKEY hKey;
-            DWORD dwRegType, dwLength;
-            DWORD rc = NO_ERROR;
-
-            InitializeListHead(&ClassCoInstallersListHead);
-            InitializeListHead(&DeviceCoInstallersListHead);
-
-            if (CanHandle & DEVICE_COINSTALLER)
-            {
-                hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
-                if (hKey != INVALID_HANDLE_VALUE)
-                {
-                    rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, &dwRegType, NULL, &dwLength);
-                    if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
-                    {
-                        LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
-                        if (KeyBuffer != NULL)
-                        {
-                            rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, 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)
-            {
-                rc = RegOpenKeyEx(
-                    HKEY_LOCAL_MACHINE,
-                    REGSTR_PATH_CODEVICEINSTALLERS,
-                    0, /* Options */
-                    KEY_QUERY_VALUE,
-                    &hKey);
-                if (rc == ERROR_SUCCESS)
-                {
-                    LPWSTR lpGuidString;
-                    if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) == RPC_S_OK)
-                    {
-                        rc = RegQueryValueExW(hKey, lpGuidString, NULL, &dwRegType, NULL, &dwLength);
-                        if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
-                        {
-                            LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
-                            if (KeyBuffer != NULL)
-                            {
-                                rc = RegQueryValueExW(hKey, lpGuidString, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
-                                if (rc == ERROR_SUCCESS)
-                                {
-                                    LPWSTR ptr;
-                                    for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
-                                    {
-                                        /* Add coinstaller to ClassCoInstallersListHead list */
-                                        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);
-                            }
-                        }
-                        RpcStringFreeW(&lpGuidString);
-                    }
-                    RegCloseKey(hKey);
-                }
-            }
-            if ((CanHandle & CLASS_INSTALLER) && !(InstallParams.FlagsEx & DI_FLAGSEX_CI_FAILED))
-            {
-                hKey = SetupDiOpenClassRegKey(&DeviceInfoData->ClassGuid, KEY_QUERY_VALUE);
-                if (hKey != INVALID_HANDLE_VALUE)
-                {
-                    rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength);
-                    if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
-                    {
-                        LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
-                        if (KeyBuffer != NULL)
-                        {
-                            rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
-                            if (rc == ERROR_SUCCESS)
-                            {
-                                /* Get ClassInstaller function pointer */
-                                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);
-                        }
-                    }
-                    RegCloseKey(hKey);
-                }
-            }
-
-            /* Call Class co-installers */
-            Context.PostProcessing = FALSE;
-            rc = NO_ERROR;
-            ListEntry = ClassCoInstallersListHead.Flink;
-            while (rc == NO_ERROR && ListEntry != &ClassCoInstallersListHead)
-            {
-                struct CoInstallerElement *coinstaller;
-                coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
-                rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
-                coinstaller->PrivateData = Context.PrivateData;
-                if (rc == ERROR_DI_POSTPROCESSING_REQUIRED)
-                {
-                    coinstaller->DoPostProcessing = TRUE;
-                    rc = NO_ERROR;
-                }
-                ListEntry = ListEntry->Flink;
-            }
-
-            /* Call Device co-installers */
-            ListEntry = DeviceCoInstallersListHead.Flink;
-            while (rc == NO_ERROR && ListEntry != &DeviceCoInstallersListHead)
-            {
-                struct CoInstallerElement *coinstaller;
-                coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
-                rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
-                coinstaller->PrivateData = Context.PrivateData;
-                if (rc == ERROR_DI_POSTPROCESSING_REQUIRED)
-                {
-                    coinstaller->DoPostProcessing = TRUE;
-                    rc = NO_ERROR;
-                }
-                ListEntry = ListEntry->Flink;
-            }
-
-            /* Call Class installer */
-            if (ClassInstaller)
-            {
-                rc = (*ClassInstaller)(InstallFunction, DeviceInfoSet, DeviceInfoData);
-                FreeFunctionPointer(ClassInstallerLibrary, ClassInstaller);
-            }
-            else
-                rc = ERROR_DI_DO_DEFAULT;
-
-            /* Call default handler */
-            if (rc == ERROR_DI_DO_DEFAULT)
-            {
-                if (DefaultHandler && !(InstallParams.Flags & DI_NODI_DEFAULTACTION))
-                {
-                    if ((*DefaultHandler)(DeviceInfoSet, DeviceInfoData))
-                        rc = NO_ERROR;
-                    else
-                        rc = GetLastError();
-                }
-                else
-                    rc = NO_ERROR;
-            }
-
-            /* Call Class co-installers that required postprocessing */
-            Context.PostProcessing = TRUE;
-            ListEntry = ClassCoInstallersListHead.Flink;
-            while (ListEntry != &ClassCoInstallersListHead)
-            {
-                struct CoInstallerElement *coinstaller;
-                coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
-                if (coinstaller->DoPostProcessing)
-                {
-                    Context.InstallResult = rc;
-                    Context.PrivateData = coinstaller->PrivateData;
-                    rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
-                }
-                FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
-                ListEntry = ListEntry->Flink;
-            }
-
-            /* Call Device co-installers that required postprocessing */
-            ListEntry = DeviceCoInstallersListHead.Flink;
-            while (ListEntry != &DeviceCoInstallersListHead)
-            {
-                struct CoInstallerElement *coinstaller;
-                coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
-                if (coinstaller->DoPostProcessing)
-                {
-                    Context.InstallResult = rc;
-                    Context.PrivateData = coinstaller->PrivateData;
-                    rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
-                }
-                FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
-                ListEntry = ListEntry->Flink;
-            }
-
-            /* Free allocated memory */
-            while (!IsListEmpty(&ClassCoInstallersListHead))
-            {
-                ListEntry = RemoveHeadList(&ClassCoInstallersListHead);
-                HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry));
-            }
-            while (!IsListEmpty(&DeviceCoInstallersListHead))
-            {
-                ListEntry = RemoveHeadList(&DeviceCoInstallersListHead);
-                HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry));
-            }
-
-            ret = (rc == NO_ERROR);
-        }
-    }
-
-    TRACE("Returning %d\n", ret);
-    return ret;
-}
-
-/***********************************************************************
- *             SetupDiGetDeviceInfoListClass  (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiGetDeviceInfoListClass(
-    IN HDEVINFO DeviceInfoSet,
-    OUT LPGUID ClassGuid)
-{
-    struct DeviceInfoSet *list;
-    BOOL ret = FALSE;
-
-    TRACE("%p %p\n", DeviceInfoSet, ClassGuid);
-
-    if (!DeviceInfoSet)
-        SetLastError(ERROR_INVALID_HANDLE);
-    else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
-        SetLastError(ERROR_INVALID_HANDLE);
-    else if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
-        SetLastError(ERROR_NO_ASSOCIATED_CLASS);
-    else
-    {
-        memcpy(&ClassGuid, &list->ClassGuid, sizeof(GUID));
-
-        ret = TRUE;
-    }
-
-    TRACE("Returning %d\n", ret);
-    return ret;
-}
-
-/***********************************************************************
- *             SetupDiGetDeviceInfoListDetailW  (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiGetDeviceInfoListDetailW(
-    IN HDEVINFO DeviceInfoSet,
-    OUT PSP_DEVINFO_LIST_DETAIL_DATA_W DeviceInfoListDetailData)
-{
-    struct DeviceInfoSet *list;
-    BOOL ret = FALSE;
-
-    TRACE("%p %p\n", DeviceInfoSet, DeviceInfoListDetailData);
-
-    if (!DeviceInfoSet)
-        SetLastError(ERROR_INVALID_HANDLE);
-    else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
-        SetLastError(ERROR_INVALID_HANDLE);
-    else if (!DeviceInfoListDetailData)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else if (DeviceInfoListDetailData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W))
-        SetLastError(ERROR_INVALID_USER_BUFFER);
-    else
-    {
-        memcpy(
-            &DeviceInfoListDetailData->ClassGuid,
-            &list->ClassGuid,
-            sizeof(GUID));
-        DeviceInfoListDetailData->RemoteMachineHandle = list->hMachine;
-        if (list->MachineName)
-            strcpyW(DeviceInfoListDetailData->RemoteMachineName, list->MachineName + 2);
-        else
-            DeviceInfoListDetailData->RemoteMachineName[0] = 0;
-
-        ret = TRUE;
-    }
-
-    TRACE("Returning %d\n", ret);
-    return ret;
-}
-
-/***********************************************************************
- *             SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiGetDeviceInstallParamsA(
-    IN HDEVINFO DeviceInfoSet,
-    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
-    OUT PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
-{
-    SP_DEVINSTALL_PARAMS_W deviceInstallParamsW;
-    BOOL ret = FALSE;
-
-    TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
-
-    if (DeviceInstallParams == NULL)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
-        SetLastError(ERROR_INVALID_USER_BUFFER);
-    else
-    {
-        deviceInstallParamsW.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
-        ret = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &deviceInstallParamsW);
-
-        if (ret)
-        {
-            /* Do W->A conversion */
-            memcpy(
-                DeviceInstallParams,
-                &deviceInstallParamsW,
-                FIELD_OFFSET(SP_DEVINSTALL_PARAMS_W, DriverPath));
-            if (WideCharToMultiByte(CP_ACP, 0, deviceInstallParamsW.DriverPath, -1,
-                DeviceInstallParams->DriverPath, MAX_PATH, NULL, NULL) == 0)
-            {
-                DeviceInstallParams->DriverPath[0] = '\0';
-                ret = FALSE;
-            }
-        }
-    }
-
-    TRACE("Returning %d\n", ret);
-    return ret;
-}
-
-/***********************************************************************
- *             SetupDiGetDeviceInstallParamsW (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiGetDeviceInstallParamsW(
-    IN HDEVINFO DeviceInfoSet,
-    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
-    OUT 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 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;
-}
-
-static BOOL
-CheckDeviceInstallParameters(
-    IN PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
-{
-    DWORD SupportedFlags =
-        DI_NOVCP |                            /* 0x00000008 */
-        DI_DIDCOMPAT |                        /* 0x00000010 */
-        DI_DIDCLASS |                         /* 0x00000020 */
-        DI_NEEDRESTART |                      /* 0x00000080 */
-        DI_NEEDREBOOT |                       /* 0x00000100 */
-        DI_RESOURCEPAGE_ADDED |               /* 0x00002000 */
-        DI_PROPERTIES_CHANGE |                /* 0x00004000 */
-        DI_ENUMSINGLEINF |                    /* 0x00010000 */
-        DI_DONOTCALLCONFIGMG |                /* 0x00020000 */
-        DI_CLASSINSTALLPARAMS |               /* 0x00100000 */
-        DI_NODI_DEFAULTACTION |               /* 0x00200000 */
-        DI_QUIETINSTALL |                     /* 0x00800000 */
-        DI_NOFILECOPY |                       /* 0x01000000 */
-        DI_DRIVERPAGE_ADDED;                  /* 0x04000000 */
-    DWORD SupportedFlagsEx =
-        DI_FLAGSEX_CI_FAILED |                /* 0x00000004 */
-        DI_FLAGSEX_DIDINFOLIST |              /* 0x00000010 */
-        DI_FLAGSEX_DIDCOMPATINFO |            /* 0x00000020 */
-        DI_FLAGSEX_ALLOWEXCLUDEDDRVS |        /* 0x00000800 */
-        DI_FLAGSEX_NO_DRVREG_MODIFY;          /* 0x00008000 */
-    BOOL ret = FALSE;
-
-    /* FIXME: add support for more flags */
-
-    /* FIXME: DI_CLASSINSTALLPARAMS flag is not correctly used.
-     * It should be checked before accessing to other values
-     * of the SP_DEVINSTALL_PARAMS structure */
-
-    if (DeviceInstallParams->Flags & ~SupportedFlags)
-    {
-        FIXME("Unknown Flags: 0x%08lx\n", DeviceInstallParams->Flags & ~SupportedFlags);
-        SetLastError(ERROR_INVALID_FLAGS);
-    }
-    else if (DeviceInstallParams->FlagsEx & ~SupportedFlagsEx)
-    {
-        FIXME("Unknown FlagsEx: 0x%08lx\n", DeviceInstallParams->FlagsEx & ~SupportedFlagsEx);
-        SetLastError(ERROR_INVALID_FLAGS);
-    }
-    else if ((DeviceInstallParams->Flags & DI_NOVCP)
-        && (DeviceInstallParams->FileQueue == NULL || DeviceInstallParams->FileQueue == (HSPFILEQ)INVALID_HANDLE_VALUE))
-        SetLastError(ERROR_INVALID_USER_BUFFER);
-    else
-    {
-        /* FIXME: check Reserved field */
-        ret = TRUE;
-    }
-
-    return ret;
-}
-
-/***********************************************************************
- *             SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiSetDeviceInstallParamsW(
-    IN HDEVINFO DeviceInfoSet,
-    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
-    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 if (CheckDeviceInstallParameters(DeviceInstallParams))
-    {
-        PSP_DEVINSTALL_PARAMS_W Destination;
-
-        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;
-}
-
-/***********************************************************************
- *             SetupDiGetDeviceInstanceIdA(SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiGetDeviceInstanceIdA(
-    IN HDEVINFO DeviceInfoSet,
-    IN PSP_DEVINFO_DATA DeviceInfoData,
-    OUT PSTR DeviceInstanceId OPTIONAL,
-    IN DWORD DeviceInstanceIdSize,
-    OUT PDWORD RequiredSize OPTIONAL)
-{
-    PWSTR DeviceInstanceIdW = NULL;
-    BOOL ret = FALSE;
-
-    TRACE("%p %p %p %lu %p\n", DeviceInfoSet, DeviceInfoData,
-          DeviceInstanceId, DeviceInstanceIdSize, RequiredSize);
-
-    if (!DeviceInstanceId && DeviceInstanceIdSize > 0)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else
-    {
-        if (DeviceInstanceIdSize != 0)
-        {
-            DeviceInstanceIdW = MyMalloc(DeviceInstanceIdSize * sizeof(WCHAR));
-            if (DeviceInstanceIdW == NULL)
-                return FALSE;
-        }
-
-        ret = SetupDiGetDeviceInstanceIdW(DeviceInfoSet, DeviceInfoData,
-                                          DeviceInstanceIdW, DeviceInstanceIdSize,
-                                          RequiredSize);
-
-        if (ret && DeviceInstanceIdW != NULL)
-        {
-            if (WideCharToMultiByte(CP_ACP, 0, DeviceInstanceIdW, -1,
-                DeviceInstanceId, DeviceInstanceIdSize, NULL, NULL) == 0)
-            {
-                DeviceInstanceId[0] = '\0';
-                ret = FALSE;
-            }
-        }
-    }
-
-    TRACE("Returning %d\n", ret);
-    return ret;
-}
-
-/***********************************************************************
- *             SetupDiGetDeviceInstanceIdW(SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiGetDeviceInstanceIdW(
-    IN HDEVINFO DeviceInfoSet,
-    IN PSP_DEVINFO_DATA DeviceInfoData,
-    OUT PWSTR DeviceInstanceId OPTIONAL,
-    IN DWORD DeviceInstanceIdSize,
-    OUT PDWORD RequiredSize OPTIONAL)
-{
-    BOOL ret = FALSE;
-
-    TRACE("%p %p %p %lu %p\n", DeviceInfoSet, DeviceInfoData,
-          DeviceInstanceId, DeviceInstanceIdSize, RequiredSize);
-
-    if (!DeviceInfoSet)
-        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 if (!DeviceInstanceId && DeviceInstanceIdSize > 0)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else if (DeviceInstanceId && DeviceInstanceIdSize == 0)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else
-    {
-        struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
-        DWORD required;
-
-        required = (strlenW(DevInfo->DeviceName) + 1) * sizeof(WCHAR);
-        if (RequiredSize)
-            *RequiredSize = required;
-
-        if (required <= DeviceInstanceIdSize)
-        {
-            strcpyW(DeviceInstanceId, DevInfo->DeviceName);
-            ret = TRUE;
-        }
-        else
-            SetLastError(ERROR_INSUFFICIENT_BUFFER);
-    }
-
-    TRACE("Returning %d\n", ret);
-    return ret;
-}
-
-/***********************************************************************
- *             SetupDiGetClassDevPropertySheetsA(SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiGetClassDevPropertySheetsA(
-    IN HDEVINFO DeviceInfoSet,
-    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
-    IN LPPROPSHEETHEADERA PropertySheetHeader,
-    IN DWORD PropertySheetHeaderPageListSize,
-    OUT PDWORD RequiredSize OPTIONAL,
-    IN DWORD PropertySheetType)
-{
-    PROPSHEETHEADERW psh;
-    BOOL ret = FALSE;
-
-    TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
-        PropertySheetHeader, PropertySheetHeaderPageListSize,
-        RequiredSize, PropertySheetType);
-
-    psh.dwFlags = PropertySheetHeader->dwFlags;
-    psh.phpage = PropertySheetHeader->phpage;
-    psh.nPages = PropertySheetHeader->nPages;
-
-    ret = SetupDiGetClassDevPropertySheetsW(DeviceInfoSet, DeviceInfoData, PropertySheetHeader ? &psh : NULL,
-                                            PropertySheetHeaderPageListSize, RequiredSize,
-                                            PropertySheetType);
-    if (ret)
-    {
-        PropertySheetHeader->nPages = psh.nPages;
-    }
-
-    TRACE("Returning %d\n", ret);
-    return ret;
-}
-
-struct ClassDevPropertySheetsData
-{
-    HPROPSHEETPAGE *PropertySheetPages;
-    DWORD MaximumNumberOfPages;
-    DWORD NumberOfPages;
-};
-
-static BOOL WINAPI
-GetClassDevPropertySheetsCallback(
-    IN HPROPSHEETPAGE hPropSheetPage,
-    IN OUT LPARAM lParam)
-{
-    struct ClassDevPropertySheetsData *PropPageData;
-
-    PropPageData = (struct ClassDevPropertySheetsData *)lParam;
-
-    if (PropPageData->NumberOfPages < PropPageData->MaximumNumberOfPages)
-    {
-        *PropPageData->PropertySheetPages = hPropSheetPage;
-        PropPageData->PropertySheetPages++;
-    }
-
-    PropPageData->NumberOfPages++;
-    return TRUE;
-}
-
-/***********************************************************************
- *             SetupDiGetClassDevPropertySheetsW(SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiGetClassDevPropertySheetsW(
-    IN HDEVINFO DeviceInfoSet,
-    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
-    IN OUT LPPROPSHEETHEADERW PropertySheetHeader,
-    IN DWORD PropertySheetHeaderPageListSize,
-    OUT PDWORD RequiredSize OPTIONAL,
-    IN DWORD PropertySheetType)
-{
-    struct DeviceInfoSet *list;
-    BOOL ret = FALSE;
-
-    TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
-        PropertySheetHeader, PropertySheetHeaderPageListSize,
-        RequiredSize, PropertySheetType);
-
-    if (!DeviceInfoSet)
-        SetLastError(ERROR_INVALID_HANDLE);
-    else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
-        SetLastError(ERROR_INVALID_HANDLE);
-    else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
-        SetLastError(ERROR_INVALID_HANDLE);
-    else if (!PropertySheetHeader)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else if (PropertySheetHeader->dwFlags & PSH_PROPSHEETPAGE)
-        SetLastError(ERROR_INVALID_FLAGS);
-    else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
-        SetLastError(ERROR_INVALID_USER_BUFFER);
-    else if (!DeviceInfoData && IsEqualIID(&list->ClassGuid, &GUID_NULL))
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else if (!PropertySheetHeader)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else if (PropertySheetType != DIGCDP_FLAG_ADVANCED
-          && PropertySheetType != DIGCDP_FLAG_BASIC
-          && PropertySheetType != DIGCDP_FLAG_REMOTE_ADVANCED
-          && PropertySheetType != DIGCDP_FLAG_REMOTE_BASIC)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else
-    {
-        HKEY hKey = INVALID_HANDLE_VALUE;
-        SP_PROPSHEETPAGE_REQUEST Request;
-        LPWSTR PropPageProvider = NULL;
-        HMODULE hModule = NULL;
-        PROPERTY_PAGE_PROVIDER pPropPageProvider = NULL;
-        struct ClassDevPropertySheetsData PropPageData;
-        DWORD dwLength, dwRegType;
-        DWORD rc;
-
-        if (DeviceInfoData)
-            hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
-        else
-        {
-            hKey = SetupDiOpenClassRegKeyExW(&list->ClassGuid, KEY_QUERY_VALUE,
-                DIOCR_INSTALLER, list->MachineName + 2, NULL);
-        }
-        if (hKey == INVALID_HANDLE_VALUE)
-            goto cleanup;
-
-        rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, &dwRegType, NULL, &dwLength);
-        if (rc == ERROR_FILE_NOT_FOUND)
-        {
-            /* No registry key. As it is optional, don't say it's a bad error */
-            if (RequiredSize)
-                *RequiredSize = 0;
-            ret = TRUE;
-            goto cleanup;
-        }
-        else if (rc != ERROR_SUCCESS && dwRegType != REG_SZ)
-        {
-            SetLastError(rc);
-            goto cleanup;
-        }
-
-        PropPageProvider = HeapAlloc(GetProcessHeap(), 0, dwLength + sizeof(WCHAR));
-        if (!PropPageProvider)
-        {
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            goto cleanup;
-        }
-        rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, NULL, (LPBYTE)PropPageProvider, &dwLength);
-        if (rc != ERROR_SUCCESS)
-        {
-            SetLastError(rc);
-            goto cleanup;
-        }
-        PropPageProvider[dwLength / sizeof(WCHAR)] = 0;
-
-        rc = GetFunctionPointer(PropPageProvider, &hModule, (PVOID*)&pPropPageProvider);
-        if (rc != ERROR_SUCCESS)
-        {
-            SetLastError(ERROR_INVALID_PROPPAGE_PROVIDER);
-            goto cleanup;
-        }
-
-        Request.cbSize = sizeof(SP_PROPSHEETPAGE_REQUEST);
-        Request.PageRequested = SPPSR_ENUM_ADV_DEVICE_PROPERTIES;
-        Request.DeviceInfoSet = DeviceInfoSet;
-        Request.DeviceInfoData = DeviceInfoData;
-        PropPageData.PropertySheetPages = &PropertySheetHeader->phpage[PropertySheetHeader->nPages];
-        PropPageData.MaximumNumberOfPages = PropertySheetHeaderPageListSize - PropertySheetHeader->nPages;
-        PropPageData.NumberOfPages = 0;
-        ret = pPropPageProvider(&Request, GetClassDevPropertySheetsCallback, (LPARAM)&PropPageData);
-        if (!ret)
-            goto cleanup;
-
-        if (RequiredSize)
-            *RequiredSize = PropPageData.NumberOfPages + PropertySheetHeader->nPages;
-        if (PropPageData.NumberOfPages <= PropPageData.MaximumNumberOfPages)
-        {
-            PropertySheetHeader->nPages += PropPageData.NumberOfPages;
-            ret = TRUE;
-        }
-        else
-        {
-            PropertySheetHeader->nPages += PropPageData.MaximumNumberOfPages;
-            SetLastError(ERROR_INSUFFICIENT_BUFFER);
-        }
-
-cleanup:
-        if (hKey != INVALID_HANDLE_VALUE)
-            RegCloseKey(hKey);
-        HeapFree(GetProcessHeap(), 0, PropPageProvider);
-        FreeFunctionPointer(hModule, pPropPageProvider);
-    }
-
-    TRACE("Returning %d\n", ret);
-    return ret;
-}
-
-/***********************************************************************
- *             SetupDiCreateDevRegKeyA (SETUPAPI.@)
- */
-HKEY WINAPI
-SetupDiCreateDevRegKeyA(
-    IN HDEVINFO DeviceInfoSet,
-    IN PSP_DEVINFO_DATA DeviceInfoData,
-    IN DWORD Scope,
-    IN DWORD HwProfile,
-    IN DWORD KeyType,
-    IN HINF InfHandle OPTIONAL,
-    IN PCSTR InfSectionName OPTIONAL)
-{
-    PCWSTR InfSectionNameW = NULL;
-    HKEY ret = INVALID_HANDLE_VALUE;
-
-    if (InfSectionName)
-    {
-        InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
-        if (InfSectionNameW == NULL) return INVALID_HANDLE_VALUE;
-    }
-
-    ret = SetupDiCreateDevRegKeyW(DeviceInfoSet,
-                                  DeviceInfoData,
-                                  Scope,
-                                  HwProfile,
-                                  KeyType,
-                                  InfHandle,
-                                  InfSectionNameW);
-
-    if (InfSectionNameW != NULL)
-        MyFree((PVOID)InfSectionNameW);
-
-    return ret;
-}
-
-static HKEY
-OpenHardwareProfileKey(
-    IN HKEY HKLM,
-    IN DWORD HwProfile,
-    IN DWORD samDesired)
-{
-    HKEY hHWProfilesKey = NULL;
-    HKEY hHWProfileKey = NULL;
-    HKEY ret = INVALID_HANDLE_VALUE;
-    LONG rc;
-
-    rc = RegOpenKeyExW(HKLM,
-        REGSTR_PATH_HWPROFILES,
-        0,
-        0,
-        &hHWProfilesKey);
-    if (rc != ERROR_SUCCESS)
-    {
-        SetLastError(rc);
-        goto cleanup;
-    }
-    if (HwProfile == 0)
-    {
-        rc = RegOpenKeyExW(
-            hHWProfilesKey,
-            REGSTR_KEY_CURRENT,
-            0,
-            KEY_CREATE_SUB_KEY,
-            &hHWProfileKey);
-    }
-    else
-    {
-        WCHAR subKey[5];
-        snprintfW(subKey, 4, L"%04lu", HwProfile);
-        subKey[4] = '\0';
-        rc = RegOpenKeyExW(
-            hHWProfilesKey,
-            subKey,
-            0,
-            KEY_CREATE_SUB_KEY,
-            &hHWProfileKey);
-    }
-    if (rc != ERROR_SUCCESS)
-    {
-        SetLastError(rc);
-        goto cleanup;
-    }
-    ret = hHWProfileKey;
-
-cleanup:
-    if (hHWProfilesKey != NULL)
-        RegCloseKey(hHWProfilesKey);
-    if (hHWProfileKey != NULL && hHWProfileKey != ret)
-        RegCloseKey(hHWProfileKey);
-    return ret;
-}
-
-/***********************************************************************
- *             SetupDiCreateDevRegKeyW (SETUPAPI.@)
- */
-HKEY WINAPI
-SetupDiCreateDevRegKeyW(
-    IN HDEVINFO DeviceInfoSet,
-    IN PSP_DEVINFO_DATA DeviceInfoData,
-    IN DWORD Scope,
-    IN DWORD HwProfile,
-    IN DWORD KeyType,
-    IN HINF InfHandle OPTIONAL,
-    IN PCWSTR InfSectionName OPTIONAL)
-{
-    struct DeviceInfoSet *list;
-    HKEY ret = INVALID_HANDLE_VALUE;
-
-    TRACE("%p %p %lu %lu %lu %p %s\n", DeviceInfoSet, DeviceInfoData,
-          Scope, HwProfile, KeyType, InfHandle, debugstr_w(InfSectionName));
-
-    if (!DeviceInfoSet)
-        SetLastError(ERROR_INVALID_HANDLE);
-    else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
-        SetLastError(ERROR_INVALID_HANDLE);
-    else if (!DeviceInfoData)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
-        SetLastError(ERROR_INVALID_USER_BUFFER);
-    else if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else if (InfHandle && !InfSectionName)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else if (!InfHandle && InfSectionName)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else
-    {
-        LPWSTR lpGuidString = NULL;
-        LPWSTR DriverKey = NULL; /* {GUID}\Index */
-        LPWSTR pDeviceInstance; /* Points into DriverKey, on the Index field */
-        DWORD Index; /* Index used in the DriverKey name */
-        DWORD rc;
-        HKEY hHWProfileKey = INVALID_HANDLE_VALUE;
-        HKEY hEnumKey = NULL;
-        HKEY hClassKey = NULL;
-        HKEY hDeviceKey = INVALID_HANDLE_VALUE;
-        HKEY hKey = NULL;
-        HKEY RootKey;
-
-        if (Scope == DICS_FLAG_GLOBAL)
-            RootKey = list->HKLM;
-        else /* Scope == DICS_FLAG_CONFIGSPECIFIC */
-        {
-            hHWProfileKey = OpenHardwareProfileKey(list->HKLM, HwProfile, KEY_CREATE_SUB_KEY);
-            if (hHWProfileKey == INVALID_HANDLE_VALUE)
-                goto cleanup;
-            RootKey = hHWProfileKey;
-        }
-
-        if (KeyType == DIREG_DEV)
-        {
-            struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
-
-            rc = RegCreateKeyExW(
-                RootKey,
-                REGSTR_PATH_SYSTEMENUM,
-                0,
-                NULL,
-                REG_OPTION_NON_VOLATILE,
-                KEY_CREATE_SUB_KEY,
-                NULL,
-                &hEnumKey,
-                NULL);
-            if (rc != ERROR_SUCCESS)
-            {
-                SetLastError(rc);
-                goto cleanup;
-            }
-            rc = RegCreateKeyExW(
-                hEnumKey,
-                deviceInfo->DeviceName,
-                0,
-                NULL,
-                REG_OPTION_NON_VOLATILE,
-#if _WIN32_WINNT >= 0x502
-                KEY_READ | KEY_WRITE,
-#else
-                KEY_ALL_ACCESS,
-#endif
-                NULL,
-                &hKey,
-                NULL);
-            if (rc != ERROR_SUCCESS)
-            {
-                SetLastError(rc);
-                goto cleanup;
-            }
-        }
-        else /* KeyType == DIREG_DRV */
-        {
-            if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) != RPC_S_OK)
-                goto cleanup;
-            /* The driver key is in \System\CurrentControlSet\Control\Class\{GUID}\Index */
-            DriverKey = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpGuidString) + 7) * sizeof(WCHAR) + sizeof(UNICODE_STRING));
-            if (!DriverKey)
-            {
-                SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-                goto cleanup;
-            }
-            strcpyW(DriverKey, L"{");
-            strcatW(DriverKey, lpGuidString);
-            strcatW(DriverKey, L"}\\");
-            pDeviceInstance = &DriverKey[strlenW(DriverKey)];
-            rc = RegOpenKeyExW(RootKey,
-                REGSTR_PATH_CLASS_NT,
-                0,
-                KEY_CREATE_SUB_KEY,
-                &hClassKey);
-            if (rc != ERROR_SUCCESS)
-            {
-                SetLastError(rc);
-                goto cleanup;
-            }
-
-            /* Try all values for Index between 0 and 9999 */
-            Index = 0;
-            while (Index <= 9999)
-            {
-                DWORD Disposition;
-                wsprintf(pDeviceInstance, L"%04lu", Index);
-                rc = RegCreateKeyEx(hClassKey,
-                    DriverKey,
-                    0,
-                    NULL,
-                    REG_OPTION_NON_VOLATILE,
-#if _WIN32_WINNT >= 0x502
-                    KEY_READ | KEY_WRITE,
-#else
-                    KEY_ALL_ACCESS,
-#endif
-                    NULL,
-                    &hKey,
-                    &Disposition);
-                if (rc != ERROR_SUCCESS)
-                {
-                    SetLastError(rc);
-                    goto cleanup;
-                }
-                if (Disposition == REG_CREATED_NEW_KEY)
-                    break;
-                RegCloseKey(hKey);
-                hKey = NULL;
-                Index++;
-            }
-            if (Index > 9999)
-            {
-                /* Unable to create more than 9999 devices within the same class */
-                SetLastError(ERROR_GEN_FAILURE);
-                goto cleanup;
-            }
-
-            /* Open device key, to write Driver value */
-            hDeviceKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, Scope, HwProfile, DIREG_DEV, KEY_SET_VALUE);
-            if (hDeviceKey == INVALID_HANDLE_VALUE)
-                goto cleanup;
-            rc = RegSetValueEx(hDeviceKey, REGSTR_VAL_DRIVER, 0, REG_SZ, (const BYTE *)DriverKey, (strlenW(DriverKey) + 1) * sizeof(WCHAR));
-            if (rc != ERROR_SUCCESS)
-            {
-                SetLastError(rc);
-                goto cleanup;
-            }
-        }
-
-        /* Do installation of the specified section */
-        if (InfHandle)
-        {
-            FIXME("Need to install section %s in file %p\n",
-                debugstr_w(InfSectionName), InfHandle);
-        }
-        ret = hKey;
-
-cleanup:
-        if (lpGuidString)
-            RpcStringFreeW(&lpGuidString);
-        HeapFree(GetProcessHeap(), 0, DriverKey);
-        if (hHWProfileKey != INVALID_HANDLE_VALUE)
-            RegCloseKey(hHWProfileKey);
-        if (hEnumKey != NULL)
-            RegCloseKey(hEnumKey);
-        if (hClassKey != NULL)
-            RegCloseKey(hClassKey);
-        if (hDeviceKey != INVALID_HANDLE_VALUE)
-            RegCloseKey(hDeviceKey);
-        if (hKey != NULL && hKey != ret)
-            RegCloseKey(hKey);
-    }
-
-    TRACE("Returning 0x%p\n", ret);
-    return ret;
-}
-
-/***********************************************************************
- *             SetupDiOpenDevRegKey (SETUPAPI.@)
- */
-HKEY WINAPI
-SetupDiOpenDevRegKey(
-    IN HDEVINFO DeviceInfoSet,
-    IN PSP_DEVINFO_DATA DeviceInfoData,
-    IN DWORD Scope,
-    IN DWORD HwProfile,
-    IN DWORD KeyType,
-    IN REGSAM samDesired)
-{
-    struct DeviceInfoSet *list;
-    HKEY ret = INVALID_HANDLE_VALUE;
-
-    TRACE("%p %p %lu %lu %lu 0x%lx\n", DeviceInfoSet, DeviceInfoData,
-          Scope, HwProfile, KeyType, samDesired);
-
-    if (!DeviceInfoSet)
-        SetLastError(ERROR_INVALID_HANDLE);
-    else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
-        SetLastError(ERROR_INVALID_HANDLE);
-    else if (!DeviceInfoData)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
-        SetLastError(ERROR_INVALID_USER_BUFFER);
-    else if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else
-    {
-        struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
-        LPWSTR DriverKey = NULL;
-        DWORD dwLength = 0;
-        DWORD dwRegType;
-        DWORD rc;
-        HKEY hHWProfileKey = INVALID_HANDLE_VALUE;
-        HKEY hEnumKey = NULL;
-        HKEY hKey = NULL;
-        HKEY RootKey;
-
-        if (Scope == DICS_FLAG_GLOBAL)
-            RootKey = list->HKLM;
-        else /* Scope == DICS_FLAG_CONFIGSPECIFIC */
-        {
-            hHWProfileKey = OpenHardwareProfileKey(list->HKLM, HwProfile, 0);
-            if (hHWProfileKey == INVALID_HANDLE_VALUE)
-                goto cleanup;
-            RootKey = hHWProfileKey;
-        }
-
-        rc = RegOpenKeyExW(
-            RootKey,
-            REGSTR_PATH_SYSTEMENUM,
-            0, /* Options */
-            0,
-            &hEnumKey);
-        if (rc != ERROR_SUCCESS)
-        {
-            SetLastError(rc);
-            goto cleanup;
-        }
-        rc = RegOpenKeyExW(
-            hEnumKey,
-            deviceInfo->DeviceName,
-            0, /* Options */
-            KeyType == DIREG_DEV ? samDesired : KEY_QUERY_VALUE,
-            &hKey);
-        RegCloseKey(hEnumKey);
-        hEnumKey = NULL;
-        if (rc != ERROR_SUCCESS)
-        {
-            SetLastError(rc);
-            goto cleanup;
-        }
-        if (KeyType == DIREG_DEV)
-        {
-            /* We're done. Just return the hKey handle */
-            ret = hKey;
-            goto cleanup;
-        }
-        /* Read the 'Driver' key */
-        rc = RegQueryValueExW(hKey, REGSTR_VAL_DRIVER, NULL, &dwRegType, NULL, &dwLength);
-        if (rc != ERROR_SUCCESS)
-        {
-            SetLastError(rc);
-            goto cleanup;
-        }
-        else if (dwRegType != REG_SZ)
-        {
-            SetLastError(ERROR_GEN_FAILURE);
-            goto cleanup;
-        }
-        DriverKey = HeapAlloc(GetProcessHeap(), 0, dwLength);
-        if (!DriverKey)
-        {
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            goto cleanup;
-        }
-        rc = RegQueryValueExW(hKey, REGSTR_VAL_DRIVER, NULL, &dwRegType, (LPBYTE)DriverKey, &dwLength);
-        if (rc != ERROR_SUCCESS)
-        {
-            SetLastError(rc);
-            goto cleanup;
-        }
-        RegCloseKey(hKey);
-        hKey = NULL;
-        /* Need to open the driver key */
-        rc = RegOpenKeyExW(
-            RootKey,
-            REGSTR_PATH_CLASS_NT,
-            0, /* Options */
-            0,
-            &hEnumKey);
-        if (rc != ERROR_SUCCESS)
-        {
-            SetLastError(rc);
-            goto cleanup;
-        }
-        rc = RegOpenKeyExW(
-            hEnumKey,
-            DriverKey,
-            0, /* Options */
-            samDesired,
-            &hKey);
-        if (rc != ERROR_SUCCESS)
-        {
-            SetLastError(rc);
-            goto cleanup;
-        }
-        ret = hKey;
-
-cleanup:
-        if (hHWProfileKey != INVALID_HANDLE_VALUE)
-            RegCloseKey(hHWProfileKey);
-        if (hEnumKey != NULL)
-            RegCloseKey(hEnumKey);
-        if (hKey != NULL && hKey != ret)
-            RegCloseKey(hKey);
-    }
-
-    TRACE("Returning 0x%p\n", ret);
-    return ret;
-}
-
-/***********************************************************************
- *             SetupDiCreateDeviceInfoA (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiCreateDeviceInfoA(
-    IN HDEVINFO DeviceInfoSet,
-    IN PCSTR DeviceName,
-    IN CONST GUID *ClassGuid,
-    IN PCSTR DeviceDescription OPTIONAL,
-    IN HWND hwndParent OPTIONAL,
-    IN DWORD CreationFlags,
-    OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
-{
-    LPWSTR DeviceNameW = NULL;
-    LPWSTR DeviceDescriptionW = NULL;
-    BOOL bResult;
-
-    TRACE("\n");
-
-    if (DeviceName)
-    {
-        DeviceNameW = MultiByteToUnicode(DeviceName, CP_ACP);
-        if (DeviceNameW == NULL) return FALSE;
-    }
-    if (DeviceDescription)
-    {
-        DeviceDescriptionW = MultiByteToUnicode(DeviceDescription, CP_ACP);
-        if (DeviceDescriptionW == NULL)
-        {
-            if (DeviceNameW) MyFree(DeviceNameW);
-            return FALSE;
-        }
-    }
-
-    bResult = SetupDiCreateDeviceInfoW(DeviceInfoSet, DeviceNameW,
-                                       ClassGuid, DeviceDescriptionW,
-                                       hwndParent, CreationFlags,
-                                       DeviceInfoData);
-
-    if (DeviceNameW) MyFree(DeviceNameW);
-    if (DeviceDescriptionW) MyFree(DeviceDescriptionW);
-
-    return bResult;
-}
-
-/***********************************************************************
- *             SetupDiCreateDeviceInfoW (SETUPAPI.@)
- */
-BOOL WINAPI
-SetupDiCreateDeviceInfoW(
-    IN HDEVINFO DeviceInfoSet,
-    IN PCWSTR DeviceName,
-    IN CONST GUID *ClassGuid,
-    IN PCWSTR DeviceDescription OPTIONAL,
-    IN HWND hwndParent OPTIONAL,
-    IN DWORD CreationFlags,
-    OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
-{
-    struct DeviceInfoSet *list;
-    BOOL ret = FALSE;
-
-    TRACE("%p %s %s %s %p %lx %p\n", DeviceInfoSet, debugstr_w(DeviceName),
-        debugstr_guid(ClassGuid), debugstr_w(DeviceDescription),
-        hwndParent, CreationFlags, DeviceInfoData);
-
-    if (!DeviceInfoSet)
-        SetLastError(ERROR_INVALID_HANDLE);
-    else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
-        SetLastError(ERROR_INVALID_HANDLE);
-    else if (!ClassGuid)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, ClassGuid))
-        SetLastError(ERROR_CLASS_MISMATCH);
-    else if (CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS))
-    {
-        TRACE("Unknown flags: 0x%08lx\n", CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS));
-        SetLastError(ERROR_INVALID_FLAGS);
-    }
-    else
-    {
-        SP_DEVINFO_DATA DevInfo;
-
-        if (CreationFlags & DICD_GENERATE_ID)
-        {
-            /* Generate a new unique ID for this device */
-            SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-            FIXME("not implemented\n");
-        }
-        else
-        {
-            /* Device name is fully qualified. Try to open it */
-            BOOL rc;
-
-            DevInfo.cbSize = sizeof(SP_DEVINFO_DATA);
-            rc = SetupDiOpenDeviceInfoW(
-                DeviceInfoSet,
-                DeviceName,
-                NULL, /* hwndParent */
-                CreationFlags & DICD_INHERIT_CLASSDRVS ? DIOD_INHERIT_CLASSDRVS : 0,
-                &DevInfo);
+                ListEntry = ListEntry->Flink;
+            }
 
-            if (rc)
+            /* Call Device co-installers */
+            ListEntry = DeviceCoInstallersListHead.Flink;
+            while (rc == NO_ERROR && ListEntry != &DeviceCoInstallersListHead)
             {
-                /* SetupDiOpenDeviceInfoW has already added
-                 * the device info to the device info set
-                 */
-                SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
+                struct CoInstallerElement *coinstaller;
+                coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
+                rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
+                coinstaller->PrivateData = Context.PrivateData;
+                if (rc == ERROR_DI_POSTPROCESSING_REQUIRED)
+                {
+                    coinstaller->DoPostProcessing = TRUE;
+                    rc = NO_ERROR;
+                }
+                ListEntry = ListEntry->Flink;
             }
-            else if (GetLastError() == ERROR_FILE_NOT_FOUND)
+
+            /* Call Class installer */
+            if (ClassInstaller)
             {
-                struct DeviceInfoElement *deviceInfo;
+                rc = (*ClassInstaller)(InstallFunction, DeviceInfoSet, DeviceInfoData);
+                FreeFunctionPointer(ClassInstallerLibrary, ClassInstaller);
+            }
+            else
+                rc = ERROR_DI_DO_DEFAULT;
 
-                if (CreateDeviceInfoElement(list, DeviceName, ClassGuid, &deviceInfo))
+            /* Call default handler */
+            if (rc == ERROR_DI_DO_DEFAULT)
+            {
+                if (DefaultHandler && !(InstallParams.Flags & DI_NODI_DEFAULTACTION))
                 {
-                    InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
-
-                    if (!DeviceInfoData)
-                        ret = TRUE;
+                    if ((*DefaultHandler)(DeviceInfoSet, DeviceInfoData))
+                        rc = NO_ERROR;
                     else
-                    {
-                        if (DeviceInfoData->cbSize != sizeof(PSP_DEVINFO_DATA))
-                        {
-                            SetLastError(ERROR_INVALID_USER_BUFFER);
-                        }
-                        else
-                        {
-                            memcpy(&DeviceInfoData->ClassGuid, ClassGuid, sizeof(GUID));
-                            DeviceInfoData->DevInst = deviceInfo->dnDevInst;
-                            DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
-                            ret = TRUE;
-                        }
-                    }
+                        rc = GetLastError();
                 }
+                else
+                    rc = NO_ERROR;
             }
-        }
-    }
-
-    TRACE("Returning %d\n", ret);
-    return ret;
-}
-
-/***********************************************************************
- *             Helper functions for SetupDiBuildDriverInfoList
- */
-static BOOL
-AddDriverToList(
-    IN PLIST_ENTRY DriverListHead,
-    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,
-    IN LPCWSTR MatchingId,
-    FILETIME DriverDate,
-    DWORDLONG DriverVersion,
-    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 InfInstallSection = NULL;
-    BOOL ret = FALSE;
-
-    driverInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DriverInfoElement));
-    if (!driverInfo)
-    {
-        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-        goto cleanup;
-    }
-    memset(driverInfo, 0, sizeof(struct DriverInfoElement));
-
-    driverInfo->Details.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
-    driverInfo->Details.Reserved = (ULONG_PTR)driverInfo;
-
-    /* Copy InfFileName field */
-    strncpyW(driverInfo->Details.InfFileName, InfFile, MAX_PATH - 1);
-    driverInfo->Details.InfFileName[MAX_PATH - 1] = '\0';
-
-    /* Fill InfDate field */
-    hFile = CreateFile(
-        InfFile,
-        GENERIC_READ, FILE_SHARE_READ,
-        NULL, OPEN_EXISTING, 0, NULL);
-    if (hFile == INVALID_HANDLE_VALUE)
-        goto cleanup;
-    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 */
-    if (MatchingId)
-    {
-        driverInfo->MatchingId = HeapAlloc(GetProcessHeap(), 0, (strlenW(MatchingId) + 1) * sizeof(WCHAR));
-        if (!driverInfo->MatchingId)
-        {
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            goto cleanup;
-        }
-        RtlCopyMemory(driverInfo->MatchingId, MatchingId, (strlenW(MatchingId) + 1) * sizeof(WCHAR));
-    }
-    else
-        driverInfo->MatchingId = NULL;
-
-    /* Get inf install section */
-    Result = FALSE;
-    RequiredSize = 128; /* Initial buffer size */
-    SetLastError(ERROR_INSUFFICIENT_BUFFER);
-    while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
-    {
-        HeapFree(GetProcessHeap(), 0, InfInstallSection);
-        InfInstallSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
-        if (!InfInstallSection)
-            goto cleanup;
-        Result = SetupGetStringFieldW(
-            &ContextDevice,
-            1, /* Field index */
-            InfInstallSection, RequiredSize,
-            &RequiredSize);
-    }
-    if (!Result)
-        goto cleanup;
-
-    TRACE("Adding driver '%s' [%s/%s] (Rank 0x%lx)\n",
-        debugstr_w(driverInfo->Details.DrvDescription), debugstr_w(InfFile),
-        debugstr_w(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;
-    strncpyW(driverInfo->Info.Description, driverInfo->Details.DrvDescription, LINE_LEN - 1);
-    driverInfo->Info.Description[LINE_LEN - 1] = '\0';
-    strncpyW(driverInfo->Info.MfgName, ManufacturerName, LINE_LEN - 1);
-    driverInfo->Info.MfgName[LINE_LEN - 1] = '\0';
-    if (ProviderName)
-    {
-        strncpyW(driverInfo->Info.ProviderName, ProviderName, LINE_LEN - 1);
-        driverInfo->Info.ProviderName[LINE_LEN - 1] = '\0';
-    }
-    else
-        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;
-    while (PreviousEntry != DriverListHead)
-    {
-        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->Blink, &driverInfo->ListEntry);
-            break;
-        }
-        PreviousEntry = PreviousEntry->Flink;
-    }
-    if (PreviousEntry == DriverListHead)
-    {
-        /* Insert at the end of the list */
-        InsertTailList(DriverListHead, &driverInfo->ListEntry);
-    }
-
-    ret = TRUE;
-
-cleanup:
-    if (!ret)
-    {
-        if (driverInfo)
-            HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId);
-        HeapFree(GetProcessHeap(), 0, driverInfo);
-    }
-    if (hFile != INVALID_HANDLE_VALUE)
-        CloseHandle(hFile);
-    HeapFree(GetProcessHeap(), 0, InfInstallSection);
-
-    return ret;
-}
 
-static BOOL
-GetVersionInformationFromInfFile(
-    IN HINF hInf,
-    OUT LPGUID ClassGuid,
-    OUT LPWSTR* pProviderName,
-    OUT FILETIME* DriverDate,
-    OUT DWORDLONG* DriverVersion)
-{
-    DWORD RequiredSize;
-    WCHAR guidW[MAX_GUID_STRING_LEN + 1];
-    LPWSTR DriverVer = NULL;
-    LPWSTR ProviderName = NULL;
-    LPWSTR pComma; /* Points into DriverVer */
-    LPWSTR pVersion = NULL; /* Points into DriverVer */
-    SYSTEMTIME SystemTime;
-    BOOL Result;
-    BOOL ret = FALSE; /* Final result */
-
-    /* Get class Guid */
-    if (!SetupGetLineTextW(
-        NULL, /* Context */
-        hInf,
-        Version, ClassGUID,
-        guidW, sizeof(guidW),
-        NULL /* Required size */))
-    {
-        goto cleanup;
-    }
-    guidW[37] = '\0'; /* Replace the } by a NULL character */
-    if (UuidFromStringW(&guidW[1], ClassGuid) != RPC_S_OK)
-    {
-        SetLastError(ERROR_GEN_FAILURE);
-        goto cleanup;
-    }
+            /* Call Class co-installers that required postprocessing */
+            Context.PostProcessing = TRUE;
+            ListEntry = ClassCoInstallersListHead.Flink;
+            while (ListEntry != &ClassCoInstallersListHead)
+            {
+                struct CoInstallerElement *coinstaller;
+                coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
+                if (coinstaller->DoPostProcessing)
+                {
+                    Context.InstallResult = rc;
+                    Context.PrivateData = coinstaller->PrivateData;
+                    rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
+                }
+                FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
+                ListEntry = ListEntry->Flink;
+            }
 
-    /* Get provider name */
-    Result = SetupGetLineTextW(
-        NULL, /* Context */
-        hInf, Version, INF_PROVIDER,
-        NULL, 0,
-        &RequiredSize);
-    if (Result)
-    {
-        /* We know know the needed buffer size */
-        ProviderName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
-        if (!ProviderName)
-        {
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            goto cleanup;
-        }
-        Result = SetupGetLineTextW(
-            NULL, /* Context */
-            hInf, Version, INF_PROVIDER,
-            ProviderName, RequiredSize,
-            &RequiredSize);
-    }
-    if (!Result)
-        goto cleanup;
-    *pProviderName = ProviderName;
-
-    /* Read the "DriverVer" value */
-    Result = SetupGetLineTextW(
-        NULL, /* Context */
-        hInf, Version, INF_DRIVER_VER,
-        NULL, 0,
-        &RequiredSize);
-    if (Result)
-    {
-        /* We know know the needed buffer size */
-        DriverVer = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
-        if (!DriverVer)
-        {
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            goto cleanup;
-        }
-        Result = SetupGetLineTextW(
-            NULL, /* Context */
-            hInf, Version, INF_DRIVER_VER,
-            DriverVer, RequiredSize,
-            &RequiredSize);
-    }
-    if (!Result)
-        goto cleanup;
+            /* Call Device co-installers that required postprocessing */
+            ListEntry = DeviceCoInstallersListHead.Flink;
+            while (ListEntry != &DeviceCoInstallersListHead)
+            {
+                struct CoInstallerElement *coinstaller;
+                coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
+                if (coinstaller->DoPostProcessing)
+                {
+                    Context.InstallResult = rc;
+                    Context.PrivateData = coinstaller->PrivateData;
+                    rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
+                }
+                FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
+                ListEntry = ListEntry->Flink;
+            }
 
-    /* Get driver date and driver version, by analyzing the "DriverVer" value */
-    pComma = strchrW(DriverVer, ',');
-    if (pComma != NULL)
-    {
-        *pComma = UNICODE_NULL;
-        pVersion = pComma + 1;
-    }
-    /* Get driver date version. Invalid date = 00/00/00 */
-    memset(DriverDate, 0, sizeof(FILETIME));
-    if (strlenW(DriverVer) == 10
-        && (DriverVer[2] == '-' || DriverVer[2] == '/')
-        && (DriverVer[5] == '-' || DriverVer[5] == '/'))
-    {
-        memset(&SystemTime, 0, sizeof(SYSTEMTIME));
-        DriverVer[2] = DriverVer[5] = UNICODE_NULL;
-        SystemTime.wMonth = ((DriverVer[0] - '0') * 10) + DriverVer[1] - '0';
-        SystemTime.wDay  = ((DriverVer[3] - '0') * 10) + DriverVer[4] - '0';
-        SystemTime.wYear = ((DriverVer[6] - '0') * 1000) + ((DriverVer[7] - '0') * 100) + ((DriverVer[8] - '0') * 10) + DriverVer[9] - '0';
-        SystemTimeToFileTime(&SystemTime, DriverDate);
-    }
-    /* Get driver version. Invalid version = 0.0.0.0 */
-    *DriverVersion = 0;
-    if (pVersion)
-    {
-        WORD Major, Minor = 0, Revision = 0, Build = 0;
-        LPWSTR pMinor = NULL, pRevision = NULL, pBuild = NULL;
-        LARGE_INTEGER fullVersion;
+            /* Free allocated memory */
+            while (!IsListEmpty(&ClassCoInstallersListHead))
+            {
+                ListEntry = RemoveHeadList(&ClassCoInstallersListHead);
+                HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry));
+            }
+            while (!IsListEmpty(&DeviceCoInstallersListHead))
+            {
+                ListEntry = RemoveHeadList(&DeviceCoInstallersListHead);
+                HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry));
+            }
 
-        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);
+            ret = (rc == NO_ERROR);
         }
-        Major = atoiW(pVersion);
-        fullVersion.u.HighPart = Major << 16 | Minor;
-        fullVersion.u.LowPart = Revision << 16 | Build;
-        memcpy(DriverVersion, &fullVersion, sizeof(LARGE_INTEGER));
     }
 
-    ret = TRUE;
-
-cleanup:
-    if (!ret)
-        HeapFree(GetProcessHeap(), 0, ProviderName);
-    HeapFree(GetProcessHeap(), 0, DriverVer);
-
+    TRACE("Returning %d\n", ret);
     return ret;
 }
 
-static BOOL
-GetHardwareAndCompatibleIDsLists(
+/***********************************************************************
+ *             SetupDiGetDeviceInfoListClass  (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiGetDeviceInfoListClass(
     IN HDEVINFO DeviceInfoSet,
-    IN OUT PSP_DEVINFO_DATA DeviceInfoData,
-    OUT LPWSTR *pHardwareIDs OPTIONAL,
-    OUT LPDWORD pHardwareIDsRequiredSize OPTIONAL,
-    OUT LPWSTR *pCompatibleIDs OPTIONAL,
-    OUT LPDWORD pCompatibleIDsRequiredSize OPTIONAL)
+    OUT LPGUID ClassGuid)
 {
-    LPWSTR HardwareIDs = NULL;
-    LPWSTR CompatibleIDs = NULL;
-    DWORD RequiredSize;
-    BOOL Result;
-
-    /* Get hardware IDs list */
-    Result = FALSE;
-    RequiredSize = 512; /* Initial buffer size */
-    SetLastError(ERROR_INSUFFICIENT_BUFFER);
-    while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
-    {
-        MyFree(HardwareIDs);
-        HardwareIDs = MyMalloc(RequiredSize);
-        if (!HardwareIDs)
-        {
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            goto done;
-        }
-        Result = SetupDiGetDeviceRegistryPropertyW(
-            DeviceInfoSet,
-            DeviceInfoData,
-            SPDRP_HARDWAREID,
-            NULL,
-            (PBYTE)HardwareIDs,
-            RequiredSize,
-            &RequiredSize);
-    }
-    if (!Result)
-    {
-        if (GetLastError() == ERROR_FILE_NOT_FOUND)
-        {
-            /* No hardware ID for this device */
-            MyFree(HardwareIDs);
-            HardwareIDs = NULL;
-            RequiredSize = 0;
-        }
-        else
-            goto done;
-    }
-    if (pHardwareIDs)
-        *pHardwareIDs = HardwareIDs;
-    if (pHardwareIDsRequiredSize)
-        *pHardwareIDsRequiredSize = RequiredSize;
-
-    /* Get compatible IDs list */
-    Result = FALSE;
-    RequiredSize = 512; /* Initial buffer size */
-    SetLastError(ERROR_INSUFFICIENT_BUFFER);
-    while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
-    {
-        MyFree(CompatibleIDs);
-        CompatibleIDs = MyMalloc(RequiredSize);
-        if (!CompatibleIDs)
-        {
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            goto done;
-        }
-        Result = SetupDiGetDeviceRegistryPropertyW(
-            DeviceInfoSet,
-            DeviceInfoData,
-            SPDRP_COMPATIBLEIDS,
-            NULL,
-            (PBYTE)CompatibleIDs,
-            RequiredSize,
-            &RequiredSize);
-    }
-    if (!Result)
-    {
-        if (GetLastError() == ERROR_FILE_NOT_FOUND)
-        {
-            /* No compatible ID for this device */
-            MyFree(CompatibleIDs);
-            CompatibleIDs = NULL;
-            RequiredSize = 0;
-        }
-        else
-            goto done;
-    }
-    if (pCompatibleIDs)
-        *pCompatibleIDs = CompatibleIDs;
-    if (pCompatibleIDsRequiredSize)
-        *pCompatibleIDsRequiredSize = RequiredSize;
+    struct DeviceInfoSet *list;
+    BOOL ret = FALSE;
 
-    Result = TRUE;
+    TRACE("%p %p\n", DeviceInfoSet, ClassGuid);
 
-done:
-    if (!Result)
+    if (!DeviceInfoSet)
+        SetLastError(ERROR_INVALID_HANDLE);
+    else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
+        SetLastError(ERROR_INVALID_HANDLE);
+    else if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
+        SetLastError(ERROR_NO_ASSOCIATED_CLASS);
+    else
     {
-        MyFree(HardwareIDs);
-        MyFree(CompatibleIDs);
+        memcpy(&ClassGuid, &list->ClassGuid, sizeof(GUID));
+
+        ret = TRUE;
     }
-    return Result;
+
+    TRACE("Returning %d\n", ret);
+    return ret;
 }
 
-static struct InfFileDetails *
-CreateInfFileDetails(
-    IN LPCWSTR FullInfFileName)
+/***********************************************************************
+ *             SetupDiGetDeviceInfoListDetailW  (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiGetDeviceInfoListDetailW(
+    IN HDEVINFO DeviceInfoSet,
+    OUT PSP_DEVINFO_LIST_DETAIL_DATA_W DeviceInfoListDetailData)
 {
-    struct InfFileDetails *details;
-    PWCHAR last;
-    DWORD Needed;
+    struct DeviceInfoSet *list;
+    BOOL ret = FALSE;
 
-    Needed = FIELD_OFFSET(struct InfFileDetails, szData)
-        + strlenW(FullInfFileName) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
+    TRACE("%p %p\n", DeviceInfoSet, DeviceInfoListDetailData);
 
-    details = HeapAlloc(GetProcessHeap(), 0, Needed);
-    if (!details)
+    if (!DeviceInfoSet)
+        SetLastError(ERROR_INVALID_HANDLE);
+    else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
+        SetLastError(ERROR_INVALID_HANDLE);
+    else if (!DeviceInfoListDetailData)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (DeviceInfoListDetailData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W))
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else
     {
-        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-        return NULL;
-    }
+        memcpy(
+            &DeviceInfoListDetailData->ClassGuid,
+            &list->ClassGuid,
+            sizeof(GUID));
+        DeviceInfoListDetailData->RemoteMachineHandle = list->hMachine;
+        if (list->MachineName)
+            strcpyW(DeviceInfoListDetailData->RemoteMachineName, list->MachineName + 2);
+        else
+            DeviceInfoListDetailData->RemoteMachineName[0] = 0;
 
-    memset(details, 0, Needed);
-    strcpyW(details->szData, FullInfFileName);
-    last = strrchrW(details->szData, '\\');
-    if (last)
-    {
-        details->DirectoryName = details->szData;
-        details->FileName = last + 1;
-        *last = '\0';
+        ret = TRUE;
     }
+
+    TRACE("Returning %d\n", ret);
+    return ret;
+}
+
+/***********************************************************************
+ *             SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiGetDeviceInstallParamsA(
+    IN HDEVINFO DeviceInfoSet,
+    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
+    OUT PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
+{
+    SP_DEVINSTALL_PARAMS_W deviceInstallParamsW;
+    BOOL ret = FALSE;
+
+    TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
+
+    if (DeviceInstallParams == NULL)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
+        SetLastError(ERROR_INVALID_USER_BUFFER);
     else
-        details->FileName = details->szData;
-    ReferenceInfFile(details);
-    details->hInf = SetupOpenInfFileW(FullInfFileName, NULL, INF_STYLE_WIN4, NULL);
-    if (details->hInf == INVALID_HANDLE_VALUE)
     {
-        HeapFree(GetProcessHeap(), 0, details);
-        return NULL;
+        deviceInstallParamsW.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
+        ret = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &deviceInstallParamsW);
+
+        if (ret)
+        {
+            /* Do W->A conversion */
+            memcpy(
+                DeviceInstallParams,
+                &deviceInstallParamsW,
+                FIELD_OFFSET(SP_DEVINSTALL_PARAMS_W, DriverPath));
+            if (WideCharToMultiByte(CP_ACP, 0, deviceInstallParamsW.DriverPath, -1,
+                DeviceInstallParams->DriverPath, MAX_PATH, NULL, NULL) == 0)
+            {
+                DeviceInstallParams->DriverPath[0] = '\0';
+                ret = FALSE;
+            }
+        }
     }
-    return details;
+
+    TRACE("Returning %d\n", ret);
+    return ret;
 }
 
 /***********************************************************************
- *             SetupDiBuildDriverInfoList (SETUPAPI.@)
+ *             SetupDiGetDeviceInstallParamsW (SETUPAPI.@)
  */
 BOOL WINAPI
-SetupDiBuildDriverInfoList(
+SetupDiGetDeviceInstallParamsW(
     IN HDEVINFO DeviceInfoSet,
-    IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
-    IN DWORD DriverType)
+    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
+    OUT PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
 {
     struct DeviceInfoSet *list;
-    SP_DEVINSTALL_PARAMS_W InstallParams;
-    PVOID Buffer = NULL;
-    struct InfFileDetails *currentInfFileDetails = NULL;
-    LPWSTR ProviderName = NULL;
-    LPWSTR ManufacturerName = NULL;
-    WCHAR ManufacturerSection[LINE_LEN + 1];
-    LPWSTR HardwareIDs = NULL;
-    LPWSTR CompatibleIDs = NULL;
-    LPWSTR FullInfFileName = NULL;
-    LPWSTR ExcludeFromSelect = NULL;
-    FILETIME DriverDate;
-    DWORDLONG DriverVersion = 0;
-    DWORD RequiredSize;
     BOOL ret = FALSE;
 
-    TRACE("%p %p %ld\n", DeviceInfoSet, DeviceInfoData, DriverType);
+    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 (list->HKLM != HKEY_LOCAL_MACHINE)
-        SetLastError(ERROR_INVALID_HANDLE);
-    else if (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER)
-        SetLastError(ERROR_INVALID_PARAMETER);
-    else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData)
-        SetLastError(ERROR_INVALID_PARAMETER);
     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
     {
-        PLIST_ENTRY pDriverListHead = &list->DriverListHead;
-        BOOL Result;
-
-        InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
-        Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
-        if (!Result)
-            goto done;
+        PSP_DEVINSTALL_PARAMS_W Source;
 
         if (DeviceInfoData)
-        {
-            struct DeviceInfoElement *devInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
-            if (!(devInfo->CreationFlags & DICD_INHERIT_CLASSDRVS))
-                pDriverListHead = &devInfo->DriverListHead;
-        }
-
-        if (DriverType == SPDIT_COMPATDRIVER)
-        {
-            /* Get hardware and compatible IDs lists */
-            Result = GetHardwareAndCompatibleIDsLists(
-                DeviceInfoSet,
-                DeviceInfoData,
-                &HardwareIDs,
-                NULL,
-                &CompatibleIDs,
-                NULL);
-            if (!Result)
-                goto done;
-            if (!HardwareIDs && !CompatibleIDs)
-            {
-                SetLastError(ERROR_FILE_NOT_FOUND);
-                goto done;
-            }
-        }
-
-        if (InstallParams.Flags & DI_ENUMSINGLEINF)
-        {
-            /* InstallParams.DriverPath contains the name of a .inf file */
-            RequiredSize = strlenW(InstallParams.DriverPath) + 2;
-            Buffer = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
-            if (!Buffer)
-            {
-                SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-                goto done;
-            }
-            strcpyW(Buffer, InstallParams.DriverPath);
-            ((LPWSTR)Buffer)[RequiredSize - 1] = 0;
-            Result = TRUE;
-        }
+            Source = &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->InstallParams;
         else
-        {
-            /* Enumerate .inf files */
-            Result = FALSE;
-            RequiredSize = 32768; /* Initial buffer size */
-            SetLastError(ERROR_INSUFFICIENT_BUFFER);
-            while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
-            {
-                HeapFree(GetProcessHeap(), 0, Buffer);
-                Buffer = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
-                if (!Buffer)
-                {
-                    Result = FALSE;
-                    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-                    break;
-                }
-                Result = SetupGetInfFileListW(
-                    *InstallParams.DriverPath ? InstallParams.DriverPath : NULL,
-                    INF_STYLE_WIN4,
-                    Buffer, RequiredSize,
-                    &RequiredSize);
-            }
-            if (!Result && GetLastError() == ERROR_FILE_NOT_FOUND)
-            {
-                /* No .inf file in specified directory. So, we should
-                 * success as we created an empty driver info list.
-                 */
-                ret = TRUE;
-                goto done;
-            }
-        }
-        if (Result)
-        {
-            LPCWSTR filename;
-            LPWSTR pFullFilename;
+            Source = &list->InstallParams;
+        memcpy(DeviceInstallParams, Source, Source->cbSize);
+        ret = TRUE;
+    }
 
-            if (InstallParams.Flags & DI_ENUMSINGLEINF)
-            {
-                /* Only a filename */
-                FullInfFileName = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
-                if (!FullInfFileName)
-                    goto done;
-                pFullFilename = &FullInfFileName[0];
-            }
-            else if (*InstallParams.DriverPath)
-            {
-                /* Directory name specified */
-                DWORD len;
-                len = GetFullPathNameW(InstallParams.DriverPath, 0, NULL, NULL);
-                if (len == 0)
-                    goto done;
-                FullInfFileName = HeapAlloc(GetProcessHeap(), 0, (len + 1 + MAX_PATH) * sizeof(WCHAR));
-                if (!FullInfFileName)
-                    goto done;
-                len = GetFullPathNameW(InstallParams.DriverPath, len, FullInfFileName, NULL);
-                if (len == 0)
-                    goto done;
-                if (*FullInfFileName && FullInfFileName[strlenW(FullInfFileName) - 1] != '\\')
-                    strcatW(FullInfFileName, BackSlash);
-                pFullFilename = &FullInfFileName[strlenW(FullInfFileName)];
-            }
-            else
-            {
-                /* Nothing specified ; need to get the %SYSTEMROOT%\ directory */
-                DWORD len;
-                len = GetSystemWindowsDirectoryW(NULL, 0);
-                if (len == 0)
-                    goto done;
-                FullInfFileName = HeapAlloc(GetProcessHeap(), 0, (len + 1 + strlenW(InfDirectory) + MAX_PATH) * sizeof(WCHAR));
-                if (!FullInfFileName)
-                    goto done;
-                len = GetSystemWindowsDirectoryW(FullInfFileName, len);
-                if (len == 0)
-                    goto done;
-                if (*FullInfFileName && FullInfFileName[strlenW(FullInfFileName) - 1] != '\\')
-                    strcatW(FullInfFileName, BackSlash);
-                strcatW(FullInfFileName, InfDirectory);
-                pFullFilename = &FullInfFileName[strlenW(FullInfFileName)];
-            }
+    TRACE("Returning %d\n", ret);
+    return ret;
+}
 
-            for (filename = (LPCWSTR)Buffer; *filename; filename += strlenW(filename) + 1)
-            {
-                INFCONTEXT ContextManufacturer, ContextDevice;
-                GUID ClassGuid;
-
-                strcpyW(pFullFilename, filename);
-                TRACE("Opening file %s\n", debugstr_w(FullInfFileName));
-
-                currentInfFileDetails = CreateInfFileDetails(FullInfFileName);
-                if (!currentInfFileDetails)
-                    continue;
-
-                if (!GetVersionInformationFromInfFile(
-                    currentInfFileDetails->hInf,
-                    &ClassGuid,
-                    &ProviderName,
-                    &DriverDate,
-                    &DriverVersion))
-                {
-                    DereferenceInfFile(currentInfFileDetails);
-                    currentInfFileDetails = NULL;
-                    continue;
-                }
+static BOOL
+CheckDeviceInstallParameters(
+    IN PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
+{
+    DWORD SupportedFlags =
+        DI_NOVCP |                            /* 0x00000008 */
+        DI_DIDCOMPAT |                        /* 0x00000010 */
+        DI_DIDCLASS |                         /* 0x00000020 */
+        DI_NEEDRESTART |                      /* 0x00000080 */
+        DI_NEEDREBOOT |                       /* 0x00000100 */
+        DI_RESOURCEPAGE_ADDED |               /* 0x00002000 */
+        DI_PROPERTIES_CHANGE |                /* 0x00004000 */
+        DI_ENUMSINGLEINF |                    /* 0x00010000 */
+        DI_DONOTCALLCONFIGMG |                /* 0x00020000 */
+        DI_CLASSINSTALLPARAMS |               /* 0x00100000 */
+        DI_NODI_DEFAULTACTION |               /* 0x00200000 */
+        DI_QUIETINSTALL |                     /* 0x00800000 */
+        DI_NOFILECOPY |                       /* 0x01000000 */
+        DI_DRIVERPAGE_ADDED;                  /* 0x04000000 */
+    DWORD SupportedFlagsEx =
+        DI_FLAGSEX_CI_FAILED |                /* 0x00000004 */
+        DI_FLAGSEX_DIDINFOLIST |              /* 0x00000010 */
+        DI_FLAGSEX_DIDCOMPATINFO |            /* 0x00000020 */
+        DI_FLAGSEX_ALLOWEXCLUDEDDRVS |        /* 0x00000800 */
+        DI_FLAGSEX_NO_DRVREG_MODIFY;          /* 0x00008000 */
+    BOOL ret = FALSE;
 
-                if (DriverType == SPDIT_CLASSDRIVER)
-                {
-                    /* Check if the ClassGuid in this .inf file is corresponding with our needs */
-                    if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, &ClassGuid))
-                    {
-                        goto next;
-                    }
-                }
+    /* FIXME: add support for more flags */
 
-                if (InstallParams.FlagsEx & DI_FLAGSEX_ALLOWEXCLUDEDDRVS)
-                {
-                    /* Read ExcludeFromSelect control flags */
-                    /* FIXME */
-                }
-                else
-                    FIXME("ExcludeFromSelect list ignored\n");
+    /* FIXME: DI_CLASSINSTALLPARAMS flag is not correctly used.
+     * It should be checked before accessing to other values
+     * of the SP_DEVINSTALL_PARAMS structure */
 
-                /* Get the manufacturers list */
-                Result = SetupFindFirstLineW(currentInfFileDetails->hInf, INF_MANUFACTURER, NULL, &ContextManufacturer);
-                while (Result)
-                {
-                    Result = SetupGetStringFieldW(
-                        &ContextManufacturer,
-                        0, /* Field index */
-                        NULL, 0,
-                        &RequiredSize);
-                    if (Result)
-                    {
-                        /* We got the needed size for the buffer */
-                        ManufacturerName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
-                        if (!ManufacturerName)
-                        {
-                            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-                            goto done;
-                        }
-                        Result = SetupGetStringFieldW(
-                            &ContextManufacturer,
-                            0, /* Field index */
-                            ManufacturerName, RequiredSize,
-                            &RequiredSize);
-                    }
-                    /* Get manufacturer section name */
-                    Result = SetupGetStringFieldW(
-                        &ContextManufacturer,
-                        1, /* Field index */
-                        ManufacturerSection, LINE_LEN,
-                        &RequiredSize);
-                    if (Result)
-                    {
-                        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)
-                        {
-                            TRACE("Enumerating devices in manufacturer %s\n", debugstr_w(ManufacturerSection));
-                            Result = SetupFindFirstLineW(currentInfFileDetails->hInf, ManufacturerSection, NULL, &ContextDevice);
-                        }
-                    }
-                    while (Result)
-                    {
-                        if (DriverType == SPDIT_CLASSDRIVER)
-                        {
-                            /* FIXME: Check ExcludeFromSelect list */
-                            if (!AddDriverToList(
-                                pDriverListHead,
-                                DriverType,
-                                &ClassGuid,
-                                ContextDevice,
-                                currentInfFileDetails,
-                                FullInfFileName,
-                                ProviderName,
-                                ManufacturerName,
-                                NULL,
-                                DriverDate, DriverVersion,
-                                0))
-                            {
-                                break;
-                            }
-                        }
-                        else /* DriverType = SPDIT_COMPATDRIVER */
-                        {
-                            /* 1. Get all fields */
-                            DWORD FieldCount = SetupGetFieldCount(&ContextDevice);
-                            DWORD DriverRank;
-                            DWORD i;
-                            LPCWSTR currentId;
-                            BOOL DriverAlreadyAdded;
-
-                            for (i = 2; i <= FieldCount; i++)
-                            {
-                                LPWSTR DeviceId = NULL;
-                                Result = FALSE;
-                                RequiredSize = 128; /* Initial buffer size */
-                                SetLastError(ERROR_INSUFFICIENT_BUFFER);
-                                while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
-                                {
-                                    HeapFree(GetProcessHeap(), 0, DeviceId);
-                                    DeviceId = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
-                                    if (!DeviceId)
-                                    {
-                                        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-                                        goto done;
-                                    }
-                                    Result = SetupGetStringFieldW(
-                                        &ContextDevice,
-                                        i,
-                                        DeviceId, RequiredSize,
-                                        &RequiredSize);
-                                }
-                                if (!Result)
-                                {
-                                    HeapFree(GetProcessHeap(), 0, DeviceId);
-                                    goto done;
-                                }
-                                /* FIXME: Check ExcludeFromSelect list */
-                                DriverAlreadyAdded = FALSE;
-                                for (DriverRank = 0, currentId = (LPCWSTR)HardwareIDs; !DriverAlreadyAdded && *currentId; currentId += strlenW(currentId) + 1, DriverRank++)
-                                {
-                                    if (strcmpiW(DeviceId, currentId) == 0)
-                                    {
-                                        AddDriverToList(
-                                            pDriverListHead,
-                                            DriverType,
-                                            &ClassGuid,
-                                            ContextDevice,
-                                            currentInfFileDetails,
-                                            FullInfFileName,
-                                            ProviderName,
-                                            ManufacturerName,
-                                            currentId,
-                                            DriverDate, DriverVersion,
-                                            DriverRank  + (i == 2 ? 0 : 0x1000 + i - 3));
-                                        DriverAlreadyAdded = TRUE;
-                                    }
-                                }
-                                if (CompatibleIDs)
-                                {
-                                    for (DriverRank = 0, currentId = (LPCWSTR)CompatibleIDs; !DriverAlreadyAdded && *currentId; currentId += strlenW(currentId) + 1, DriverRank++)
-                                    {
-                                        if (strcmpiW(DeviceId, currentId) == 0)
-                                        {
-                                            AddDriverToList(
-                                                pDriverListHead,
-                                                DriverType,
-                                                &ClassGuid,
-                                                ContextDevice,
-                                                currentInfFileDetails,
-                                                FullInfFileName,
-                                                ProviderName,
-                                                ManufacturerName,
-                                                currentId,
-                                                DriverDate, DriverVersion,
-                                                DriverRank + (i == 2 ? 0x2000 : 0x3000 + i - 3));
-                                            DriverAlreadyAdded = TRUE;
-                                        }
-                                    }
-                                }
-                                HeapFree(GetProcessHeap(), 0, DeviceId);
-                            }
-                        }
-                        Result = SetupFindNextLine(&ContextDevice, &ContextDevice);
-                    }
+    if (DeviceInstallParams->Flags & ~SupportedFlags)
+    {
+        FIXME("Unknown Flags: 0x%08lx\n", DeviceInstallParams->Flags & ~SupportedFlags);
+        SetLastError(ERROR_INVALID_FLAGS);
+    }
+    else if (DeviceInstallParams->FlagsEx & ~SupportedFlagsEx)
+    {
+        FIXME("Unknown FlagsEx: 0x%08lx\n", DeviceInstallParams->FlagsEx & ~SupportedFlagsEx);
+        SetLastError(ERROR_INVALID_FLAGS);
+    }
+    else if ((DeviceInstallParams->Flags & DI_NOVCP)
+        && (DeviceInstallParams->FileQueue == NULL || DeviceInstallParams->FileQueue == (HSPFILEQ)INVALID_HANDLE_VALUE))
+        SetLastError(ERROR_INVALID_USER_BUFFER);
+    else
+    {
+        /* FIXME: check Reserved field */
+        ret = TRUE;
+    }
 
-                    HeapFree(GetProcessHeap(), 0, ManufacturerName);
-                    ManufacturerName = NULL;
-                    Result = SetupFindNextLine(&ContextManufacturer, &ContextManufacturer);
-                }
+    return ret;
+}
 
-                ret = TRUE;
-next:
-                HeapFree(GetProcessHeap(), 0, ProviderName);
-                HeapFree(GetProcessHeap(), 0, ExcludeFromSelect);
-                ProviderName = ExcludeFromSelect = NULL;
+/***********************************************************************
+ *             SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiSetDeviceInstallParamsW(
+    IN HDEVINFO DeviceInfoSet,
+    IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
+    IN PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
+{
+    struct DeviceInfoSet *list;
+    BOOL ret = FALSE;
 
-                DereferenceInfFile(currentInfFileDetails);
-                currentInfFileDetails = NULL;
-            }
-            ret = TRUE;
-        }
-    }
+    TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
 
-done:
-    if (ret)
+    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 if (CheckDeviceInstallParameters(DeviceInstallParams))
     {
+        PSP_DEVINSTALL_PARAMS_W Destination;
+
         if (DeviceInfoData)
-        {
-            InstallParams.Flags |= DI_DIDCOMPAT;
-            InstallParams.FlagsEx |= DI_FLAGSEX_DIDCOMPATINFO;
-        }
+            Destination = &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->InstallParams;
         else
-        {
-            InstallParams.Flags |= DI_DIDCLASS;
-            InstallParams.FlagsEx |= DI_FLAGSEX_DIDINFOLIST;
-        }
-        ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
+            Destination = &list->InstallParams;
+        memcpy(Destination, DeviceInstallParams, DeviceInstallParams->cbSize);
+        ret = TRUE;
     }
 
-    HeapFree(GetProcessHeap(), 0, ProviderName);
-    HeapFree(GetProcessHeap(), 0, ManufacturerName);
-    MyFree(HardwareIDs);
-    MyFree(CompatibleIDs);
-    HeapFree(GetProcessHeap(), 0, FullInfFileName);
-    HeapFree(GetProcessHeap(), 0, ExcludeFromSelect);
-    if (currentInfFileDetails)
-        DereferenceInfFile(currentInfFileDetails);
-    HeapFree(GetProcessHeap(), 0, Buffer);
-
     TRACE("Returning %d\n", ret);
     return ret;
 }
 
 /***********************************************************************
- *             SetupDiDeleteDeviceInfo (SETUPAPI.@)
+ *             SetupDiGetDeviceInstanceIdA(SETUPAPI.@)
  */
 BOOL WINAPI
-SetupDiDeleteDeviceInfo(
+SetupDiGetDeviceInstanceIdA(
     IN HDEVINFO DeviceInfoSet,
-    IN PSP_DEVINFO_DATA DeviceInfoData)
+    IN PSP_DEVINFO_DATA DeviceInfoData,
+    OUT PSTR DeviceInstanceId OPTIONAL,
+    IN DWORD DeviceInstanceIdSize,
+    OUT PDWORD RequiredSize OPTIONAL)
 {
-    TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
+    PWSTR DeviceInstanceIdW = NULL;
+    BOOL ret = FALSE;
 
-    FIXME("not implemented\n");
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
+    TRACE("%p %p %p %lu %p\n", DeviceInfoSet, DeviceInfoData,
+          DeviceInstanceId, DeviceInstanceIdSize, RequiredSize);
+
+    if (!DeviceInstanceId && DeviceInstanceIdSize > 0)
+        SetLastError(ERROR_INVALID_PARAMETER);
+    else
+    {
+        if (DeviceInstanceIdSize != 0)
+        {
+            DeviceInstanceIdW = MyMalloc(DeviceInstanceIdSize * sizeof(WCHAR));
+            if (DeviceInstanceIdW == NULL)
+                return FALSE;
+        }
+
+        ret = SetupDiGetDeviceInstanceIdW(DeviceInfoSet, DeviceInfoData,