use a .spec file and fix the export ordinals
[reactos.git] / reactos / lib / devmgr / hwpage.c
index ce8969e..b871747 100644 (file)
 #define NDEBUG
 #include <debug.h>
 
-typedef VOID (WINAPI *PINITCOMMONCONTROLS)(VOID);
-
-typedef enum
-{
-    HWPD_STANDARDLIST = 0,
-    HWPD_LARGELIST,
-    HWPD_MAX = HWPD_LARGELIST
-} HWPAGE_DISPLAYMODE, *PHWPAGE_DISPLAYMODE;
-
 typedef struct _HWDEVINFO
 {
     struct _HWCLASSDEVINFO *ClassDevInfo;
     SP_DEVINFO_DATA DevInfoData;
+    BOOL HideDevice;
 } HWDEVINFO, *PHWDEVINFO;
 
 typedef struct _HWCLASSDEVINFO
 {
     GUID Guid;
     HDEVINFO hDevInfo;
+    INT ImageIndex;
     INT ItemCount;
     PHWDEVINFO HwDevInfo;
 } HWCLASSDEVINFO, *PHWCLASSDEVINFO;
@@ -125,119 +118,331 @@ InitializeDevicesList(IN PHARDWARE_PAGE_DATA hpd)
 }
 
 
+static BOOL
+DisplaySelectedDeviceProperties(IN PHARDWARE_PAGE_DATA hpd)
+{
+    PHWDEVINFO HwDevInfo;
+    SP_DEVINFO_DATA DevInfoData;
+    BOOL Ret = FALSE;
+
+    HwDevInfo = (PHWDEVINFO)ListViewGetSelectedItemData(hpd->hWndDevList);
+    if (HwDevInfo != NULL)
+    {
+        /* make a copy of the SP_DEVINFO_DATA structure on the stack, it may
+           become invalid in case the devices are updated */
+        DevInfoData = HwDevInfo->DevInfoData;
+
+        /* display the advanced properties */
+        Ret = DisplayDeviceAdvancedProperties(hpd->hWnd,
+                                              NULL,
+                                              HwDevInfo->ClassDevInfo->hDevInfo,
+                                              &DevInfoData,
+                                              hpd->hComCtl32,
+                                              NULL,
+                                              0) != -1;
+    }
+
+    return Ret;
+}
+
+
 static VOID
 UpdateControlStates(IN PHARDWARE_PAGE_DATA hpd)
 {
     PHWDEVINFO HwDevInfo;
+    HWND hBtnTroubleShoot, hBtnProperties;
+    
+    hBtnTroubleShoot = GetDlgItem(hpd->hWnd,
+                                  IDC_TROUBLESHOOT);
+    hBtnProperties = GetDlgItem(hpd->hWnd,
+                                IDC_PROPERTIES);
 
     HwDevInfo = (PHWDEVINFO)ListViewGetSelectedItemData(hpd->hWndDevList);
     if (HwDevInfo != NULL)
     {
-        /* FIXME - update static controls and enable buttons */
+        /* update static controls */
+        WCHAR szBuffer[256];
+        LPWSTR szFormatted = NULL;
+
+        /* get the manufacturer string */
+        if (GetDeviceManufacturerString(HwDevInfo->ClassDevInfo->hDevInfo,
+                                        &HwDevInfo->DevInfoData,
+                                        szBuffer,
+                                        sizeof(szBuffer) / sizeof(szBuffer[0])) &&
+            LoadAndFormatString(hDllInstance,
+                                IDS_MANUFACTURER,
+                                &szFormatted,
+                                szBuffer) != 0)
+        {
+            SetDlgItemText(hpd->hWnd,
+                           IDC_MANUFACTURER,
+                           szFormatted);
+            LocalFree((HLOCAL)szFormatted);
+        }
+
+        /* get the location string */
+        if (GetDeviceLocationString(HwDevInfo->DevInfoData.DevInst,
+                                    0,
+                                    szBuffer,
+                                    sizeof(szBuffer) / sizeof(szBuffer[0])) &&
+            LoadAndFormatString(hDllInstance,
+                                IDS_LOCATION,
+                                &szFormatted,
+                                szBuffer) != 0)
+        {
+            SetDlgItemText(hpd->hWnd,
+                           IDC_LOCATION,
+                           szFormatted);
+            LocalFree((HLOCAL)szFormatted);
+        }
+
+        if (GetDeviceStatusString(HwDevInfo->DevInfoData.DevInst,
+                                  NULL,
+                                  szBuffer,
+                                  sizeof(szBuffer) / sizeof(szBuffer[0])) &&
+            LoadAndFormatString(hDllInstance,
+                                IDS_STATUS,
+                                &szFormatted,
+                                szBuffer) != 0)
+        {
+            SetDlgItemText(hpd->hWnd,
+                           IDC_STATUS,
+                           szFormatted);
+            LocalFree((HLOCAL)szFormatted);
+        }
     }
     else
     {
-        /* FIXME - clear static controls and disable buttons */
+        /* clear static controls */
+        SetDlgItemText(hpd->hWnd,
+                       IDC_MANUFACTURER,
+                       NULL);
+        SetDlgItemText(hpd->hWnd,
+                       IDC_LOCATION,
+                       NULL);
+        SetDlgItemText(hpd->hWnd,
+                       IDC_STATUS,
+                       NULL);
+    }
+
+    EnableWindow(hBtnTroubleShoot,
+                 HwDevInfo != NULL);
+    EnableWindow(hBtnProperties,
+                 HwDevInfo != NULL);
+}
+
+
+static VOID
+FreeDevicesList(IN PHARDWARE_PAGE_DATA hpd)
+{
+    PHWCLASSDEVINFO ClassDevInfo, LastClassDevInfo;
+
+    ClassDevInfo = hpd->ClassDevInfo;
+    LastClassDevInfo = ClassDevInfo + hpd->NumberOfGuids;
+
+    /* free the device info set handles and structures */
+    while (ClassDevInfo != LastClassDevInfo)
+    {
+        if (ClassDevInfo->hDevInfo != INVALID_HANDLE_VALUE)
+        {
+            SetupDiDestroyDeviceInfoList(ClassDevInfo->hDevInfo);
+            ClassDevInfo->hDevInfo = INVALID_HANDLE_VALUE;
+        }
+
+        ClassDevInfo->ItemCount = 0;
+        ClassDevInfo->ImageIndex = 0;
+
+        if (ClassDevInfo->HwDevInfo != NULL)
+        {
+            HeapFree(GetProcessHeap(),
+                     0,
+                     ClassDevInfo->HwDevInfo);
+            ClassDevInfo->HwDevInfo = NULL;
+        }
+
+        ClassDevInfo++;
     }
 }
 
 
 static VOID
