Implement SetupDiGetDeviceInstanceIdW
[reactos.git] / reactos / lib / devmgr / hwpage.c
index ce8969e..4dfe8d5 100644 (file)
@@ -30,8 +30,6 @@
 #define NDEBUG
 #include <debug.h>
 
-typedef VOID (WINAPI *PINITCOMMONCONTROLS)(VOID);
-
 typedef enum
 {
     HWPD_STANDARDLIST = 0,
@@ -49,6 +47,7 @@ typedef struct _HWCLASSDEVINFO
 {
     GUID Guid;
     HDEVINFO hDevInfo;
+    INT ImageIndex;
     INT ItemCount;
     PHWDEVINFO HwDevInfo;
 } HWCLASSDEVINFO, *PHWCLASSDEVINFO;
@@ -125,102 +124,351 @@ InitializeDevicesList(IN PHARDWARE_PAGE_DATA hpd)
 }
 
 
+static BOOL
+DisplaySelectedDeviceProperties(IN PHARDWARE_PAGE_DATA hpd)
+{
+    PHWDEVINFO HwDevInfo;
+    BOOL Ret = FALSE;
+
+    HwDevInfo = (PHWDEVINFO)ListViewGetSelectedItemData(hpd->hWndDevList);
+    if (HwDevInfo != NULL)
+    {
+        PWSTR szDeviceInstanceId = NULL;
+        DWORD DeviceInstanceIdLen = 0;
+
+        /* find out how much size is needed for the buffer */
+        if (SetupDiGetDeviceInstanceId(HwDevInfo->ClassDevInfo->hDevInfo,
+                                       &HwDevInfo->DevInfoData,
+                                       NULL,
+                                       0,
+                                       &DeviceInstanceIdLen))
+        {
+            DPRINT1("SetupDiGetDeviceInstanceId unexpectedly returned TRUE!\n");
+            goto Cleanup;
+        }
+
+        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+        {
+            goto Cleanup;
+        }
+
+        szDeviceInstanceId = HeapAlloc(GetProcessHeap(),
+                                       0,
+                                       DeviceInstanceIdLen * sizeof(WCHAR));
+        if (szDeviceInstanceId == NULL)
+        {
+            goto Cleanup;
+        }
+
+        /* read the device instance id */
+        if (!SetupDiGetDeviceInstanceId(HwDevInfo->ClassDevInfo->hDevInfo,
+                                        &HwDevInfo->DevInfoData,
+                                        szDeviceInstanceId,
+                                        DeviceInstanceIdLen,
+                                        &DeviceInstanceIdLen))
+        {
+            goto Cleanup;
+        }
+
+        /* display the properties dialog */
+        Ret = DeviceAdvancedProperties(hpd->hWnd,
+                                       NULL,
+                                       szDeviceInstanceId) >= 0;
+
+Cleanup:
+        if (szDeviceInstanceId != NULL)
+        {
+            HeapFree(GetProcessHeap(),
+                     0,
+                     szDeviceInstanceId);
+        }
+    }
+
+    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 */
+        CONFIGRET cRet;
+        DWORD RegDataType;
+        ULONG DataSize;
+        WCHAR szBuffer[256];
+        LPWSTR szFormatted = NULL;
+
+        /* get the manufacturer string */
+        if (!SetupDiGetDeviceRegistryProperty(HwDevInfo->ClassDevInfo->hDevInfo,
+                                              &HwDevInfo->DevInfoData,
+                                              SPDRP_MFG,
+                                              &RegDataType,
+                                              (PBYTE)szBuffer,
+                                              sizeof(szBuffer),
+                                              NULL) ||
+            RegDataType != REG_SZ)
+        {
+            szBuffer[0] = L'\0';
+            LoadString(hDllInstance,
+                       IDS_UNKNOWN,
+                       szBuffer,
+                       sizeof(szBuffer) / sizeof(szBuffer[0]));
+        }
+        /* FIXME - check string for NULL termination! */
+        if (LoadAndFormatString(hDllInstance,
+                                IDS_MANUFACTURER,
+                                &szFormatted,
+                                szBuffer) != 0)
+        {
+            SetDlgItemText(hpd->hWnd,
+                           IDC_MANUFACTURER,
+                           szFormatted);
+            LocalFree((HLOCAL)szFormatted);
+        }
+
+        /* get the location string */
+        DataSize = sizeof(szBuffer);
+        cRet = CM_Get_DevNode_Registry_Property(HwDevInfo->DevInfoData.DevInst,
+                                                CM_DRP_LOCATION_INFORMATION,
+                                                &RegDataType,
+                                                szBuffer,
+                                                &DataSize,
+                                                0);
+        if (cRet != CR_SUCCESS ||
+            RegDataType != REG_SZ)
+        {
+            szBuffer[0] = L'\0';
+            LoadString(hDllInstance,
+                       IDS_UNKNOWN,
+                       szBuffer,
+                       sizeof(szBuffer) / sizeof(szBuffer[0]));
+        }
+        /* FIXME - check string for NULL termination! */
+
+        if (szBuffer[0] >= L'0' && szBuffer[0] <= L'9')
+        {
+            /* convert the string to an integer value and create a
+               formatted string */
+            ULONG ulLocation = (ULONG)wcstoul(szBuffer,
+                                              NULL,
+                                              10);
+            if (LoadAndFormatString(hDllInstance,
+                                    IDS_LOCATIONSTR,
+                                    &szFormatted,
+                                    ulLocation,
+                                    szBuffer) != 0)
+            {
+                wcsncpy(szBuffer,
+                        szFormatted,
+                        (sizeof(szBuffer) / sizeof(szBuffer[0])) - 1);
+                szBuffer[(sizeof(szBuffer) / sizeof(szBuffer[0])) - 1] = L'\0';
+                LocalFree((HLOCAL)szFormatted);
+            }
+        }
+
+        if (LoadAndFormatString(hDllInstance,
+                                IDS_LOCATION,
+                                &szFormatted,
+                                szBuffer) != 0)
+        {
+            SetDlgItemText(hpd->hWnd,
+                           IDC_LOCATION,
+                           szFormatted);
+            LocalFree((HLOCAL)szFormatted);
+        }
+
+        /* FIXME - get the device status text */
+        LoadString(hDllInstance,
+                   IDS_UNKNOWN,
+                   szBuffer,
+                   sizeof(szBuffer) / sizeof(szBuffer[0]));
+
+        if (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);
+        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;
-
-                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;
+                /* save all information for the current device */
+                ClassDevInfo->HwDevInfo[ClassDevInfo->ItemCount].ClassDevInfo = ClassDevInfo;
+                ClassDevInfo->HwDevInfo[ClassDevInfo->ItemCount++].DevInfoData = DevInfoData;
+            }
+        }
+
+        ClassDevInfo++;
+    }
+}
+
+
+static VOID
+FillDevicesListViewControl(IN PHARDWARE_PAGE_DATA hpd)
+{
+    PHWCLASSDEVINFO ClassDevInfo, LastClassDevInfo;
+    PHWDEVINFO HwDevInfo, LastHwDevInfo;
+    WCHAR szBuffer[255];
+    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;
 
-                if ((SetupDiGetDeviceRegistryProperty(DevInfo->hDevInfo,
-                                                      &DevInfoData,
+            while (HwDevInfo != LastHwDevInfo)
+            {
+                DWORD RegDataType;
+                INT iItem;
+                LVITEM li;
+
+                /* get the device name */
+                if ((SetupDiGetDeviceRegistryProperty(ClassDevInfo->hDevInfo,
+                                                      &HwDevInfo->DevInfoData,
                                                       SPDRP_FRIENDLYNAME,
                                                       &RegDataType,
                                                       (PBYTE)szBuffer,
                                                       sizeof(szBuffer),
                                                       NULL) ||
-                     SetupDiGetDeviceRegistryProperty(DevInfo->hDevInfo,
-                                                      &DevInfoData,
+                     SetupDiGetDeviceRegistryProperty(ClassDevInfo->hDevInfo,
+                                                      &HwDevInfo->DevInfoData,
                                                       SPDRP_DEVICEDESC,
                                                       &RegDataType,
                                                       (PBYTE)szBuffer,
@@ -236,8 +484,8 @@ FillDevicesList(IN PHARDWARE_PAGE_DATA hpd)
                     li.state = (ItemCount == 0 ? LVIS_SELECTED : 0);
                     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,7 +493,8 @@ FillDevicesList(IN PHARDWARE_PAGE_DATA hpd)
                     {
                         ItemCount++;
 
-                        if (SetupDiGetClassDescription(&DevInfo->Guid,
+                        /* get the device type for the second column */
+                        if (SetupDiGetClassDescription(&ClassDevInfo->Guid,
                                                        szBuffer,
                                                        sizeof(szBuffer) / sizeof(szBuffer[0]),
                                                        NULL))
@@ -259,10 +508,12 @@ FillDevicesList(IN PHARDWARE_PAGE_DATA hpd)
                         }
                     }
                 }
+
+                HwDevInfo++;
             }
         }
 
-        DevInfo++;
+        ClassDevInfo++;
     }
 
     /* update the controls */
@@ -502,6 +753,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,
@@ -542,12 +805,39 @@ HardwareDlgProc(IN HWND hwndDlg,
                 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;
+            }
+
             case WM_SIZE:
                 HardwareDlgResize(hpd,
                                   (INT)LOWORD(lParam),
                                   (INT)HIWORD(lParam));
                 break;            
 
+            case WM_SETTEXT:
+            {
+                LPCWSTR szWndText = (LPCWSTR)lParam;
+                EnableTroubleShoot(hpd,
+                                   (szWndText != NULL && szWndText[0] != L'\0'));
+                break;
+            }
+
             case WM_INITDIALOG:
             {
                 hpd = (PHARDWARE_PAGE_DATA)lParam;
@@ -617,28 +907,19 @@ HardwareDlgProc(IN HWND hwndDlg,
                     InitializeDevicesList(hpd);
 
                     /* fill the devices list view control */
-                    FillDevicesList(hpd);
+                    FillDevicesListViewControl(hpd);
+
+                    /* decide whether to show or hide the troubleshoot button */
+                    EnableTroubleShoot(hpd,
+                                       GetWindowTextLength(hwndDlg) != 0);
                 }
                 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)
@@ -681,20 +962,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 +978,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
@@ -727,25 +1000,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 +1055,7 @@ Cleanup:
  *   Returns the handle of the hardware page window that has been created or
  *   NULL if it failed.
  *
- * REVISIONS
- *
- * NOTE
- *
+ * @implemented
  */
 HWND
 WINAPI