add stub for SetupDiSetClassInstallParamsW
[reactos.git] / reactos / lib / setupapi / devinst.c
index bdecfe3..c05b63f 100644 (file)
@@ -66,12 +66,17 @@ typedef BOOL
 (WINAPI* DEFAULT_CLASS_INSTALL_PROC) (
     IN HDEVINFO DeviceInfoSet,
     IN OUT PSP_DEVINFO_DATA DeviceInfoData);
-typedef DWORD 
+typedef DWORD
 (CALLBACK* COINSTALLER_PROC) (
     IN DI_FUNCTION InstallFunction,
     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);
 
 struct CoInstallerElement
 {
@@ -149,13 +154,14 @@ BOOL WINAPI SetupDiBuildClassInfoListExW(
     LONG lError;
     DWORD dwGuidListIndex = 0;
 
-    TRACE("\n");
+    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_ALL_ACCESS,
+                                            KEY_ENUMERATE_SUB_KEYS,
                                             DIOCR_INSTALLER,
                                             MachineName,
                                             Reserved);
@@ -178,12 +184,12 @@ BOOL WINAPI SetupDiBuildClassInfoListExW(
        TRACE("RegEnumKeyExW() returns %ld\n", lError);
        if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
        {
-           TRACE("Key name: %p\n", szKeyName);
+           TRACE("Key name: %s\n", debugstr_w(szKeyName));
 
            if (RegOpenKeyExW(hClassesKey,
                              szKeyName,
                              0,
-                             KEY_ALL_ACCESS,
+                             KEY_QUERY_VALUE,
                              &hClassKey))
            {
                RegCloseKey(hClassesKey);
@@ -230,14 +236,14 @@ BOOL WINAPI SetupDiBuildClassInfoListExW(
 
            RegCloseKey(hClassKey);
 
-           TRACE("Guid: %p\n", szKeyName);
+           TRACE("Guid: %s\n", debugstr_w(szKeyName));
            if (dwGuidListIndex < ClassGuidListSize)
            {
                if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
                {
                    szKeyName[37] = 0;
                }
-               TRACE("Guid: %p\n", &szKeyName[1]);
+               TRACE("Guid: %s\n", debugstr_w(&szKeyName[1]));
 
                UuidFromStringW(&szKeyName[1],
                                &ClassGuidList[dwGuidListIndex]);
@@ -355,6 +361,9 @@ BOOL WINAPI SetupDiClassGuidsFromNameExW(
     LONG lError;
     DWORD dwGuidListIndex = 0;
 
+    TRACE("%s %p %lu %p %s %p\n", debugstr_w(ClassName), ClassGuidList,
+        ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved);
+
     if (RequiredSize != NULL)
        *RequiredSize = 0;
 
@@ -382,7 +391,7 @@ BOOL WINAPI SetupDiClassGuidsFromNameExW(
        TRACE("RegEnumKeyExW() returns %ld\n", lError);
        if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
        {
-           TRACE("Key name: %p\n", szKeyName);
+           TRACE("Key name: %s\n", debugstr_w(szKeyName));
 
            if (RegOpenKeyExW(hClassesKey,
                              szKeyName,
@@ -402,20 +411,20 @@ BOOL WINAPI SetupDiClassGuidsFromNameExW(
                                  (LPBYTE)szClassName,
                                  &dwLength))
            {
-               TRACE("Class name: %p\n", szClassName);
+               TRACE("Class name: %s\n", debugstr_w(szClassName));
 
                if (strcmpiW(szClassName, ClassName) == 0)
                {
                    TRACE("Found matching class name\n");
 
-                   TRACE("Guid: %p\n", szKeyName);
+                   TRACE("Guid: %s\n", debugstr_w(szKeyName));
                    if (dwGuidListIndex < ClassGuidListSize)
                    {
                        if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
                        {
                            szKeyName[37] = 0;
                        }
-                       TRACE("Guid: %p\n", &szKeyName[1]);
+                       TRACE("Guid: %s\n", debugstr_w(&szKeyName[1]));
 
                        UuidFromStringW(&szKeyName[1],
                                        &ClassGuidList[dwGuidListIndex]);
@@ -520,6 +529,9 @@ BOOL WINAPI SetupDiClassNameFromGuidExW(
     DWORD dwLength;
     LONG rc;
 
+    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,
@@ -590,7 +602,8 @@ SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
     LPWSTR MachineNameW = NULL;
     HDEVINFO hDevInfo;
 
-    TRACE("%p %p %s %p\n", ClassGuid, hwndParent, MachineName, Reserved);
+    TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
+      debugstr_a(MachineName), Reserved);
 
     if (MachineName)
     {
@@ -608,6 +621,22 @@ SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
     return hDevInfo;
 }
 
+static DWORD
+GetErrorCodeFromCrCode(const IN CONFIGRET cr)
+{
+  switch (cr)
+  {
+    case CR_INVALID_MACHINENAME: return ERROR_INVALID_COMPUTERNAME;
+    case CR_OUT_OF_MEMORY: return ERROR_NOT_ENOUGH_MEMORY;
+    case CR_SUCCESS: return ERROR_SUCCESS;
+    default:
+      /* FIXME */
+      return ERROR_GEN_FAILURE;
+  }
+  
+  /* Does not happen */
+}
+
 /***********************************************************************
  *             SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
  */
@@ -618,15 +647,23 @@ SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
                               PVOID Reserved)
 {
   struct DeviceInfoSet *list;
+  LPWSTR UNCServerName = NULL;
+  DWORD size;
   DWORD rc;
+  //CONFIGRET cr;
+  HDEVINFO ret = (HDEVINFO)INVALID_HANDLE_VALUE;;
 
-  TRACE("%p %p %S %p\n", ClassGuid, hwndParent, MachineName, Reserved);
+  TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
+      debugstr_w(MachineName), Reserved);
 
-  list = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInfoSet));
+  size = sizeof(struct DeviceInfoSet);
+  if (MachineName)
+    size += (wcslen(MachineName) + 3) * sizeof(WCHAR);
+  list = HeapAlloc(GetProcessHeap(), 0, size);
   if (!list)
   {
     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-    return (HDEVINFO)INVALID_HANDLE_VALUE;
+    goto cleanup;
   }
   memset(list, 0, sizeof(struct DeviceInfoSet));
 
@@ -644,17 +681,57 @@ SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
     if (rc != ERROR_SUCCESS)
     {
       SetLastError(rc);
-      HeapFree(GetProcessHeap(), 0, list);
-      return (HDEVINFO)INVALID_HANDLE_VALUE;
+      goto cleanup;
     }
+    UNCServerName = HeapAlloc(GetProcessHeap(), 0, (strlenW(MachineName) + 3) * sizeof(WCHAR));
+    if (!UNCServerName)
+    {
+      SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+      goto cleanup;
+    }
+    
+    strcpyW(UNCServerName + 2, MachineName);
+    list->szData[0] = list->szData[1] = '\\';
+    strcpyW(list->szData + 2, MachineName);
+    list->MachineName = list->szData;
   }
   else
   {
+    DWORD Size = MAX_PATH;
     list->HKLM = HKEY_LOCAL_MACHINE;
+    UNCServerName = HeapAlloc(GetProcessHeap(), 0, (MAX_PATH + 2) * sizeof(WCHAR));
+    if (!UNCServerName)
+    {
+      SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+      goto cleanup;
+    }
+    if (!GetComputerNameW(UNCServerName + 2, &Size))
+      goto cleanup;
+    list->MachineName = NULL;
   }
+#if 0
+  UNCServerName[0] = UNCServerName[1] = '\\';
+  cr = CM_Connect_MachineW(UNCServerName, &list->hMachine);
+  if (cr != CR_SUCCESS)
+  {
+    SetLastError(GetErrorCodeFromCrCode(cr));
+    goto cleanup;
+  }
+#endif
   InitializeListHead(&list->DriverListHead);
   InitializeListHead(&list->ListHead);
-  return (HDEVINFO)list;
+
+  ret = (HDEVINFO)list;
+
+cleanup:
+  if (ret == INVALID_HANDLE_VALUE)
+  {
+    if (list && list->HKLM != 0 && list->HKLM != HKEY_LOCAL_MACHINE)
+      RegCloseKey(list->HKLM);
+    HeapFree(GetProcessHeap(), 0, list);
+  }
+  HeapFree(GetProcessHeap(), 0, UNCServerName);
+  return ret;
 }
 
 /***********************************************************************
@@ -691,12 +768,7 @@ BOOL WINAPI SetupDiEnumDeviceInfo(
                 memcpy(&DeviceInfoData->ClassGuid,
                     &DevInfo->ClassGuid,
                     sizeof(GUID));
-                DeviceInfoData->DevInst = 0; /* FIXME */
-                /* Note: this appears to be dangerous, passing a private
-                 * pointer a heap-allocated datum to the caller.  However, the
-                 * expected lifetime of the device data is the same as the
-                 * HDEVINFO; once that is closed, the data are no longer valid.
-                 */
+                DeviceInfoData->DevInst = DevInfo->dnDevInst;
                 DeviceInfoData->Reserved = (ULONG_PTR)DevInfo;
                 ret = TRUE;
             }
@@ -777,6 +849,9 @@ BOOL WINAPI SetupDiGetActualSectionToInstallW(
     DWORD dwFullLength;
     LONG lLineCount = -1;
 
+    TRACE("%p %s %p %lu %p %p\n", InfHandle, debugstr_w(InfSectionName),
+        InfSectionWithExt, InfSectionWithExtSize, RequiredSize, Extension);
+
     lstrcpyW(szBuffer, InfSectionName);
     dwLength = lstrlenW(szBuffer);
 
@@ -937,8 +1012,11 @@ BOOL WINAPI SetupDiGetClassDescriptionExW(
     HKEY hKey;
     DWORD dwLength;
 
+    TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassDescription,
+        ClassDescriptionSize, RequiredSize, debugstr_w(MachineName), Reserved);
+
     hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
-                                     KEY_ALL_ACCESS,
+                                     KEY_QUERY_VALUE,
                                      DIOCR_INSTALLER,
                                      MachineName,
                                      Reserved);
@@ -1056,11 +1134,13 @@ end:
 
 static BOOL
 CreateDeviceInfoElement(
+    IN struct DeviceInfoSet *list,
     IN LPCWSTR InstancePath,
     IN LPCGUID pClassGuid,
     OUT struct DeviceInfoElement **pDeviceInfo)
 {
     DWORD size;
+    CONFIGRET cr;
     struct DeviceInfoElement *deviceInfo;
 
     *pDeviceInfo = NULL;
@@ -1073,6 +1153,14 @@ CreateDeviceInfoElement(
         return FALSE;
     }
     memset(deviceInfo, 0, size);
+
+    cr = CM_Locate_DevNode_ExW(&deviceInfo->dnDevInst, (DEVINSTID_W)InstancePath, CM_LOCATE_DEVNODE_PHANTOM, list->hMachine);
+    if (cr != CR_SUCCESS)
+    {
+        SetLastError(GetErrorCodeFromCrCode(cr));
+        return FALSE;
+    }
+
     deviceInfo->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
     wcscpy(deviceInfo->Data, InstancePath);
     deviceInfo->DeviceName = deviceInfo->Data;
@@ -1185,6 +1273,8 @@ static LONG SETUP_CreateDevListFromEnumerator(
                 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)
             {
@@ -1196,13 +1286,14 @@ static LONG SETUP_CreateDevListFromEnumerator(
                 RegCloseKey(hDeviceIdKey);
                 return ERROR_GEN_FAILURE;
             }
-
-            KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */
-            if (UuidFromStringW(&KeyBuffer[1], &KeyGuid) != RPC_S_OK)
+            else
             {
-                RegCloseKey(hDeviceIdKey);
-                return GetLastError();
+                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 */
@@ -1210,7 +1301,7 @@ static LONG SETUP_CreateDevListFromEnumerator(
             }
 
             /* Add the entry to the list */
-            if (!CreateDeviceInfoElement(InstancePath, &KeyGuid, &deviceInfo))
+            if (!CreateDeviceInfoElement(list, InstancePath, &KeyGuid, &deviceInfo))
             {
                 RegCloseKey(hDeviceIdKey);
                 return GetLastError();
@@ -1236,7 +1327,7 @@ static LONG SETUP_CreateDevList(
     DWORD dwLength;
     DWORD rc;
 
-    if (IsEqualIID(class, &GUID_NULL))
+    if (class && IsEqualIID(class, &GUID_NULL))
         class = NULL;
 
     /* Open Enum key */
@@ -1259,7 +1350,7 @@ static LONG SETUP_CreateDevList(
         return rc;
 
     /* If enumerator is provided, call directly SETUP_CreateDevListFromEnumerator.
-     * Else, enumerate all enumerators all call SETUP_CreateDevListFromEnumerator
+     * Else, enumerate all enumerators and call SETUP_CreateDevListFromEnumerator
      * for each one.
      */
     if (Enumerator)
@@ -1369,7 +1460,7 @@ static LONG SETUP_CreateSerialDeviceList(
             struct DeviceInterface *interfaceInfo;
             TRACE("Adding %s to list\n", debugstr_w(ptr));
             /* Step 1. Create a device info element */
-            if (!CreateDeviceInfoElement(ptr, &GUID_SERENUM_BUS_ENUMERATOR, &deviceInfo))
+            if (!CreateDeviceInfoElement(list, ptr, &GUID_SERENUM_BUS_ENUMERATOR, &deviceInfo))
             {
                 if (devices != buf)
                     HeapFree(GetProcessHeap(), 0, devices);
@@ -1593,7 +1684,7 @@ static LONG SETUP_CreateInterfaceList(
 
             /* We have found a device */
             /* Step 1. Create a device info element */
-            if (!CreateDeviceInfoElement(InstancePath, &ClassGuid, &deviceInfo))
+            if (!CreateDeviceInfoElement(list, InstancePath, &ClassGuid, &deviceInfo))
             {
                 RegCloseKey(hReferenceKey);
                 RegCloseKey(hDeviceInstanceKey);
@@ -1803,11 +1894,6 @@ BOOL WINAPI SetupDiEnumDeviceInterfaces(
                             &DevItf->InterfaceClassGuid,
                             sizeof(GUID));
                         DeviceInterfaceData->Flags = 0; /* FIXME */
-                        /* Note: this appears to be dangerous, passing a private
-                         * pointer a heap-allocated datum to the caller.  However, the
-                         * expected lifetime of the device data is the same as the
-                         * HDEVINFO; once that is closed, the data are no longer valid.
-                         */
                         DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
                         Found = TRUE;
                     }
@@ -1885,6 +1971,7 @@ static BOOL DestroyDeviceInfoSet(struct DeviceInfoSet* list)
     }
     if (list->HKLM != HKEY_LOCAL_MACHINE)
         RegCloseKey(list->HKLM);
+    CM_Disconnect_Machine(list->hMachine);
     HeapFree(GetProcessHeap(), 0, list);
     return TRUE;
 }
@@ -1928,7 +2015,7 @@ BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(
     DWORD sizeW = 0, sizeA;
     BOOL ret = FALSE;
 
-    TRACE("(%p, %p, %p, %ld, %p, %p)\n", DeviceInfoSet,
+    TRACE("%p %p %p %lu %p %p\n", DeviceInfoSet,
         DeviceInterfaceData, DeviceInterfaceDetailData,
         DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
 
@@ -1996,7 +2083,7 @@ BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
 {
     BOOL ret = FALSE;
 
-    TRACE("(%p, %p, %p, %ld, %p, %p): stub\n", DeviceInfoSet,
+    TRACE("%p %p %p %lu %p %p\n", DeviceInfoSet,
         DeviceInterfaceData, DeviceInterfaceDetailData,
         DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
 
@@ -2038,12 +2125,7 @@ BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
                 memcpy(&DeviceInfoData->ClassGuid,
                     &deviceInterface->DeviceInfo->ClassGuid,
                     sizeof(GUID));
-                DeviceInfoData->DevInst = 0; /* FIXME */
-                /* Note: this appears to be dangerous, passing a private
-                 * pointer a heap-allocated datum to the caller.  However, the
-                 * expected lifetime of the device data is the same as the
-                 * HDEVINFO; once that is closed, the data are no longer valid.
-                 */
+                DeviceInfoData->DevInst = deviceInterface->DeviceInfo->dnDevInst;
                 DeviceInfoData->Reserved = (ULONG_PTR)deviceInterface->DeviceInfo;
             }
             ret = TRUE;
@@ -2320,7 +2402,7 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
 
             default:
             {
-                FIXME("Property 0x%lx not implemented\n", Property);
+                ERR("Property 0x%lx not implemented\n", Property);
                 SetLastError(ERROR_NOT_SUPPORTED);
             }
         }
@@ -2469,7 +2551,7 @@ BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
 
             default:
             {
-                FIXME("Property 0x%lx not implemented\n", Property);
+                ERR("Property 0x%lx not implemented\n", Property);
                 SetLastError(ERROR_NOT_SUPPORTED);
             }
         }
@@ -2544,7 +2626,7 @@ static HKEY CreateClassKey(HINF hInf)
                            0,
                            NULL,
                            REG_OPTION_NON_VOLATILE,
-                           KEY_ALL_ACCESS,
+                           KEY_SET_VALUE,
                            NULL,
                            &hClassKey,
              NULL))
@@ -2583,6 +2665,9 @@ BOOL WINAPI SetupDiInstallClassW(
     BOOL bFileQueueCreated = FALSE;
     HKEY hClassKey;
 
+    TRACE("%p %s 0x%lx %p\n", hwndParent, debugstr_w(InfFileName),
+        Flags, FileQueue);
+
     FIXME("not fully implemented\n");
 
     if ((Flags & DI_NOVCP) && (FileQueue == NULL || FileQueue == INVALID_HANDLE_VALUE))
@@ -2728,6 +2813,9 @@ HKEY WINAPI SetupDiOpenClassRegKeyExW(
     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 = ControlClass;
@@ -2739,7 +2827,7 @@ HKEY WINAPI SetupDiOpenClassRegKeyExW(
     else
     {
         ERR("Invalid Flags parameter!\n");
-        SetLastError(ERROR_INVALID_PARAMETER);
+        SetLastError(ERROR_INVALID_FLAGS);
         return INVALID_HANDLE_VALUE;
     }
 
@@ -2758,7 +2846,7 @@ HKEY WINAPI SetupDiOpenClassRegKeyExW(
     rc = RegOpenKeyExW(HKLM,
                      lpKeyName,
                      0,
-                     KEY_ALL_ACCESS,
+                     ClassGuid ? KEY_ENUMERATE_SUB_KEYS : samDesired,
                      &hClassesKey);
     if (MachineName != NULL) RegCloseKey(HKLM);
     if (rc != ERROR_SUCCESS)
@@ -2794,7 +2882,7 @@ HKEY WINAPI SetupDiOpenClassRegKeyExW(
     rc = RegOpenKeyExW(hClassesKey,
                      lpFullGuidString,
                      0,
-                     KEY_ALL_ACCESS,
+                     samDesired,
                      &hClassKey);
     if (rc != ERROR_SUCCESS)
     {
@@ -2864,6 +2952,20 @@ BOOL WINAPI SetupDiSetClassInstallParamsA(
     return FALSE;
 }
 
+/***********************************************************************
+ *             SetupDiSetClassInstallParamsW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupDiSetClassInstallParamsW(
+       HDEVINFO  DeviceInfoSet,
+       PSP_DEVINFO_DATA DeviceInfoData,
+       PSP_CLASSINSTALL_HEADER ClassInstallParams,
+       DWORD ClassInstallParamsSize)
+{
+    FIXME("%p %p %x %lu\n",DeviceInfoSet, DeviceInfoData,
+          ClassInstallParams->InstallFunction, ClassInstallParamsSize);
+    return FALSE;
+}
+
 static DWORD
 GetFunctionPointer(
         IN PWSTR InstallerName,
@@ -2948,7 +3050,7 @@ BOOL WINAPI SetupDiCallClassInstaller(
 {
     BOOL ret = FALSE;
 
-    TRACE("%ld %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
+    TRACE("%u %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
 
     if (!DeviceInfoSet)
         SetLastError(ERROR_INVALID_PARAMETER);
@@ -3007,8 +3109,8 @@ BOOL WINAPI SetupDiCallClassInstaller(
                 DefaultHandler = SetupDiSelectBestCompatDrv;
                 break;
             default:
-                FIXME("Install function %ld not implemented\n", InstallFunction);
-                SetLastError(ERROR_INVALID_PARAMETER);
+                ERR("Install function %u not supported\n", InstallFunction);
+                SetLastError(ERROR_NOT_SUPPORTED);
         }
 
         InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
@@ -3248,6 +3350,45 @@ BOOL WINAPI SetupDiCallClassInstaller(
     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.@)
  */
@@ -3370,6 +3511,291 @@ BOOL WINAPI SetupDiSetDeviceInstallParamsW(
     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 = (wcslen(DevInfo->DeviceName) + 1) * sizeof(WCHAR);
+        if (RequiredSize)
+            *RequiredSize = required;
+
+        if (required <= DeviceInstanceIdSize)
+        {
+            wcscpy(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, L"EnumPropPages32", 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, L"EnumPropPages32", 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(rc);
+            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.@)
  */
@@ -3770,7 +4196,7 @@ BOOL WINAPI SetupDiCreateDeviceInfoW(
     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_PARAMETER);
+        SetLastError(ERROR_INVALID_FLAGS);
     }
     else
     {
@@ -3806,8 +4232,7 @@ BOOL WINAPI SetupDiCreateDeviceInfoW(
             {
                 struct DeviceInfoElement *deviceInfo;
 
-                /* FIXME: ClassGuid can be NULL */
-                if (CreateDeviceInfoElement(DeviceName, ClassGuid, &deviceInfo))
+                if (CreateDeviceInfoElement(list, DeviceName, ClassGuid, &deviceInfo))
                 {
                     InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
 
@@ -3822,7 +4247,7 @@ BOOL WINAPI SetupDiCreateDeviceInfoW(
                         else
                         {
                             memcpy(&DeviceInfoData->ClassGuid, ClassGuid, sizeof(GUID));
-                            DeviceInfoData->DevInst = 0; /* FIXME */
+                            DeviceInfoData->DevInst = deviceInfo->dnDevInst;
                             DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
                             ret = TRUE;
                         }
@@ -4103,7 +4528,6 @@ cleanup:
         HeapFree(GetProcessHeap(), 0, ProviderName);
     HeapFree(GetProcessHeap(), 0, DriverVer);
 
-    TRACE("Returning %d\n", ret);
     return ret;
 }
 
@@ -4422,7 +4846,7 @@ SetupDiBuildDriverInfoList(
                                 DriverAlreadyAdded = FALSE;
                                 for (DriverRank = 0, currentId = (LPCWSTR)HardwareIDs; !DriverAlreadyAdded && *currentId; currentId += wcslen(currentId) + 1, DriverRank++)
                                 {
-                                    if (wcscmp(DeviceId, currentId) == 0)
+                                    if (wcsicmp(DeviceId, currentId) == 0)
                                     {
                                         AddDriverToList(
                                             &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->DriverListHead,
@@ -4443,7 +4867,7 @@ SetupDiBuildDriverInfoList(
                                 {
                                     for (DriverRank = 0, currentId = (LPCWSTR)CompatibleIDs; !DriverAlreadyAdded && *currentId; currentId += wcslen(currentId) + 1, DriverRank++)
                                     {
-                                        if (wcscmp(DeviceId, currentId) == 0)
+                                        if (wcsicmp(DeviceId, currentId) == 0)
                                         {
                                             AddDriverToList(
                                                 &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->DriverListHead,
@@ -4672,7 +5096,7 @@ SetupDiOpenDeviceInfoW(
     else if (OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS))
     {
         TRACE("Unknown flags: 0x%08lx\n", OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS));
-        SetLastError(ERROR_INVALID_PARAMETER);
+        SetLastError(ERROR_INVALID_FLAGS);
     }
     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
         SetLastError(ERROR_INVALID_USER_BUFFER);
@@ -4721,12 +5145,16 @@ SetupDiOpenDeviceInfoW(
             RegCloseKey(hEnumKey);
             if (rc != ERROR_SUCCESS)
             {
+                if (rc == ERROR_FILE_NOT_FOUND)
+                    rc = ERROR_NO_SUCH_DEVINST;
                 SetLastError(rc);
                 return FALSE;
             }
 
-            /* FIXME: GUID_NULL is not allowed */
-            if (!CreateDeviceInfoElement(DeviceInstanceId, &GUID_NULL /* FIXME */, &deviceInfo))
+            /* FIXME: try to get ClassGUID from registry, instead of
+             * sending GUID_NULL to CreateDeviceInfoElement
+             */
+            if (!CreateDeviceInfoElement(list, DeviceInstanceId, &GUID_NULL, &deviceInfo))
             {
                 RegCloseKey(hKey);
                 return FALSE;
@@ -4740,7 +5168,7 @@ SetupDiOpenDeviceInfoW(
         if (ret && deviceInfo && DeviceInfoData)
         {
             memcpy(&DeviceInfoData->ClassGuid, &deviceInfo->ClassGuid, sizeof(GUID));
-            DeviceInfoData->DevInst = 0; /* FIXME */
+            DeviceInfoData->DevInst = deviceInfo->dnDevInst;
             DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
         }
     }
@@ -5529,7 +5957,7 @@ SetupDiRegisterCoDeviceInstallers(
         DWORD DoAction;
         WCHAR SectionName[MAX_PATH];
         DWORD SectionNameLength = 0;
-        HKEY hKey = INVALID_HANDLE_VALUE;;
+        HKEY hKey = INVALID_HANDLE_VALUE;
 
         InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
         Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
@@ -5877,7 +6305,17 @@ SetupDiInstallDevice(
             NULL, 0,
             &RequiredSize);
         if (!Result)
-            goto nextfile;
+        {
+            if (GetLastError() == ERROR_INVALID_PARAMETER)
+            {
+                /* This first is probably missing. It is not
+                 * required, so ignore the error */
+                RequiredSize = 0;
+                Result = TRUE;
+            }
+            else
+                goto nextfile;
+        }
         if (RequiredSize > 0)
         {
             /* We got the needed size for the buffer */
@@ -5894,11 +6332,12 @@ SetupDiInstallDevice(
                 &RequiredSize);
             if (!Result)
                 goto nextfile;
+
+            SetLastError(ERROR_SUCCESS);
+            Result = SetupInstallServicesFromInfSectionExW(
+                SelectedDriver->InfFileDetails->hInf,
+                ServiceSection, Flags, DeviceInfoSet, DeviceInfoData, ServiceName, NULL);
         }
-        SetLastError(ERROR_SUCCESS);
-        Result = SetupInstallServicesFromInfSectionExW(
-            SelectedDriver->InfFileDetails->hInf,
-            ServiceSection, Flags, DeviceInfoSet, DeviceInfoData, ServiceName, NULL);
         if (Result && (Flags & SPSVCINST_ASSOCSERVICE))
         {
             AssociatedService = ServiceName;
@@ -5951,20 +6390,20 @@ nextfile:
 
     /* Write information to enum key */
     TRACE("Write information to enum key\n");
-    TRACE("Service         : '%S'\n", AssociatedService);
     TRACE("Class           : '%S'\n", ClassName);
     TRACE("ClassGUID       : '%S'\n", lpFullGuidString);
     TRACE("DeviceDesc      : '%S'\n", SelectedDriver->Info.Description);
     TRACE("Mfg             : '%S'\n", SelectedDriver->Info.MfgName);
-    rc = RegSetValueEx(hKey, L"Service", 0, REG_SZ, (const BYTE *)AssociatedService, (wcslen(AssociatedService) + 1) * sizeof(WCHAR));
-    if (rc == ERROR_SUCCESS)
-        rc = RegSetValueEx(hKey, L"Class", 0, REG_SZ, (const BYTE *)ClassName, (wcslen(ClassName) + 1) * sizeof(WCHAR));
+    TRACE("Service         : '%S'\n", AssociatedService);
+    rc = RegSetValueEx(hKey, L"Class", 0, REG_SZ, (const BYTE *)ClassName, (wcslen(ClassName) + 1) * sizeof(WCHAR));
     if (rc == ERROR_SUCCESS)
         rc = RegSetValueEx(hKey, L"ClassGUID", 0, REG_SZ, (const BYTE *)lpFullGuidString, (wcslen(lpFullGuidString) + 1) * sizeof(WCHAR));
     if (rc == ERROR_SUCCESS)
         rc = RegSetValueEx(hKey, L"DeviceDesc", 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (wcslen(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
     if (rc == ERROR_SUCCESS)
         rc = RegSetValueEx(hKey, L"Mfg", 0, REG_SZ, (const BYTE *)SelectedDriver->Info.MfgName, (wcslen(SelectedDriver->Info.MfgName) + 1) * sizeof(WCHAR));
+    if (rc == ERROR_SUCCESS && *AssociatedService)
+        rc = RegSetValueEx(hKey, L"Service", 0, REG_SZ, (const BYTE *)AssociatedService, (wcslen(AssociatedService) + 1) * sizeof(WCHAR));
     if (rc != ERROR_SUCCESS)
     {
        SetLastError(rc);