-FillDevicesList(IN PHARDWARE_PAGE_DATA hpd)
+BuildDevicesList(IN PHARDWARE_PAGE_DATA hpd)
 {
-    PHWCLASSDEVINFO DevInfo, LastDevInfo;
+    PHWCLASSDEVINFO ClassDevInfo, LastClassDevInfo;
     SP_DEVINFO_DATA DevInfoData;
-    WCHAR szBuffer[255];
-    INT ItemCount = 0;
 
     DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
 
-    DevInfo = hpd->ClassDevInfo;
-    LastDevInfo = DevInfo + hpd->NumberOfGuids;
+    ClassDevInfo = hpd->ClassDevInfo;
+    LastClassDevInfo = ClassDevInfo + hpd->NumberOfGuids;
 
-    while (DevInfo != LastDevInfo)
+    while (ClassDevInfo != LastClassDevInfo)
     {
-        INT ImageIndex = -1;
-
-        DevInfo->hDevInfo = SetupDiGetClassDevs(&DevInfo->Guid,
-                                                NULL,
-                                                hpd->hWnd,
-                                                DIGCF_PRESENT);
-        if (DevInfo->hDevInfo != INVALID_HANDLE_VALUE)
+        ClassDevInfo->ImageIndex = -1;
+
+        /* open a class device handle for the GUID we're processing */
+        ClassDevInfo->hDevInfo = SetupDiGetClassDevs(&ClassDevInfo->Guid,
+                                                     NULL,
+                                                     hpd->hWnd,
+                                                     DIGCF_PRESENT | DIGCF_PROFILE);
+        if (ClassDevInfo->hDevInfo != INVALID_HANDLE_VALUE)
         {
-            LVITEM li;
             DWORD MemberIndex = 0;
 
             SetupDiGetClassImageIndex(&hpd->ClassImageListData,
-                                      &DevInfo->Guid,
-                                      &ImageIndex);
+                                      &ClassDevInfo->Guid,
+                                      &ClassDevInfo->ImageIndex);
 
-            while (SetupDiEnumDeviceInfo(DevInfo->hDevInfo,
+            /* enumerate all devices in the class */
+            while (SetupDiEnumDeviceInfo(ClassDevInfo->hDevInfo,
                                          MemberIndex++,
                                          &DevInfoData))
             {
-                DWORD RegDataType;
-                INT iItem;
+                BOOL HideDevice = FALSE;
 
-                if (DevInfo->HwDevInfo != NULL)
+                if (ClassDevInfo->HwDevInfo != NULL)
                 {
                     PHWDEVINFO HwNewDevInfo = HeapReAlloc(GetProcessHeap(),
                                                           0,
-                                                          DevInfo->HwDevInfo,
-                                                          (DevInfo->ItemCount + 1) *
+                                                          ClassDevInfo->HwDevInfo,
+                                                          (ClassDevInfo->ItemCount + 1) *
                                                               sizeof(HWDEVINFO));
                     if (HwNewDevInfo != NULL)
                     {
-                        DevInfo->HwDevInfo = HwNewDevInfo;
+                        ClassDevInfo->HwDevInfo = HwNewDevInfo;
                     }
                     else
                     {
                         DPRINT1("Unable to allocate memory for %d SP_DEVINFO_DATA structures!\n",
-                                DevInfo->ItemCount + 1);
+                                ClassDevInfo->ItemCount + 1);
                         break;
                     }
                 }
                 else
                 {
-                    DevInfo->HwDevInfo = HeapAlloc(GetProcessHeap(),
-                                                   0,
-                                                   sizeof(HWDEVINFO));
-                    if (DevInfo->HwDevInfo == NULL)
+                    ClassDevInfo->HwDevInfo = HeapAlloc(GetProcessHeap(),
+                                                        0,
+                                                        sizeof(HWDEVINFO));
+                    if (ClassDevInfo->HwDevInfo == NULL)
                     {
                         DPRINT1("Unable to allocate memory for a SP_DEVINFO_DATA structures!\n");
                         break;
                     }
                 }
 
-                DevInfo->HwDevInfo[DevInfo->ItemCount].ClassDevInfo = DevInfo;
-                DevInfo->HwDevInfo[DevInfo->ItemCount++].DevInfoData = DevInfoData;
-
-                if ((SetupDiGetDeviceRegistryProperty(DevInfo->hDevInfo,
-                                                      &DevInfoData,
-                                                      SPDRP_FRIENDLYNAME,
-                                                      &RegDataType,
-                                                      (PBYTE)szBuffer,
-                                                      sizeof(szBuffer),
-                                                      NULL) ||
-                     SetupDiGetDeviceRegistryProperty(DevInfo->hDevInfo,
-                                                      &DevInfoData,
-                                                      SPDRP_DEVICEDESC,
-                                                      &RegDataType,
-                                                      (PBYTE)szBuffer,
-                                                      sizeof(szBuffer),
-                                                      NULL)) &&
-                    RegDataType == REG_SZ)
+                /* Find out if the device should be hidden by default */
+                IsDeviceHidden(DevInfoData.DevInst,
+                               NULL,
+                               &HideDevice);
+
+                /* save all information for the current device */
+                ClassDevInfo->HwDevInfo[ClassDevInfo->ItemCount].ClassDevInfo = ClassDevInfo;
+                ClassDevInfo->HwDevInfo[ClassDevInfo->ItemCount].DevInfoData = DevInfoData;
+                ClassDevInfo->HwDevInfo[ClassDevInfo->ItemCount++].HideDevice = HideDevice;
+            }
+        }
+
+        ClassDevInfo++;
+    }
+}
+
+
+static BOOL
+DeviceIdMatch(IN HDEVINFO DeviceInfoSet,
+              IN PSP_DEVINFO_DATA DeviceInfoData,
+              IN LPCWSTR lpDeviceId)
+{
+    DWORD DevIdLen;
+    LPWSTR lpQueriedDeviceId;
+    BOOL Ret = FALSE;
+
+    if (!SetupDiGetDeviceInstanceId(DeviceInfoSet,
+                                    DeviceInfoData,
+                                    NULL,
+                                    0,
+                                    &DevIdLen) &&
+        GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+    {
+        if (DevIdLen == wcslen(lpDeviceId) + 1)
+        {
+            lpQueriedDeviceId = HeapAlloc(GetProcessHeap(),
+                                          0,
+                                          DevIdLen * sizeof(WCHAR));
+            if (lpQueriedDeviceId != NULL)
+            {
+                if (SetupDiGetDeviceInstanceId(DeviceInfoSet,
+                                               DeviceInfoData,
+                                               lpQueriedDeviceId,
+                                               DevIdLen,
+                                               NULL))
                 {
-                    /* FIXME - check string for NULL termination! */
+                    Ret = (wcscmp(lpDeviceId,
+                                  lpQueriedDeviceId) == 0);
+                }
+
+                HeapFree(GetProcessHeap(),
+                         0,
+                         lpQueriedDeviceId);
+            }
+        }
+    }
+
+    return Ret;
+}
+
+
+static VOID
+FillDevicesListViewControl(IN PHARDWARE_PAGE_DATA hpd,
+                           IN LPCWSTR lpSelectDeviceId  OPTIONAL,
+                           IN GUID *SelectedClassGuid  OPTIONAL)
+{
+    PHWCLASSDEVINFO ClassDevInfo, LastClassDevInfo;
+    PHWDEVINFO HwDevInfo, LastHwDevInfo;
+    WCHAR szBuffer[255];
+    BOOL SelectedInClass;
+    INT ItemCount = 0;
+
+    BuildDevicesList(hpd);
+
+    ClassDevInfo = hpd->ClassDevInfo;
+    LastClassDevInfo = ClassDevInfo + hpd->NumberOfGuids;
+
+    while (ClassDevInfo != LastClassDevInfo)
+    {
+        if (ClassDevInfo->HwDevInfo != NULL)
+        {
+            HwDevInfo = ClassDevInfo->HwDevInfo;
+            LastHwDevInfo = HwDevInfo + ClassDevInfo->ItemCount;
 
+            SelectedInClass = (SelectedClassGuid != NULL &&
+                               IsEqualGUID(SelectedClassGuid,
+                                           &ClassDevInfo->Guid));
+            while (HwDevInfo != LastHwDevInfo)
+            {
+                INT iItem;
+                LVITEM li = {0};
+
+                /* get the device name */
+                if (!HwDevInfo->HideDevice &&
+                    GetDeviceDescriptionString(ClassDevInfo->hDevInfo,
+                                               &HwDevInfo->DevInfoData,
+                                               szBuffer,
+                                               sizeof(szBuffer) / sizeof(szBuffer[0])))
+                {
                     li.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT | LVIF_IMAGE;
                     li.iItem = ItemCount;
-                    li.iSubItem = 0;
-                    li.state = (ItemCount == 0 ? LVIS_SELECTED : 0);
+                    if ((ItemCount == 0 && lpSelectDeviceId == NULL) ||
+                        (SelectedInClass &&
+                         DeviceIdMatch(ClassDevInfo->hDevInfo,
+                                       &HwDevInfo->DevInfoData,
+                                       lpSelectDeviceId)))
+                    {
+                        li.state = LVIS_SELECTED;
+                    }
                     li.stateMask = LVIS_SELECTED;
                     li.pszText = szBuffer;
-                    li.iImage = ImageIndex;
-                    li.lParam = (LPARAM)&DevInfo->HwDevInfo[DevInfo->ItemCount - 1];
+                    li.iImage = ClassDevInfo->ImageIndex;
+                    li.lParam = (LPARAM)HwDevInfo;
 
                     iItem = ListView_InsertItem(hpd->hWndDevList,
                                                 &li);
@@ -245,24 +450,26 @@ FillDevicesList(IN PHARDWARE_PAGE_DATA hpd)
                     {
                         ItemCount++;
 
-                        if (SetupDiGetClassDescription(&DevInfo->Guid,
-                                                       szBuffer,
-                                                       sizeof(szBuffer) / sizeof(szBuffer[0]),
-                                                       NULL))
+                        /* get the device type for the second column */
+                        if (GetDeviceTypeString(&HwDevInfo->DevInfoData,
+                                                szBuffer,
+                                                sizeof(szBuffer) / sizeof(szBuffer[0])))
                         {
                             li.mask = LVIF_TEXT;
                             li.iItem = iItem;
                             li.iSubItem = 1;
 
                             ListView_SetItem(hpd->hWndDevList,
-                                             &li);                  
+                                             &li);
                         }
                     }
                 }
+
+                HwDevInfo++;
             }
         }
 
-        DevInfo++;
+        ClassDevInfo++;
     }
 
     /* update the controls */
@@ -270,6 +477,67 @@ FillDevicesList(IN PHARDWARE_PAGE_DATA hpd)
 }
 
 
