Fix a broken cast (thanks w3seek)
[reactos.git] / reactos / dll / win32 / setupapi / devinst.c
index 1d96ab2..1cfa7a2 100644 (file)
@@ -676,12 +676,24 @@ 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;
+    case CR_ACCESS_DENIED:        return ERROR_ACCESS_DENIED;
+    case CR_BUFFER_SMALL:         return ERROR_INSUFFICIENT_BUFFER;
+    case CR_CALL_NOT_IMPLEMENTED: return ERROR_CALL_NOT_IMPLEMENTED;
+    case CR_FAILURE:              return ERROR_GEN_FAILURE;
+    case CR_INVALID_DATA:         return ERROR_INVALID_USER_BUFFER;
+    case CR_INVALID_DEVICE_ID:    return ERROR_INVALID_PARAMETER;
+    case CR_INVALID_MACHINENAME:  return ERROR_INVALID_COMPUTERNAME;
+    case CR_INVALID_DEVNODE:      return ERROR_INVALID_PARAMETER;
+    case CR_INVALID_FLAG:         return ERROR_INVALID_FLAGS;
+    case CR_INVALID_POINTER:      return ERROR_INVALID_PARAMETER;
+    case CR_INVALID_PROPERTY:     return ERROR_INVALID_PARAMETER;
+    case CR_NO_SUCH_DEVNODE:      return ERROR_FILE_NOT_FOUND;
+    case CR_NO_SUCH_REGISTRY_KEY: return ERROR_FILE_NOT_FOUND;
+    case CR_NO_SUCH_VALUE:        return ERROR_FILE_NOT_FOUND;
+    case CR_OUT_OF_MEMORY:        return ERROR_NOT_ENOUGH_MEMORY;
+    case CR_REGISTRY_ERROR:       return ERROR_GEN_FAILURE;
+    case CR_SUCCESS:              return ERROR_SUCCESS;
+    default:                      return ERROR_GEN_FAILURE;
   }
 
   /* Does not happen */
@@ -1403,7 +1415,7 @@ CreateDeviceInterface(
     }
     deviceInterface->DeviceInfo = deviceInfo;
     strcpyW(deviceInterface->SymbolicLink, SymbolicLink);
-    deviceInterface->Flags = 0; /* FIXME */
+    deviceInterface->Flags = 0; /* Flags will be updated later */
     memcpy(&deviceInterface->InterfaceClassGuid, pInterfaceGuid, sizeof(GUID));
 
     *pDeviceInterface = deviceInterface;
@@ -1616,11 +1628,19 @@ static LONG SETUP_CreateDevList(
     }
 }
 
+static BOOL DestroyDeviceInterface(struct DeviceInterface* deviceInterface)
+{
+    HeapFree(GetProcessHeap(), 0, deviceInterface);
+    return TRUE;
+}
+
 static LONG SETUP_CreateInterfaceList(
        struct DeviceInfoSet *list,
        PCWSTR MachineName,
        LPGUID InterfaceGuid,
-       PCWSTR DeviceInstanceW /* OPTIONAL */)
+       PCWSTR DeviceInstanceW /* OPTIONAL */,
+       BOOL OnlyPresentInterfaces
+       )
 {
     HKEY hInterfaceKey;      /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
     HKEY hDeviceInstanceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath} */
