- document and partly implement DevicePropertiesExA/W()
[reactos.git] / reactos / lib / devmgr / advprop.c
index 76c8c25..9463290 100644 (file)
@@ -49,7 +49,10 @@ typedef struct _DEVADVPROP_INFO
 
     HDEVINFO DeviceInfoSet;
     SP_DEVINFO_DATA DeviceInfoData;
-    HANDLE hMachine;
+    HDEVINFO CurrentDeviceInfoSet;
+    SP_DEVINFO_DATA CurrentDeviceInfoData;
+    DEVINST ParentDevInst;
+    HMACHINE hMachine;
     LPCWSTR lpMachineName;
 
     HINSTANCE hComCtl32;
@@ -62,7 +65,9 @@ typedef struct _DEVADVPROP_INFO
     BOOL CanDisable : 1;
     BOOL DeviceEnabled : 1;
     BOOL DeviceUsageChanged : 1;
-    BOOL CreatedDevInfoSet : 1;
+    BOOL CloseDevInst : 1;
+    BOOL IsAdmin : 1;
+    BOOL DoDefaultDevAction : 1;
 
     WCHAR szDevName[255];
     WCHAR szTemp[255];
@@ -170,7 +175,7 @@ static VOID
 ApplyGeneralSettings(IN HWND hwndDlg,
                      IN PDEVADVPROP_INFO dap)
 {
-    if (dap->DeviceUsageChanged)
+    if (dap->DeviceUsageChanged && dap->IsAdmin)
     {
         DEVENABLEACTION SelectedUsageAction;
 
@@ -217,13 +222,14 @@ UpdateDevInfo(IN HWND hwndDlg,
     HWND hPropSheetDlg;
     BOOL bFlag;
     DWORD i;
+    HDEVINFO DeviceInfoSet = NULL;
+    PSP_DEVINFO_DATA DeviceInfoData = NULL;
 
     hPropSheetDlg = GetParent(hwndDlg);
 
     if (ReOpen)
     {
         PROPSHEETHEADER psh;
-        HDEVINFO hOldDevInfo;
 
         /* switch to the General page */
         PropSheet_SetCurSelByID(hPropSheetDlg,
@@ -254,46 +260,56 @@ UpdateDevInfo(IN HWND hwndDlg,
         dap->nDevPropSheets = 0;
 
         /* create a new device info set and re-open the device */
-        hOldDevInfo = dap->DeviceInfoSet;
-        dap->DeviceInfoSet = SetupDiCreateDeviceInfoListEx(NULL,
-                                                           hwndDlg,
-                                                           dap->lpMachineName,
-                                                           NULL);
-        if (dap->DeviceInfoSet != INVALID_HANDLE_VALUE)
+        if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
         {
-            if (SetupDiOpenDeviceInfo(dap->DeviceInfoSet,
+            SetupDiDestroyDeviceInfoList(dap->CurrentDeviceInfoSet);
+        }
+
+        dap->ParentDevInst = 0;
+        dap->CurrentDeviceInfoSet = SetupDiCreateDeviceInfoListEx(NULL,
+                                                                  hwndDlg,
+                                                                  dap->lpMachineName,
+                                                                  NULL);
+        if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
+        {
+            if (SetupDiOpenDeviceInfo(dap->CurrentDeviceInfoSet,
                                       dap->szDeviceID,
                                       hwndDlg,
                                       0,
-                                      &dap->DeviceInfoData))
+                                      &dap->CurrentDeviceInfoData))
             {
-                if (dap->CreatedDevInfoSet)
+                if (dap->CloseDevInst)
                 {
-                    SetupDiDestroyDeviceInfoList(hOldDevInfo);
+                    SetupDiDestroyDeviceInfoList(dap->DeviceInfoSet);
                 }
 
-                dap->CreatedDevInfoSet = TRUE;
+                dap->CloseDevInst = TRUE;
+                dap->DeviceInfoSet = dap->CurrentDeviceInfoSet;
+                dap->DeviceInfoData = dap->CurrentDeviceInfoData;
+                dap->CurrentDeviceInfoSet = INVALID_HANDLE_VALUE;
             }
             else
-            {
-                SetupDiDestroyDeviceInfoList(dap->DeviceInfoSet);
-                dap->DeviceInfoSet = INVALID_HANDLE_VALUE;
-                dap->CreatedDevInfoSet = FALSE;
-            }
+                goto GetParentNode;
         }
         else
         {
-            /* oops, something went wrong, restore the old device info set */
-            dap->DeviceInfoSet = hOldDevInfo;
+GetParentNode:
+            /* get the parent node from the initial devinst */
+            CM_Get_Parent_Ex(&dap->ParentDevInst,
+                             dap->DeviceInfoData.DevInst,
+                             0,
+                             dap->hMachine);
+        }
 
-            if (dap->DeviceInfoSet != INVALID_HANDLE_VALUE)
-            {
-                SetupDiOpenDeviceInfo(dap->DeviceInfoSet,
-                                      dap->szDeviceID,
-                                      hwndDlg,
-                                      0,
-                                      &dap->DeviceInfoData);
-            }
+        if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
+        {
+            DeviceInfoSet = dap->CurrentDeviceInfoSet;
+            DeviceInfoData = &dap->CurrentDeviceInfoData;
+        }
+        else
+        {
+            DeviceInfoSet = dap->DeviceInfoSet;
+            DeviceInfoData = &dap->DeviceInfoData;
         }
 
         /* find out how many new device property sheets to add.
@@ -303,8 +319,8 @@ UpdateDevInfo(IN HWND hwndDlg,
         psh.dwFlags = 0;
         psh.nPages = 0;
 
-        if (!SetupDiGetClassDevPropertySheets(dap->DeviceInfoSet,
-                                              &dap->DeviceInfoData,
+        if (!SetupDiGetClassDevPropertySheets(DeviceInfoSet,
+                                              DeviceInfoData,
                                               &psh,
                                               0,
                                               &dap->nDevPropSheets,
@@ -319,8 +335,8 @@ UpdateDevInfo(IN HWND hwndDlg,
                 psh.phpage = dap->DevPropSheets;
 
                 /* query the new property sheet pages to add */
-                if (SetupDiGetClassDevPropertySheets(dap->DeviceInfoSet,
-                                                     &dap->DeviceInfoData,
+                if (SetupDiGetClassDevPropertySheets(DeviceInfoSet,
+                                                     DeviceInfoData,
                                                      &psh,
                                                      dap->nDevPropSheets,
                                                      NULL,
@@ -353,10 +369,23 @@ UpdateDevInfo(IN HWND hwndDlg,
                 dap->nDevPropSheets = 0;
         }
     }
+    else
+    {
+        if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
+        {
+            DeviceInfoSet = dap->CurrentDeviceInfoSet;
+            DeviceInfoData = &dap->CurrentDeviceInfoData;
+        }
+        else
+        {
+            DeviceInfoSet = dap->DeviceInfoSet;
+            DeviceInfoData = &dap->DeviceInfoData;
+        }
+    }
 
     /* get the device name */
-    if (GetDeviceDescriptionString(dap->DeviceInfoSet,
-                                   &dap->DeviceInfoData,
+    if (GetDeviceDescriptionString(DeviceInfoSet,
+                                   DeviceInfoData,
                                    dap->szDevName,
                                    sizeof(dap->szDevName) / sizeof(dap->szDevName[0])))
     {
@@ -366,7 +395,7 @@ UpdateDevInfo(IN HWND hwndDlg,
     }
 
     /* set the device image */
-    if (SetupDiLoadClassIcon(&dap->DeviceInfoData.ClassGuid,
+    if (SetupDiLoadClassIcon(&DeviceInfoData->ClassGuid,
                              &hIcon,
                              NULL))
     {
@@ -387,7 +416,7 @@ UpdateDevInfo(IN HWND hwndDlg,
                    dap->szDevName);
 
     /* set the device type edit control text */
-    if (GetDeviceTypeString(&dap->DeviceInfoData,
+    if (GetDeviceTypeString(DeviceInfoData,
                             dap->szTemp,
                             sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
     {
@@ -397,8 +426,8 @@ UpdateDevInfo(IN HWND hwndDlg,
     }
 
     /* set the device manufacturer edit control text */
-    if (GetDeviceManufacturerString(dap->DeviceInfoSet,
-                                    &dap->DeviceInfoData,
+    if (GetDeviceManufacturerString(DeviceInfoSet,
+                                    DeviceInfoData,
                                     dap->szTemp,
                                     sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
     {
@@ -408,7 +437,8 @@ UpdateDevInfo(IN HWND hwndDlg,
     }
 
     /* set the device location edit control text */
-    if (GetDeviceLocationString(dap->DeviceInfoData.DevInst,
+    if (GetDeviceLocationString(DeviceInfoData->DevInst,
+                                dap->ParentDevInst,
                                 dap->szTemp,
                                 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
     {
@@ -418,7 +448,7 @@ UpdateDevInfo(IN HWND hwndDlg,
     }
 
     /* set the device status edit control text */
-    if (GetDeviceStatusString(dap->DeviceInfoData.DevInst,
+    if (GetDeviceStatusString(DeviceInfoData->DevInst,
                               dap->hMachine,
                               dap->szTemp,
                               sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
@@ -435,14 +465,14 @@ UpdateDevInfo(IN HWND hwndDlg,
     dap->CanDisable = FALSE;
     dap->DeviceEnabled = FALSE;
 
-    if (CanDisableDevice(dap->DeviceInfoData.DevInst,
+    if (CanDisableDevice(DeviceInfoData->DevInst,
                          dap->hMachine,
                          &bFlag))
     {
         dap->CanDisable = bFlag;
     }
 
-    if (IsDeviceEnabled(dap->DeviceInfoData.DevInst,
+    if (IsDeviceEnabled(DeviceInfoData->DevInst,
                         dap->hMachine,
                         &bFlag))
     {
@@ -452,9 +482,9 @@ UpdateDevInfo(IN HWND hwndDlg,
     /* enable/disable the device usage controls */
     EnableWindow(GetDlgItem(hwndDlg,
                             IDC_DEVUSAGELABEL),
-                 dap->CanDisable);
+                 dap->CanDisable && dap->IsAdmin);
     EnableWindow(hDevUsage,
-                 dap->CanDisable);
+                 dap->CanDisable && dap->IsAdmin);
 
     /* clear the combobox */
     SendMessage(hDevUsage,
@@ -653,7 +683,8 @@ DisplayDeviceAdvancedProperties(IN HWND hWndParent,
                                 IN HDEVINFO DeviceInfoSet,
                                 IN PSP_DEVINFO_DATA DeviceInfoData,
                                 IN HINSTANCE hComCtl32,
-                                IN LPCWSTR lpMachineName)
+                                IN LPCWSTR lpMachineName,
+                                IN DWORD dwFlags)
 {
     PROPSHEETHEADER psh = {0};
     PROPSHEETPAGE pspGeneral = {0};
@@ -662,7 +693,7 @@ DisplayDeviceAdvancedProperties(IN HWND hWndParent,
     PCREATEPROPERTYSHEETPAGEW pCreatePropertySheetPageW;
     PDESTROYPROPERTYSHEETPAGE pDestroyPropertySheetPage;
     PDEVADVPROP_INFO DevAdvPropInfo;
-    HANDLE hMachine = NULL;
+    HMACHINE hMachine = NULL;
     DWORD DevIdSize = 0;
     INT_PTR Ret = -1;
 
@@ -726,6 +757,7 @@ DisplayDeviceAdvancedProperties(IN HWND hWndParent,
                                    (DevIdSize * sizeof(WCHAR)));
     if (DevAdvPropInfo == NULL)
     {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
         goto Cleanup;
     }
 
@@ -750,11 +782,17 @@ DisplayDeviceAdvancedProperties(IN HWND hWndParent,
 
     DevAdvPropInfo->DeviceInfoSet = DeviceInfoSet;
     DevAdvPropInfo->DeviceInfoData = *DeviceInfoData;
+    DevAdvPropInfo->CurrentDeviceInfoSet = INVALID_HANDLE_VALUE;
+    DevAdvPropInfo->CurrentDeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
+
     DevAdvPropInfo->hMachine = hMachine;
     DevAdvPropInfo->lpMachineName = lpMachineName;
     DevAdvPropInfo->szDevName[0] = L'\0';
     DevAdvPropInfo->hComCtl32 = hComCtl32;
 
+    DevAdvPropInfo->IsAdmin = IsUserAdmin();
+    DevAdvPropInfo->DoDefaultDevAction = ((dwFlags & DPF_DEVICE_STATUS_ACTION) != 0);
+
     psh.dwSize = sizeof(PROPSHEETHEADER);
     psh.dwFlags = PSH_PROPTITLE | PSH_NOAPPLYNOW;
     psh.hwndParent = hWndParent;
@@ -860,12 +898,17 @@ Cleanup:
                      DevAdvPropInfo->DevPropSheets);
         }
 
-        if (DevAdvPropInfo->CreatedDevInfoSet)
+        if (DevAdvPropInfo->CloseDevInst)
         {
             /* close the device info set in case a new one was created */
             SetupDiDestroyDeviceInfoList(DevAdvPropInfo->DeviceInfoSet);
         }
 
+        if (DevAdvPropInfo->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
+        {
+            SetupDiDestroyDeviceInfoList(DevAdvPropInfo->CurrentDeviceInfoSet);
+        }
+
         HeapFree(GetProcessHeap(),
                  0,
                  DevAdvPropInfo);
@@ -901,19 +944,15 @@ Cleanup:
  *   lpDeviceID:    Specifies the device whose properties are to be shown
  *
  * RETURN VALUE
- *   -1: if errors occured
- *
- * REVISIONS
- *
- * NOTE
+ *   Always returns -1, a call to GetLastError returns 0 if successful
  *
  * @implemented
  */
 INT_PTR
 WINAPI
-DeviceAdvancedPropertiesW(HWND hWndParent,
-                          LPCWSTR lpMachineName,
-                          LPCWSTR lpDeviceID)
+DeviceAdvancedPropertiesW(IN HWND hWndParent  OPTIONAL,
+                          IN LPCWSTR lpMachineName  OPTIONAL,
+                          IN LPCWSTR lpDeviceID)
 {
     HDEVINFO hDevInfo;
     SP_DEVINFO_DATA DevInfoData;
@@ -942,7 +981,8 @@ DeviceAdvancedPropertiesW(HWND hWndParent,
                                                       hDevInfo,
                                                       &DevInfoData,
                                                       hComCtl32,
-                                                      lpMachineName);
+                                                      lpMachineName,
+                                                      0);
             }
 
             SetupDiDestroyDeviceInfoList(hDevInfo);
@@ -969,19 +1009,15 @@ DeviceAdvancedPropertiesW(HWND hWndParent,
  *   lpDeviceID:    Specifies the device whose properties are to be shown
  *
  * RETURN VALUE
- *   -1: if errors occured
- *
- * REVISIONS
- *
- * NOTE
+ *   Always returns -1, a call to GetLastError returns 0 if successful
  *
  * @implemented
  */
 INT_PTR
 WINAPI
-DeviceAdvancedPropertiesA(HWND hWndParent,
-                          LPCSTR lpMachineName,
-                          LPCSTR lpDeviceID)
+DeviceAdvancedPropertiesA(IN HWND hWndParent  OPTIONAL,
+                          IN LPCSTR lpMachineName  OPTIONAL,
+                          IN LPCSTR lpDeviceID)
 {
     LPWSTR lpMachineNameW = NULL;
     LPWSTR lpDeviceIDW = NULL;
@@ -1024,3 +1060,178 @@ Cleanup:
 
     return Ret;
 }
+
+
+/***************************************************************************
+ * NAME                                                         EXPORTED
+ *      DevicePropertiesExA
+ *
+ * DESCRIPTION
+ *   Invokes the extended device properties dialog
+ *
+ * ARGUMENTS
+ *   hWndParent:    Handle to the parent window
+ *   lpMachineName: Machine Name, NULL is the local machine
+ *   lpDeviceID:    Specifies the device whose properties are to be shown
+ *   dwFlags:       This parameter can be a combination of the following flags:
+ *                  * DPF_DEVICE_STATUS_ACTION: Only valid if bShowDevMgr, causes
+ *                                              the default device status action button
+ *                                              to be clicked (Troubleshoot, Enable
+ *                                              Device, etc)
+ *   bShowDevMgr:   If non-zero it displays the device manager instead of
+ *                  the advanced device property dialog
+ *
+ * RETURN VALUE
+ *   1:  if bShowDevMgr is non-zero and no error occured
+ *   -1: a call to GetLastError returns 0 if successful
+ *
+ * @implemented
+ */
+INT_PTR
+WINAPI
+DevicePropertiesExA(IN HWND hWndParent  OPTIONAL,
+                    IN LPCSTR lpMachineName  OPTIONAL,
+                    IN LPCSTR lpDeviceID  OPTIONAL,
+                    IN DWORD dwFlags  OPTIONAL,
+                    IN BOOL bShowDevMgr)
+{
+    LPWSTR lpMachineNameW = NULL;
+    LPWSTR lpDeviceIDW = NULL;
+    INT_PTR Ret = -1;
+
+    if (lpMachineName != NULL)
+    {
+        if (!(lpMachineNameW = ConvertMultiByteToUnicode(lpMachineName,
+                                                         CP_ACP)))
+        {
+            goto Cleanup;
+        }
+    }
+    if (lpDeviceID != NULL)
+    {
+        if (!(lpDeviceIDW = ConvertMultiByteToUnicode(lpDeviceID,
+                                                      CP_ACP)))
+        {
+            goto Cleanup;
+        }
+    }
+
+    Ret = DevicePropertiesExW(hWndParent,
+                              lpMachineNameW,
+                              lpDeviceIDW,
+                              dwFlags,
+                              bShowDevMgr);
+
+Cleanup:
+    if (lpMachineNameW != NULL)
+    {
+        HeapFree(GetProcessHeap(),
+                 0,
+                 lpMachineNameW);
+    }
+    if (lpDeviceIDW != NULL)
+    {
+        HeapFree(GetProcessHeap(),
+                 0,
+                 lpDeviceIDW);
+    }
+
+    return Ret;
+}
+
+
+/***************************************************************************
+ * NAME                                                         EXPORTED
+ *      DevicePropertiesExW
+ *
+ * DESCRIPTION
+ *   Invokes the extended device properties dialog
+ *
+ * ARGUMENTS
+ *   hWndParent:    Handle to the parent window
+ *   lpMachineName: Machine Name, NULL is the local machine
+ *   lpDeviceID:    Specifies the device whose properties are to be shown
+ *   dwFlags:       This parameter can be a combination of the following flags:
+ *                  * DPF_DEVICE_STATUS_ACTION: Only valid if bShowDevMgr, causes
+ *                                              the default device status action button
+ *                                              to be clicked (Troubleshoot, Enable
+ *                                              Device, etc)
+ *   bShowDevMgr:   If non-zero it displays the device manager instead of
+ *                  the advanced device property dialog
+ *
+ * RETURN VALUE
+ *   1:  if bShowDevMgr is non-zero and no error occured
+ *   -1: a call to GetLastError returns 0 if successful
+ *
+ * @unimplemented
+ */
+INT_PTR
+WINAPI
+DevicePropertiesExW(IN HWND hWndParent  OPTIONAL,
+                    IN LPCWSTR lpMachineName  OPTIONAL,
+                    IN LPCWSTR lpDeviceID  OPTIONAL,
+                    IN DWORD dwFlags  OPTIONAL,
+                    IN BOOL bShowDevMgr)
+{
+    INT_PTR Ret = -1;
+
+    if (dwFlags & ~(DPF_UNKNOWN | DPF_DEVICE_STATUS_ACTION))
+    {
+        DPRINT1("DevPropertiesExW: Invalid flags: 0x%x\n",
+                dwFlags & ~(DPF_UNKNOWN | DPF_DEVICE_STATUS_ACTION));
+        SetLastError(ERROR_INVALID_FLAGS);
+        return -1;
+    }
+
+    if (bShowDevMgr)
+    {
+        DPRINT("DevPropertiesExW doesn't support bShowDevMgr!\n");
+        SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    }
+    else
+    {
+        HDEVINFO hDevInfo;
+        SP_DEVINFO_DATA DevInfoData;
+        HINSTANCE hComCtl32;
+
+        if (lpDeviceID == NULL)
+        {
+            SetLastError(ERROR_INVALID_PARAMETER);
+            return -1;
+        }
+
+        /* dynamically load comctl32 */
+        hComCtl32 = LoadAndInitComctl32();
+        if (hComCtl32 != NULL)
+        {
+            hDevInfo = SetupDiCreateDeviceInfoListEx(NULL,
+                                                     hWndParent,
+                                                     lpMachineName,
+                                                     NULL);
+            if (hDevInfo != INVALID_HANDLE_VALUE)
+            {
+                DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
+                if (SetupDiOpenDeviceInfo(hDevInfo,
+                                          lpDeviceID,
+                                          hWndParent,
+                                          0,
+                                          &DevInfoData))
+                {
+                    Ret = DisplayDeviceAdvancedProperties(hWndParent,
+                                                          lpDeviceID,
+                                                          hDevInfo,
+                                                          &DevInfoData,
+                                                          hComCtl32,
+                                                          lpMachineName,
+                                                          dwFlags);
+                }
+
+                SetupDiDestroyDeviceInfoList(hDevInfo);
+            }
+
+            FreeLibrary(hComCtl32);
+        }
+    }
+
+    return Ret;
+}