+static VOID
+UpdateDevicesListViewControl(IN PHARDWARE_PAGE_DATA hpd)
+{
+    PHWDEVINFO HwDevInfo;
+    GUID SelectedClassGuid = {0};
+    LPWSTR lpDeviceId = NULL;
+
+    /* if a device currently is selected, remember the device id so we can
+       select the device after the update if still present */
+    HwDevInfo = (PHWDEVINFO)ListViewGetSelectedItemData(hpd->hWndDevList);
+    if (HwDevInfo != NULL)
+    {
+        DWORD DevIdLen;
+        if (!SetupDiGetDeviceInstanceId(HwDevInfo->ClassDevInfo->hDevInfo,
+                                        &HwDevInfo->DevInfoData,
+                                        NULL,
+                                        0,
+                                        &DevIdLen) &&
+            GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+        {
+            SelectedClassGuid = HwDevInfo->DevInfoData.ClassGuid;
+            lpDeviceId = HeapAlloc(GetProcessHeap(),
+                                   0,
+                                   DevIdLen * sizeof(WCHAR));
+            if (lpDeviceId != NULL &&
+                !SetupDiGetDeviceInstanceId(HwDevInfo->ClassDevInfo->hDevInfo,
+                                            &HwDevInfo->DevInfoData,
+                                            lpDeviceId,
+                                            DevIdLen,
+                                            NULL))
+            {
+                HeapFree(GetProcessHeap(),
+                         0,
+                         lpDeviceId);
+                lpDeviceId = NULL;
+            }
+        }
+    }
+
+    /* clear the devices list view control */
+    ListView_DeleteAllItems(hpd->hWndDevList);
+
+    /* free the device list */
+    FreeDevicesList(hpd);
+
+    /* build rebuild the device list and fill the list box again */
+    FillDevicesListViewControl(hpd,
+                               lpDeviceId,
+                               (lpDeviceId != NULL ?
+                                    &SelectedClassGuid :
+                                    NULL));
+
+    if (lpDeviceId != NULL)
+    {
+        HeapFree(GetProcessHeap(),
+                 0,
+                 lpDeviceId);
+    }
+}
+
+
 static LRESULT
 CALLBACK
 ParentSubWndProc(IN HWND hwnd,
@@ -294,6 +562,16 @@ ParentSubWndProc(IN HWND hwnd,
                          HIWORD(lParam),
                          SWP_NOZORDER);
         }
+        else if (uMsg == WM_DEVICECHANGE && IsWindowVisible(hpd->hWnd))
+        {
+            /* forward a WM_DEVICECHANGE message to the hardware
+               page which wouldn't get the message itself as it is
+               a child window */
+            SendMessage(hpd->hWnd,
+                        WM_DEVICECHANGE,
+                        wParam,
+                        lParam);
+        }
 
         /* pass the message the the old window proc */
         return CallWindowProc(hpd->ParentOldWndProc,
@@ -502,6 +780,18 @@ HardwareDlgResize(IN PHARDWARE_PAGE_DATA hpd,
 }
 
 
+static VOID
+EnableTroubleShoot(PHARDWARE_PAGE_DATA hpd,
+                   BOOL Enable)
+{
+    HWND hBtnTroubleShoot = GetDlgItem(hpd->hWnd,
+                                       IDC_TROUBLESHOOT);
+
+    ShowWindow(hBtnTroubleShoot,
+               Enable ? SW_SHOW : SW_HIDE);
+}
+
+
 static INT_PTR
 CALLBACK
 HardwareDlgProc(IN HWND hwndDlg,
@@ -510,6 +800,7 @@ HardwareDlgProc(IN HWND hwndDlg,
                 IN LPARAM lParam)
 {
     PHARDWARE_PAGE_DATA hpd;
+    INT_PTR Ret = FALSE;
 
     hpd = (PHARDWARE_PAGE_DATA)GetWindowLongPtr(hwndDlg,
                                                 DWL_USER);
@@ -537,6 +828,31 @@ HardwareDlgProc(IN HWND hwndDlg,
                             }
                             break;
                         }
+
+                        case NM_DBLCLK:
+                        {
+                            DisplaySelectedDeviceProperties(hpd);
+                            break;
+                        }
+                    }
+                }
+                break;
+            }
+
+            case WM_COMMAND:
+            {
+                switch (LOWORD(wParam))
+                {
+                    case IDC_TROUBLESHOOT:
+                    {
+                        /* FIXME - start the help using the command in the window text */
+                        break;
+                    }
+
+                    case IDC_PROPERTIES:
+                    {
+                        DisplaySelectedDeviceProperties(hpd);
+                        break;
                     }
                 }
                 break;
@@ -548,6 +864,22 @@ HardwareDlgProc(IN HWND hwndDlg,
                                   (INT)HIWORD(lParam));
                 break;            
 
+            case WM_SETTEXT:
+            {
+                LPCWSTR szWndText = (LPCWSTR)lParam;
+                EnableTroubleShoot(hpd,
+                                   (szWndText != NULL && szWndText[0] != L'\0'));
+                break;
+            }
+
+            case WM_DEVICECHANGE:
+            {
+                /* FIXME - don't call UpdateDevicesListViewControl for all events */
+                UpdateDevicesListViewControl(hpd);
+                Ret = TRUE;
+                break;
+            }
+
             case WM_INITDIALOG:
             {
                 hpd = (PHARDWARE_PAGE_DATA)lParam;
@@ -617,28 +949,22 @@ HardwareDlgProc(IN HWND hwndDlg,
                     InitializeDevicesList(hpd);
 
                     /* fill the devices list view control */
-                    FillDevicesList(hpd);
+                    FillDevicesListViewControl(hpd,
+                                               NULL,
+                                               NULL);
+
+                    /* decide whether to show or hide the troubleshoot button */
+                    EnableTroubleShoot(hpd,
+                                       GetWindowTextLength(hwndDlg) != 0);
                 }
+                Ret = TRUE;
                 break;
             }
 
             case WM_DESTROY:
             {
-                UINT i;
-
-                /* free the device info set handles */
-                for (i = 0;
-                     i < hpd->NumberOfGuids;
-                     i++)
-                {
-                    SetupDiDestroyDeviceInfoList(hpd->ClassDevInfo[i].hDevInfo);
-                    if (hpd->ClassDevInfo[i].HwDevInfo != NULL)
-                    {
-                        HeapFree(GetProcessHeap(),
-                                 0,
-                                 hpd->ClassDevInfo[i].HwDevInfo);
-                    }
-                }
+                /* free devices list */
+                FreeDevicesList(hpd);
 
                 /* restore the old window proc of the subclassed parent window */
                 if (hpd->hWndParent != NULL && hpd->ParentOldWndProc != NULL)
@@ -666,7 +992,7 @@ HardwareDlgProc(IN HWND hwndDlg,
         }
     }
 
-    return FALSE;
+    return Ret;
 }
 
 