@@ -1630,7 +1650,8 @@ static LONG SETUP_CreateInterfaceList(
     HKEY hKey;               /* HKLM\SYSTEM\CurrentControlSet\Enum\{Instance\Path} */
     LONG rc;
     WCHAR KeyBuffer[max(MAX_PATH, MAX_GUID_STRING_LEN) + 1];
-    PWSTR InstancePath;
+    PWSTR pSymbolicLink = NULL;
+    PWSTR InstancePath = NULL;
     DWORD i, j;
     DWORD dwLength, dwInstancePathLength;
     DWORD dwRegType;
@@ -1638,10 +1659,16 @@ static LONG SETUP_CreateInterfaceList(
     GUID ClassGuid;
     struct DeviceInfoElement *deviceInfo;
 
+    hInterfaceKey = INVALID_HANDLE_VALUE;
+    hDeviceInstanceKey = INVALID_HANDLE_VALUE;
+
     /* Open registry key related to this interface */
     hInterfaceKey = SetupDiOpenClassRegKeyExW(InterfaceGuid, KEY_ENUMERATE_SUB_KEYS, DIOCR_INTERFACE, MachineName, NULL);
     if (hInterfaceKey == INVALID_HANDLE_VALUE)
-        return GetLastError();
+    {
+        rc = GetLastError();
+        goto cleanup;
+    }
 
     /* Enumerate sub keys of hInterfaceKey */
     i = 0;
@@ -1652,49 +1679,36 @@ static LONG SETUP_CreateInterfaceList(
         if (rc == ERROR_NO_MORE_ITEMS)
             break;
         if (rc != ERROR_SUCCESS)
-        {
-            RegCloseKey(hInterfaceKey);
-            return rc;
-        }
+            goto cleanup;
         i++;
 
         /* Open sub key */
+        if (hDeviceInstanceKey != INVALID_HANDLE_VALUE)
+            RegCloseKey(hDeviceInstanceKey);
         rc = RegOpenKeyExW(hInterfaceKey, KeyBuffer, 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hDeviceInstanceKey);
         if (rc != ERROR_SUCCESS)
-        {
-            RegCloseKey(hInterfaceKey);
-            return rc;
-        }
+            goto cleanup;
 
         /* Read DeviceInstance */
         rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, &dwRegType, NULL, &dwInstancePathLength);
-        if (rc != ERROR_SUCCESS )
-        {
-            RegCloseKey(hDeviceInstanceKey);
-            RegCloseKey(hInterfaceKey);
-            return rc;
-        }
+        if (rc != ERROR_SUCCESS)
+            goto cleanup;
         if (dwRegType != REG_SZ)
         {
-            RegCloseKey(hDeviceInstanceKey);
-            RegCloseKey(hInterfaceKey);
-            return ERROR_GEN_FAILURE;
+            rc = ERROR_GEN_FAILURE;
+            goto cleanup;
         }
+        if (InstancePath != NULL)
+            HeapFree(GetProcessHeap(), 0, InstancePath);
         InstancePath = HeapAlloc(GetProcessHeap(), 0, dwInstancePathLength + sizeof(WCHAR));
         if (!InstancePath)
         {
-            RegCloseKey(hDeviceInstanceKey);
-            RegCloseKey(hInterfaceKey);
-            return ERROR_NOT_ENOUGH_MEMORY;
+            rc = ERROR_NOT_ENOUGH_MEMORY;
+            goto cleanup;
         }
         rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, NULL, (LPBYTE)InstancePath, &dwInstancePathLength);
         if (rc != ERROR_SUCCESS)
-        {
-            HeapFree(GetProcessHeap(), 0, InstancePath);
-            RegCloseKey(hDeviceInstanceKey);
-            RegCloseKey(hInterfaceKey);
-            return rc;
-        }
+            goto cleanup;
         InstancePath[dwInstancePathLength / sizeof(WCHAR)] = '\0';
         TRACE("DeviceInstance %s\n", debugstr_w(InstancePath));
 
@@ -1702,11 +1716,7 @@ static LONG SETUP_CreateInterfaceList(
         {
             /* Check if device enumerator is not the right one */
             if (strcmpW(DeviceInstanceW, InstancePath) != 0)
-            {
-                HeapFree(GetProcessHeap(), 0, InstancePath);
-                RegCloseKey(hDeviceInstanceKey);
                 continue;
-            }
         }
 
         /* Find class GUID associated to the device instance */
@@ -1717,12 +1727,7 @@ static LONG SETUP_CreateInterfaceList(
             0,
             &hEnumKey);
         if (rc != ERROR_SUCCESS)
-        {
-            HeapFree(GetProcessHeap(), 0, InstancePath);
-            RegCloseKey(hDeviceInstanceKey);
-            RegCloseKey(hInterfaceKey);
-            return rc;
-        }
+            goto cleanup;
         rc = RegOpenKeyExW(
             hEnumKey,
             InstancePath,
@@ -1731,46 +1736,29 @@ static LONG SETUP_CreateInterfaceList(
             &hKey);
         RegCloseKey(hEnumKey);
         if (rc != ERROR_SUCCESS)
-        {
-            HeapFree(GetProcessHeap(), 0, InstancePath);
-            RegCloseKey(hDeviceInstanceKey);
-            RegCloseKey(hInterfaceKey);
-            return rc;
-        }
+            goto cleanup;
         dwLength = sizeof(KeyBuffer) - sizeof(WCHAR);
         rc = RegQueryValueExW(hKey, ClassGUID, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
         RegCloseKey(hKey);
         if (rc != ERROR_SUCCESS)
-        {
-            HeapFree(GetProcessHeap(), 0, InstancePath);
-            RegCloseKey(hDeviceInstanceKey);
-            RegCloseKey(hInterfaceKey);
-            return rc;
-        }
+            goto cleanup;
         KeyBuffer[dwLength / sizeof(WCHAR)] = '\0';
         KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */
         if (UuidFromStringW(&KeyBuffer[1], &ClassGuid) != RPC_S_OK)
         {
-            HeapFree(GetProcessHeap(), 0, InstancePath);
-            RegCloseKey(hDeviceInstanceKey);
-            RegCloseKey(hInterfaceKey);
-            return ERROR_GEN_FAILURE;
+            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))
-        {
-            HeapFree(GetProcessHeap(), 0, InstancePath);
-            RegCloseKey(hDeviceInstanceKey);
             continue;
-        }
 
         /* Enumerate subkeys of hDeviceInstanceKey (ie "#ReferenceString" in IoRegisterDeviceInterface). Skip entries that don't start with '#' */
         j = 0;
         while (TRUE)
         {
-            LPWSTR pSymbolicLink;
             struct DeviceInterface *interfaceInfo;
 
             dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
@@ -1778,88 +1766,73 @@ static LONG SETUP_CreateInterfaceList(
             if (rc == ERROR_NO_MORE_ITEMS)
                 break;
             if (rc != ERROR_SUCCESS)
-            {
-                HeapFree(GetProcessHeap(), 0, InstancePath);
-                RegCloseKey(hDeviceInstanceKey);
-                RegCloseKey(hInterfaceKey);
-                return rc;
-            }
+                goto cleanup;
             j++;
             if (KeyBuffer[0] != '#')
                 /* This entry doesn't represent an interesting entry */
                 continue;
 
             /* Open sub key */
+            if (hReferenceKey != INVALID_HANDLE_VALUE)
+                RegCloseKey(hReferenceKey);
             rc = RegOpenKeyExW(hDeviceInstanceKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hReferenceKey);
             if (rc != ERROR_SUCCESS)
-            {
-                RegCloseKey(hDeviceInstanceKey);
-                RegCloseKey(hInterfaceKey);
-                return rc;
-            }
+                goto cleanup;
 
             /* Read SymbolicLink value */
             rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, &dwRegType, NULL, &dwLength);
             if (rc != ERROR_SUCCESS )
-            {
-                RegCloseKey(hReferenceKey);
-                RegCloseKey(hDeviceInstanceKey);
-                RegCloseKey(hInterfaceKey);
-                return rc;
-            }
+                goto cleanup;
             if (dwRegType != REG_SZ)
             {
-                RegCloseKey(hReferenceKey);
-                RegCloseKey(hDeviceInstanceKey);
-                RegCloseKey(hInterfaceKey);
-                return ERROR_GEN_FAILURE;
+                rc = ERROR_GEN_FAILURE;
+                goto cleanup;
             }
 
             /* We have found a device */
             /* Step 1. Create a device info element */
             if (!CreateDeviceInfoElement(list, InstancePath, &ClassGuid, &deviceInfo))
             {
-                RegCloseKey(hReferenceKey);
-                RegCloseKey(hDeviceInstanceKey);
-                RegCloseKey(hInterfaceKey);
-                return GetLastError();
+                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 */
+            if (pSymbolicLink != NULL)
+                HeapFree(GetProcessHeap(), 0, pSymbolicLink);
             pSymbolicLink = HeapAlloc(GetProcessHeap(), 0, (dwLength + 1) * sizeof(WCHAR));
             if (!pSymbolicLink)
             {
-                RegCloseKey(hReferenceKey);
-                RegCloseKey(hDeviceInstanceKey);
-                RegCloseKey(hInterfaceKey);
-                return ERROR_NOT_ENOUGH_MEMORY;
+                rc = ERROR_NOT_ENOUGH_MEMORY;
+                goto cleanup;
             }
             rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, NULL, (LPBYTE)pSymbolicLink, &dwLength);
             pSymbolicLink[dwLength / sizeof(WCHAR)] = '\0';
             RegCloseKey(hReferenceKey);
             if (rc != ERROR_SUCCESS)
-            {
-                HeapFree(GetProcessHeap(), 0, pSymbolicLink);
-                RegCloseKey(hDeviceInstanceKey);
-                RegCloseKey(hInterfaceKey);
-                return rc;
-            }
+                goto cleanup;
             if (!CreateDeviceInterface(deviceInfo, pSymbolicLink, InterfaceGuid, &interfaceInfo))
             {
-                HeapFree(GetProcessHeap(), 0, pSymbolicLink);
-                RegCloseKey(hDeviceInstanceKey);
-                RegCloseKey(hInterfaceKey);
-                return GetLastError();
+                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)
-                interfaceInfo->Flags |= SPINT_REMOVED;
+            if (rc != ERROR_SUCCESS)
+            {
+                if (OnlyPresentInterfaces)
+                {
+                    DestroyDeviceInterface(interfaceInfo);
+                    continue;
+                }
+                else
+                    interfaceInfo->Flags |= SPINT_REMOVED;
+            }
             else
             {
                 dwLength = sizeof(DWORD);
@@ -1870,13 +1843,23 @@ static LONG SETUP_CreateInterfaceList(
             }
 
             TRACE("Adding interface %s to list\n", debugstr_w(pSymbolicLink));
-            HeapFree(GetProcessHeap(), 0, pSymbolicLink);
             InsertTailList(&deviceInfo->InterfaceListHead, &interfaceInfo->ListEntry);
         }
-        RegCloseKey(hDeviceInstanceKey);
     }
-    RegCloseKey(hInterfaceKey);
-    return ERROR_SUCCESS;
+    rc = ERROR_SUCCESS;
+
+cleanup:
+    if (hReferenceKey != INVALID_HANDLE_VALUE)
+        RegCloseKey(hReferenceKey);
+    if (hDeviceInstanceKey != INVALID_HANDLE_VALUE)
+        RegCloseKey(hDeviceInstanceKey);
+    if (hInterfaceKey != INVALID_HANDLE_VALUE)
+        RegCloseKey(hInterfaceKey);
+    if (InstancePath != NULL)
+        HeapFree(GetProcessHeap(), 0, InstancePath);
+    if (pSymbolicLink != NULL)
+        HeapFree(GetProcessHeap(), 0, pSymbolicLink);
+    return rc;
 }
 
 /***********************************************************************
@@ -1925,8 +1908,6 @@ HDEVINFO WINAPI SetupDiGetClassDevsExW(
     else
         pClassGuid = &list->ClassGuid;
 
-    if (flags & DIGCF_PRESENT)
-        FIXME(": flag DIGCF_PRESENT ignored\n");
     if (flags & DIGCF_PROFILE)
         FIXME(": flag DIGCF_PROFILE ignored\n");
 
@@ -1952,7 +1933,7 @@ HDEVINFO WINAPI SetupDiGetClassDevsExW(
             return INVALID_HANDLE_VALUE;
         }
 
-        rc = SETUP_CreateInterfaceList(list, machine, (LPGUID)class, enumstr);
+        rc = SETUP_CreateInterfaceList(list, machine, (LPGUID)class, enumstr, flags & DIGCF_PRESENT);
         if (rc != ERROR_SUCCESS)
         {
             SetLastError(rc);
@@ -2153,7 +2134,7 @@ BOOL WINAPI SetupDiGetClassImageListExW(
             list->MachineName = NULL;
         }
 
-        ClassImageListData->Reserved = (DWORD)list; /* FIXME: 64 bit portability issue */
+        ClassImageListData->Reserved = (ULONG_PTR)list;
         ret = TRUE;
 
 cleanup:
@@ -2384,18 +2365,21 @@ static BOOL DestroyDeviceInfoElement(struct DeviceInfoElement* deviceInfo)
 {
     PLIST_ENTRY ListEntry;
     struct DriverInfoElement *driverInfo;
+    struct DeviceInterface *deviceInterface;
 
     while (!IsListEmpty(&deviceInfo->DriverListHead))
     {
         ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
-        driverInfo = (struct DriverInfoElement *)ListEntry;
+        driverInfo = CONTAINING_RECORD(ListEntry, struct DriverInfoElement, ListEntry);
         if (!DestroyDriverInfoElement(driverInfo))
             return FALSE;
     }
     while (!IsListEmpty(&deviceInfo->InterfaceListHead))
     {
         ListEntry = RemoveHeadList(&deviceInfo->InterfaceListHead);
-        HeapFree(GetProcessHeap(), 0, ListEntry);
+        deviceInterface = CONTAINING_RECORD(ListEntry, struct DeviceInterface, ListEntry);
+        if (!DestroyDeviceInterface(deviceInterface))
+            return FALSE;
     }
     DestroyClassInstallParams(&deviceInfo->ClassInstallParams);
     HeapFree(GetProcessHeap(), 0, deviceInfo);
@@ -5470,6 +5454,109 @@ cleanup:
     return ret;
 }
 
+static BOOL
+GetHardwareAndCompatibleIDsLists(
+    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)
+{
+    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;
+
+    Result = TRUE;
+
+done:
+    if (!Result)
+    {
+        MyFree(HardwareIDs);
+        MyFree(CompatibleIDs);
+    }
+    return Result;
+}
+
 /***********************************************************************
  *             SetupDiBuildDriverInfoList (SETUPAPI.@)
  */
@@ -5528,62 +5615,21 @@ SetupDiBuildDriverInfoList(
 
         if (DriverType == SPDIT_COMPATDRIVER)
         {
-            /* Get hardware IDs list */
-            Result = FALSE;
-            RequiredSize = 512; /* Initial buffer size */
-            SetLastError(ERROR_INSUFFICIENT_BUFFER);
-            while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
-            {
-                HeapFree(GetProcessHeap(), 0, HardwareIDs);
-                HardwareIDs = HeapAlloc(GetProcessHeap(), 0, RequiredSize);
-                if (!HardwareIDs)
-                {
-                    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-                    goto done;
-                }
-                Result = SetupDiGetDeviceRegistryPropertyW(
-                    DeviceInfoSet,
-                    DeviceInfoData,
-                    SPDRP_HARDWAREID,
-                    NULL,
-                    (PBYTE)HardwareIDs,
-                    RequiredSize,
-                    &RequiredSize);
-            }
+            /* Get hardware and compatible IDs lists */
+            Result = GetHardwareAndCompatibleIDsLists(
+                DeviceInfoSet,
+                DeviceInfoData,
+                &HardwareIDs,
+                NULL,
+                &CompatibleIDs,
+                NULL);
             if (!Result)
                 goto done;
-
-            /* Get compatible IDs list */
-            Result = FALSE;
-            RequiredSize = 512; /* Initial buffer size */
-            SetLastError(ERROR_INSUFFICIENT_BUFFER);
-            while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+            if (!HardwareIDs && !CompatibleIDs)
             {
-                HeapFree(GetProcessHeap(), 0, CompatibleIDs);
-                CompatibleIDs = HeapAlloc(GetProcessHeap(), 0, RequiredSize);
-                if (!CompatibleIDs)
-                {
-                    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-                    goto done;
-                }
-                Result = SetupDiGetDeviceRegistryPropertyW(
-                    DeviceInfoSet,
-                    DeviceInfoData,
-                    SPDRP_COMPATIBLEIDS,
-                    NULL,
-                    (PBYTE)CompatibleIDs,
-                    RequiredSize,
-                    &RequiredSize);
-                if (!Result && GetLastError() == ERROR_FILE_NOT_FOUND)
-                {
-                    /* No compatible ID for this device */
-                    HeapFree(GetProcessHeap(), 0, CompatibleIDs);
-                    CompatibleIDs = NULL;
-                    Result = TRUE;
-                }
-            }
-            if (!Result)
+                SetLastError(ERROR_FILE_NOT_FOUND);
                 goto done;
+            }
         }
 
         if (InstallParams.Flags & DI_ENUMSINGLEINF)
@@ -5906,8 +5952,8 @@ done:
 
     HeapFree(GetProcessHeap(), 0, ProviderName);
     HeapFree(GetProcessHeap(), 0, ManufacturerName);
-    HeapFree(GetProcessHeap(), 0, HardwareIDs);
-    HeapFree(GetProcessHeap(), 0, CompatibleIDs);
+    MyFree(HardwareIDs);
+    MyFree(CompatibleIDs);
     HeapFree(GetProcessHeap(), 0, FullInfFileName);
     HeapFree(GetProcessHeap(), 0, ExcludeFromSelect);
     if (currentInfFileDetails)
@@ -6862,16 +6908,88 @@ SetupDiGetDriverInfoDetailW(
     else
     {
         struct DriverInfoElement *driverInfoElement;
+        LPWSTR HardwareIDs = NULL;
+        LPWSTR CompatibleIDs = NULL;
+        LPWSTR pBuffer = NULL;
+        LPCWSTR DeviceID = NULL;
+        ULONG HardwareIDsSize, CompatibleIDsSize;
+        ULONG sizeNeeded, sizeLeft, size;
+        BOOL Result;
+
         driverInfoElement = (struct DriverInfoElement *)DriverInfoData->Reserved;
 
+        /* Get hardware and compatible IDs lists */
+        Result = GetHardwareAndCompatibleIDsLists(
+            DeviceInfoSet,
+            DeviceInfoData,
+            &HardwareIDs, &HardwareIDsSize,
+            &CompatibleIDs, &CompatibleIDsSize);
+        if (!Result)
+            goto done;
+
+        sizeNeeded = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID)
+            + HardwareIDsSize + CompatibleIDsSize;
+        if (RequiredSize)
+            *RequiredSize = sizeNeeded;
+
+        if (!DriverInfoDetailData)
+        {
+            ret = TRUE;
+            goto done;
+        }
+
         memcpy(
             DriverInfoDetailData,
             &driverInfoElement->Details,
             driverInfoElement->Details.cbSize);
-        /* FIXME: copy HardwareIDs/CompatibleIDs if buffer is big enough
-         * Don't forget to set CompatIDsOffset and CompatIDsLength fields.
-         */
-        ret = TRUE;
+        DriverInfoDetailData->CompatIDsOffset = 0;
+        DriverInfoDetailData->CompatIDsLength = 0;
+
+        sizeLeft = (DriverInfoDetailDataSize - FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID)) / sizeof(WCHAR);
+        pBuffer = DriverInfoDetailData->HardwareID;
+        /* Add as many as possible HardwareIDs in the list */
+        DeviceID = HardwareIDs;
+        while (DeviceID && *DeviceID && (size = wcslen(DeviceID)) + 1 < sizeLeft)
+        {
+            TRACE("Adding %S to list\n", DeviceID);
+            wcscpy(pBuffer, DeviceID);
+            DeviceID += size + 1;
+            pBuffer += size + 1;
+            sizeLeft -= size + 1;
+            DriverInfoDetailData->CompatIDsOffset += size + 1;
+        }
+        if (sizeLeft > 0)
+        {
+            *pBuffer = UNICODE_NULL;
+            sizeLeft--;
+            DriverInfoDetailData->CompatIDsOffset++;
+        }
+        /* Add as many as possible CompatibleIDs in the list */
+        DeviceID = CompatibleIDs;
+        while (DeviceID && *DeviceID && (size = wcslen(DeviceID)) + 1 < sizeLeft)
+        {
+            TRACE("Adding %S to list\n", DeviceID);
+            wcscpy(pBuffer, DeviceID);
+            DeviceID += size + 1;
+            pBuffer += size + 1;
+            sizeLeft -= size + 1;
+            DriverInfoDetailData->CompatIDsLength += size + 1;
+        }
+        if (sizeLeft > 0)
+        {
+            *pBuffer = UNICODE_NULL;
+            sizeLeft--;
+            DriverInfoDetailData->CompatIDsLength++;
+        }
+
+        if (sizeNeeded > DriverInfoDetailDataSize)
+            SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        else
+            ret = TRUE;
+
+done:
+        MyFree(HardwareIDs);
+        MyFree(CompatibleIDs);
     }
 
     TRACE("Returning %d\n", ret);