@@ -681,20 +1007,13 @@ HardwareDlgProc(IN HWND hwndDlg,
  *   hWndParent:     Handle to the parent window
  *   lpGuids:        An array of guids of devices that are to be listed
  *   uNumberOfGuids: Numbers of guids in the Guids array
- *   Unknown:        Unknown parameter, see NOTEs
+ *   DisplayMode:    Sets the size of the device list view control
  *
  * RETURN VALUE
  *   Returns the handle of the hardware page window that has been created or
  *   NULL if it failed.
  *
- * REVISIONS
- *   13-05-2005 first working version (Sebastian Gasiorek <zebasoftis@gmail.com>)
- *
- * TODO
- *   missing: device icon in list view, Troubleshoot button, device properties,
- *            status description,
- *            devices should be visible afer PSN_SETACTIVE message
- *
+ * @implemented
  */
 HWND
 WINAPI
@@ -704,7 +1023,6 @@ DeviceCreateHardwarePageEx(IN HWND hWndParent,
                            IN HWPAGE_DISPLAYMODE DisplayMode)
 {
     PHARDWARE_PAGE_DATA hpd;
-    PINITCOMMONCONTROLS pInitCommonControls;
 
     /* allocate the HARDWARE_PAGE_DATA structure. Make sure it is
        zeroed because the initialization code assumes that in
@@ -712,8 +1030,7 @@ DeviceCreateHardwarePageEx(IN HWND hWndParent,
     hpd = HeapAlloc(GetProcessHeap(),
                     HEAP_ZERO_MEMORY,
                     FIELD_OFFSET(HARDWARE_PAGE_DATA,
-                                 ClassDevInfo) +
-                        (uNumberOfGuids * sizeof(HWCLASSDEVINFO)));
+                                 ClassDevInfo[uNumberOfGuids]));
     if (hpd != NULL)
     {
         HWND hWnd;
@@ -727,25 +1044,17 @@ DeviceCreateHardwarePageEx(IN HWND hWndParent,
              i < uNumberOfGuids;
              i++)
         {
+            hpd->ClassDevInfo[i].hDevInfo = INVALID_HANDLE_VALUE;
             hpd->ClassDevInfo[i].Guid = lpGuids[i];
         }
 
         /* load comctl32.dll dynamically */
-        hpd->hComCtl32 = LoadLibrary(TEXT("comctl32.dll"));
+        hpd->hComCtl32 = LoadAndInitComctl32();
         if (hpd->hComCtl32 == NULL)
         {
             goto Cleanup;
         }
 
-        /* initialize the common controls */
-        pInitCommonControls = (PINITCOMMONCONTROLS)GetProcAddress(hpd->hComCtl32,
-                                                                  "InitCommonControls");
-        if (pInitCommonControls == NULL)
-        {
-            goto Cleanup;
-        }
-        pInitCommonControls();
-
         /* create the dialog */
         hWnd = CreateDialogParam(hDllInstance,
                                  MAKEINTRESOURCE(IDD_HARDWARE), 
@@ -790,10 +1099,7 @@ Cleanup:
  *   Returns the handle of the hardware page window that has been created or
  *   NULL if it failed.
  *
- * REVISIONS
- *
- * NOTE
- *
+ * @implemented
  */
 HWND
 WINAPI