add the driver details dialog (not fully implemented)
[reactos.git] / reactos / lib / devmgr / advprop.c
index ee46873..245e51c 100644 (file)
@@ -39,6 +39,7 @@ typedef struct _DEVADVPROP_INFO
     HWND hWndGeneralPage;
     HWND hWndParent;
     WNDPROC ParentOldWndProc;
+    HICON hDevIcon;
 
     HDEVINFO DeviceInfoSet;
     SP_DEVINFO_DATA DeviceInfoData;
@@ -49,6 +50,8 @@ typedef struct _DEVADVPROP_INFO
     LPCWSTR lpMachineName;
 
     HINSTANCE hComCtl32;
+    PCREATEPROPERTYSHEETPAGEW pCreatePropertySheetPageW;
+    PDESTROYPROPERTYSHEETPAGE pDestroyPropertySheetPage;
 
     DWORD PropertySheetType;
     DWORD nDevPropSheets;
@@ -56,11 +59,16 @@ typedef struct _DEVADVPROP_INFO
 
     BOOL FreeDevPropSheets : 1;
     BOOL CanDisable : 1;
-    BOOL DeviceEnabled : 1;
+    BOOL DeviceStarted : 1;
     BOOL DeviceUsageChanged : 1;
     BOOL CloseDevInst : 1;
     BOOL IsAdmin : 1;
     BOOL DoDefaultDevAction : 1;
+    BOOL PageInitialized : 1;
+    BOOL ShowRemotePages : 1;
+    BOOL HasDriverPage : 1;
+    BOOL HasResourcePage : 1;
+    BOOL HasPowerPage : 1;
 
     WCHAR szDevName[255];
     WCHAR szTemp[255];
@@ -69,6 +77,340 @@ typedef struct _DEVADVPROP_INFO
 } DEVADVPROP_INFO, *PDEVADVPROP_INFO;
 
 
+typedef struct _ENUMDRIVERFILES_CONTEXT
+{
+    HWND hDriversListView;
+    UINT nCount;
+} ENUMDRIVERFILES_CONTEXT, *PENUMDRIVERFILES_CONTEXT;
+
+#define PM_INITIALIZE (WM_APP + 0x101)
+
+
+static UINT WINAPI
+EnumDeviceDriverFilesCallback(IN PVOID Context,
+                              IN UINT Notification,
+                              IN UINT_PTR Param1,
+                              IN UINT_PTR Param2)
+{
+    LVITEM li;
+    PENUMDRIVERFILES_CONTEXT EnumDriverFilesContext = (PENUMDRIVERFILES_CONTEXT)Context;
+
+    li.mask = LVIF_TEXT | LVIF_STATE;
+    li.iItem = EnumDriverFilesContext->nCount++;
+    li.iSubItem = 0;
+    li.state = (li.iItem == 0 ? LVIS_SELECTED : 0);
+    li.stateMask = LVIS_SELECTED;
+    li.pszText = (LPWSTR)Param1;
+    ListView_InsertItem(EnumDriverFilesContext->hDriversListView,
+                        &li);
+    return NO_ERROR;
+}
+
+
+static VOID
+UpdateDriverDetailsDlg(IN HWND hwndDlg,
+                       IN HWND hDriversListView,
+                       IN PDEVADVPROP_INFO dap)
+{
+    HDEVINFO DeviceInfoSet;
+    PSP_DEVINFO_DATA DeviceInfoData;
+    SP_DRVINFO_DATA DriverInfoData;
+    ENUMDRIVERFILES_CONTEXT EnumDriverFilesContext;
+
+    if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
+    {
+        DeviceInfoSet = dap->CurrentDeviceInfoSet;
+        DeviceInfoData = &dap->CurrentDeviceInfoData;
+    }
+    else
+    {
+        DeviceInfoSet = dap->DeviceInfoSet;
+        DeviceInfoData = &dap->DeviceInfoData;
+    }
+
+    /* set the device image */
+    SendDlgItemMessage(hwndDlg,
+                       IDC_DEVICON,
+                       STM_SETICON,
+                       (WPARAM)dap->hDevIcon,
+                       0);
+
+    /* set the device name edit control text */
+    SetDlgItemText(hwndDlg,
+                   IDC_DEVNAME,
+                   dap->szDevName);
+
+    /* fill the driver files list view */
+    EnumDriverFilesContext.hDriversListView = hDriversListView;
+    EnumDriverFilesContext.nCount = 0;
+
+    ListView_DeleteAllItems(EnumDriverFilesContext.hDriversListView);
+    DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
+    if (FindCurrentDriver(DeviceInfoSet,
+                          DeviceInfoData,
+                          &DriverInfoData) &&
+        SetupDiSetSelectedDriver(DeviceInfoSet,
+                                 DeviceInfoData,
+                                 &DriverInfoData))
+    {
+        HSPFILEQ queueHandle;
+
+        queueHandle = SetupOpenFileQueue();
+        if (queueHandle != (HSPFILEQ)INVALID_HANDLE_VALUE)
+        {
+            SP_DEVINSTALL_PARAMS DeviceInstallParams = {0};
+            DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+            if (SetupDiGetDeviceInstallParams(DeviceInfoSet,
+                                              DeviceInfoData,
+                                              &DeviceInstallParams))
+            {
+                DeviceInstallParams.FileQueue = queueHandle;
+                DeviceInstallParams.Flags |= DI_NOVCP;
+
+                if (SetupDiSetDeviceInstallParams(DeviceInfoSet,
+                                                  DeviceInfoData,
+                                                  &DeviceInstallParams) &&
+                    SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES,
+                                              DeviceInfoSet,
+                                              DeviceInfoData))
+                {
+                    DWORD scanResult;
+                    RECT rcClient;
+                    LVCOLUMN lvc;
+
+                    /* enumerate the driver files */
+                    SetupScanFileQueue(queueHandle,
+                                       SPQ_SCAN_USE_CALLBACK,
+                                       NULL,
+                                       EnumDeviceDriverFilesCallback,
+                                       &EnumDriverFilesContext,
+                                       &scanResult);
+
+                    /* update the list view column width */
+                    GetClientRect(hDriversListView,
+                                  &rcClient);
+                    lvc.mask = LVCF_WIDTH;
+                    lvc.cx = rcClient.right;
+                    ListView_SetColumn(hDriversListView,
+                                       0,
+                                       &lvc);
+                }
+            }
+
+            SetupCloseFileQueue(queueHandle);
+        }
+    }
+}
+
+
+static INT_PTR
+CALLBACK
+DriverDetailsDlgProc(IN HWND hwndDlg,
+                     IN UINT uMsg,
+                     IN WPARAM wParam,
+                     IN LPARAM lParam)
+{
+    PDEVADVPROP_INFO dap;
+    INT_PTR Ret = FALSE;
+
+    dap = (PDEVADVPROP_INFO)GetWindowLongPtr(hwndDlg,
+                                             DWL_USER);
+
+    if (dap != NULL || uMsg == WM_INITDIALOG)
+    {
+        switch (uMsg)
+        {
+            case WM_COMMAND:
+            {
+                switch (LOWORD(wParam))
+                {
+                    case IDOK:
+                    {
+                        EndDialog(hwndDlg,
+                                  IDOK);
+                        break;
+                    }
+                }
+                break;
+            }
+
+            case WM_CLOSE:
+            {
+                EndDialog(hwndDlg,
+                          IDCANCEL);
+                break;
+            }
+
+            case WM_INITDIALOG:
+            {
+                LV_COLUMN lvc;
+                HWND hDriversListView;
+
+                dap = (PDEVADVPROP_INFO)lParam;
+                if (dap != NULL)
+                {
+                    SetWindowLongPtr(hwndDlg,
+                                     DWL_USER,
+                                     (DWORD_PTR)dap);
+
+                    hDriversListView = GetDlgItem(hwndDlg,
+                                                  IDC_DRIVERFILES);
+
+                    /* add a column to the list view control */
+                    lvc.mask = LVCF_FMT | LVCF_WIDTH;
+                    lvc.fmt = LVCFMT_LEFT;
+                    lvc.cx = 0;
+                    ListView_InsertColumn(hDriversListView,
+                                          0,
+                                          &lvc);
+
+                    UpdateDriverDetailsDlg(hwndDlg,
+                                           hDriversListView,
+                                           dap);
+                }
+
+                Ret = TRUE;
+                break;
+            }
+        }
+    }
+
+    return Ret;
+}
+
+
+static VOID
+UpdateDriverDlg(IN HWND hwndDlg,
+                IN PDEVADVPROP_INFO dap)
+{
+    HDEVINFO DeviceInfoSet;
+    PSP_DEVINFO_DATA DeviceInfoData;
+
+    if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
+    {
+        DeviceInfoSet = dap->CurrentDeviceInfoSet;
+        DeviceInfoData = &dap->CurrentDeviceInfoData;
+    }
+    else
+    {
+        DeviceInfoSet = dap->DeviceInfoSet;
+        DeviceInfoData = &dap->DeviceInfoData;
+    }
+
+    /* set the device image */
+    SendDlgItemMessage(hwndDlg,
+                       IDC_DEVICON,
+                       STM_SETICON,
+                       (WPARAM)dap->hDevIcon,
+                       0);
+
+    /* set the device name edit control text */
+    SetDlgItemText(hwndDlg,
+                   IDC_DEVNAME,
+                   dap->szDevName);
+
+    /* query the driver provider */
+    if (GetDriverProviderString(DeviceInfoSet,
+                                DeviceInfoData,
+                                dap->szTemp,
+                                sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
+    {
+        SetDlgItemText(hwndDlg,
+                       IDC_DRVPROVIDER,
+                       dap->szTemp);
+    }
+
+    /* query the driver date */
+    if (GetDriverDateString(DeviceInfoSet,
+                            DeviceInfoData,
+                            dap->szTemp,
+                            sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
+    {
+        SetDlgItemText(hwndDlg,
+                       IDC_DRVDATE,
+                       dap->szTemp);
+    }
+
+    /* query the driver version */
+    if (GetDriverVersionString(DeviceInfoSet,
+                               DeviceInfoData,
+                               dap->szTemp,
+                               sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
+    {
+        SetDlgItemText(hwndDlg,
+                       IDC_DRVVERSION,
+                       dap->szTemp);
+    }
+}
+
+
+static INT_PTR
+CALLBACK
+AdvProcDriverDlgProc(IN HWND hwndDlg,
+                     IN UINT uMsg,
+                     IN WPARAM wParam,
+                     IN LPARAM lParam)
+{
+    PDEVADVPROP_INFO dap;
+    INT_PTR Ret = FALSE;
+
+    dap = (PDEVADVPROP_INFO)GetWindowLongPtr(hwndDlg,
+                                             DWL_USER);
+
+    if (dap != NULL || uMsg == WM_INITDIALOG)
+    {
+        switch (uMsg)
+        {
+            case WM_COMMAND:
+            {
+                switch (LOWORD(wParam))
+                {
+                    case IDC_DRIVERDETAILS:
+                    {
+                        DialogBoxParam(hDllInstance,
+                                       MAKEINTRESOURCE(IDD_DRIVERDETAILS),
+                                       hwndDlg,
+                                       DriverDetailsDlgProc,
+                                       (ULONG_PTR)dap);
+                        break;
+                    }
+                }
+                break;
+            }
+
+            case WM_NOTIFY:
+            {
+                NMHDR *hdr = (NMHDR*)lParam;
+                switch (hdr->code)
+                {
+                    case PSN_APPLY:
+                        break;
+                }
+                break;
+            }
+
+            case WM_INITDIALOG:
+            {
+                dap = (PDEVADVPROP_INFO)((LPPROPSHEETPAGE)lParam)->lParam;
+                if (dap != NULL)
+                {
+                    SetWindowLongPtr(hwndDlg,
+                                     DWL_USER,
+                                     (DWORD_PTR)dap);
+
+                    UpdateDriverDlg(hwndDlg,
+                                    dap);
+                }
+                Ret = TRUE;
+                break;
+            }
+        }
+    }
+
+    return Ret;
+}
+
+
 static VOID
 InitDevUsageActions(IN HWND hwndDlg,
                     IN HWND hComboBox,
@@ -106,7 +448,7 @@ InitDevUsageActions(IN HWND hwndDlg,
                 switch (Actions[i])
                 {
                     case IDS_ENABLEDEVICE:
-                        if (dap->DeviceEnabled)
+                        if (dap->DeviceStarted)
                         {
                             SendMessage(hComboBox,
                                         CB_SETCURSEL,
@@ -116,7 +458,7 @@ InitDevUsageActions(IN HWND hwndDlg,
                         break;
 
                     case IDS_DISABLEDEVICE:
-                        if (!dap->DeviceEnabled)
+                        if (!dap->DeviceStarted)
                         {
                             SendMessage(hComboBox,
                                         CB_SETCURSEL,
@@ -176,7 +518,7 @@ ApplyGeneralSettings(IN HWND hwndDlg,
         switch (SelectedUsageAction)
         {
             case IDS_ENABLEDEVICE:
-                if (!dap->DeviceEnabled)
+                if (!dap->DeviceStarted)
                 {
                     Ret = EnableDevice(dap->DeviceInfoSet,
                                        &dap->DeviceInfoData,
@@ -187,7 +529,7 @@ ApplyGeneralSettings(IN HWND hwndDlg,
                 break;
 
             case IDS_DISABLEDEVICE:
-                if (dap->DeviceEnabled)
+                if (dap->DeviceStarted)
                 {
                     Ret = EnableDevice(dap->DeviceInfoSet,
                                        &dap->DeviceInfoData,
@@ -232,50 +574,62 @@ UpdateDevInfo(IN HWND hwndDlg,
               IN PDEVADVPROP_INFO dap,
               IN BOOL ReOpen)
 {
-    HICON hIcon;
     HWND hDevUsage, hPropSheetDlg, hDevProbBtn;
     CONFIGRET cr;
     ULONG Status, ProblemNumber;
+    SP_DEVINSTALL_PARAMS_W InstallParams;
     UINT TroubleShootStrId = IDS_TROUBLESHOOTDEV;
     BOOL bFlag, bDevActionAvailable = TRUE;
-    DWORD i;
+    BOOL bDrvInstalled = FALSE;
+    DWORD iPage;
     HDEVINFO DeviceInfoSet = NULL;
     PSP_DEVINFO_DATA DeviceInfoData = NULL;
+    PROPSHEETHEADER psh;
+    DWORD nDriverPages = 0;
 
     hPropSheetDlg = GetParent(hwndDlg);
 
-    if (ReOpen)
+    if (dap->PageInitialized)
     {
-        PROPSHEETHEADER psh;
-
         /* switch to the General page */
         PropSheet_SetCurSelByID(hPropSheetDlg,
                                 IDD_DEVICEGENERAL);
 
         /* remove and destroy the existing device property sheet pages */
-        for (i = 0;
-             i != dap->nDevPropSheets;
-             i++)
+        if (dap->DevPropSheets != NULL)
         {
-            PropSheet_RemovePage(hPropSheetDlg,
-                                 -1,
-                                 dap->DevPropSheets[i]);
+            for (iPage = 0;
+                 iPage != dap->nDevPropSheets;
+                 iPage++)
+            {
+                if (dap->DevPropSheets[iPage] != NULL)
+                {
+                    PropSheet_RemovePage(hPropSheetDlg,
+                                         -1,
+                                         dap->DevPropSheets[iPage]);
+                }
+            }
         }
+    }
 
-        if (dap->FreeDevPropSheets)
-        {
-            /* don't free the array if it's the one allocated in
-               DisplayDeviceAdvancedProperties */
-            HeapFree(GetProcessHeap(),
-                     0,
-                     dap->DevPropSheets);
+    iPage = 0;
 
-            dap->FreeDevPropSheets = FALSE;
-        }
+    if (dap->FreeDevPropSheets)
+    {
+        /* don't free the array if it's the one allocated in
+           DisplayDeviceAdvancedProperties */
+        HeapFree(GetProcessHeap(),
+                 0,
+                 dap->DevPropSheets);
+
+        dap->FreeDevPropSheets = FALSE;
+    }
 
-        dap->DevPropSheets = NULL;
-        dap->nDevPropSheets = 0;
+    dap->DevPropSheets = NULL;
+    dap->nDevPropSheets = 0;
 
+    if (ReOpen)
+    {
         /* create a new device info set and re-open the device */
         if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
         {
@@ -328,76 +682,54 @@ GetParentNode:
             DeviceInfoSet = dap->DeviceInfoSet;
             DeviceInfoData = &dap->DeviceInfoData;
         }
+    }
+    else
+    {
+        DeviceInfoSet = dap->DeviceInfoSet;
+        DeviceInfoData = &dap->DeviceInfoData;
+    }
 
-        /* find out how many new device property sheets to add.
-           fake a PROPSHEETHEADER structure, we don't plan to
-           call PropertySheet again!*/
-        psh.dwSize = sizeof(PROPSHEETHEADER);
-        psh.dwFlags = 0;
-        psh.nPages = 0;
-
-        if (!SetupDiGetClassDevPropertySheets(DeviceInfoSet,
-                                              DeviceInfoData,
-                                              &psh,
-                                              0,
-                                              &dap->nDevPropSheets,
-                                              dap->PropertySheetType) &&
-            dap->nDevPropSheets != 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+    dap->HasDriverPage = FALSE;
+    dap->HasResourcePage = FALSE;
+    dap->HasPowerPage = FALSE;
+    if (IsDriverInstalled(DeviceInfoData->DevInst,
+                          dap->hMachine,
+                          &bDrvInstalled) &&
+        bDrvInstalled)
+    {
+        if (SetupDiCallClassInstaller((dap->ShowRemotePages ?
+                                           DIF_ADDREMOTEPROPERTYPAGE_ADVANCED :
+                                           DIF_ADDPROPERTYPAGE_ADVANCED),
+                                      DeviceInfoSet,
+                                      DeviceInfoData))
         {
-            dap->DevPropSheets = HeapAlloc(GetProcessHeap(),
-                                           HEAP_ZERO_MEMORY,
-                                           dap->nDevPropSheets * sizeof(HPROPSHEETPAGE));
-            if (dap->DevPropSheets != NULL)
+            /* get install params */
+            InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
+            if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet,
+                                                DeviceInfoData,
+                                                &InstallParams))
             {
-                psh.phpage = dap->DevPropSheets;
-
-                /* query the new property sheet pages to add */
-                if (SetupDiGetClassDevPropertySheets(DeviceInfoSet,
-                                                     DeviceInfoData,
-                                                     &psh,
-                                                     dap->nDevPropSheets,
-                                                     NULL,
-                                                     dap->PropertySheetType))
-                {
-                    /* add the property sheets */
-
-                    for (i = 0;
-                         i != dap->nDevPropSheets;
-                         i++)
-                    {
-                        PropSheet_AddPage(hPropSheetDlg,
-                                          dap->DevPropSheets[i]);
-                    }
-
-                    dap->FreeDevPropSheets = TRUE;
-                }
-                else
-                {
-                    /* cleanup, we were unable to get the device property sheets */
-                    HeapFree(GetProcessHeap(),
-                             0,
-                             dap->DevPropSheets);
-
-                    dap->nDevPropSheets = 0;
-                    dap->DevPropSheets = NULL;
-                }
+                /* zero the flags */
+                InstallParams.Flags = 0;
             }
-            else
-                dap->nDevPropSheets = 0;
+
+            dap->HasDriverPage = !(InstallParams.Flags & DI_DRIVERPAGE_ADDED);
+            dap->HasResourcePage = !(InstallParams.Flags & DI_RESOURCEPAGE_ADDED);
+            dap->HasPowerPage = !(InstallParams.Flags & DI_FLAGSEX_POWERPAGE_ADDED);
         }
     }
-    else
+
+    /* get the device icon */
+    if (dap->hDevIcon != NULL)
     {
-        if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
-        {
-            DeviceInfoSet = dap->CurrentDeviceInfoSet;
-            DeviceInfoData = &dap->CurrentDeviceInfoData;
-        }
-        else
-        {
-            DeviceInfoSet = dap->DeviceInfoSet;
-            DeviceInfoData = &dap->DeviceInfoData;
-        }
+        DestroyIcon(dap->hDevIcon);
+        dap->hDevIcon = NULL;
+    }
+    if (!SetupDiLoadClassIcon(&DeviceInfoData->ClassGuid,
+                              &dap->hDevIcon,
+                              NULL))
+    {
+        dap->hDevIcon = NULL;
     }
 
     /* get the device name */
@@ -406,26 +738,17 @@ GetParentNode:
                                    dap->szDevName,
                                    sizeof(dap->szDevName) / sizeof(dap->szDevName[0])))
     {
-        PropSheet_SetTitle(GetParent(hwndDlg),
+        PropSheet_SetTitle(hPropSheetDlg,
                            PSH_PROPTITLE,
                            dap->szDevName);
     }
 
     /* set the device image */
-    if (SetupDiLoadClassIcon(&DeviceInfoData->ClassGuid,
-                             &hIcon,
-                             NULL))
-    {
-        HICON hOldIcon = (HICON)SendDlgItemMessage(hwndDlg,
-                                                   IDC_DEVICON,
-                                                   STM_SETICON,
-                                                   (WPARAM)hIcon,
-                                                   0);
-        if (hOldIcon != NULL)
-        {
-            DestroyIcon(hOldIcon);
-        }
-    }
+    SendDlgItemMessage(hwndDlg,
+                       IDC_DEVICON,
+                       STM_SETICON,
+                       (WPARAM)dap->hDevIcon,
+                       0);
 
     /* set the device name edit control text */
     SetDlgItemText(hwndDlg,
@@ -606,7 +929,7 @@ GetParentNode:
                            IDC_DEVUSAGE);
 
     dap->CanDisable = FALSE;
-    dap->DeviceEnabled = FALSE;
+    dap->DeviceStarted = FALSE;
 
     if (CanDisableDevice(DeviceInfoData->DevInst,
                          dap->hMachine,
@@ -615,11 +938,11 @@ GetParentNode:
         dap->CanDisable = bFlag;
     }
 
-    if (IsDeviceEnabled(DeviceInfoData->DevInst,
+    if (IsDeviceStarted(DeviceInfoData->DevInst,
                         dap->hMachine,
                         &bFlag))
     {
-        dap->DeviceEnabled = bFlag;
+        dap->DeviceStarted = bFlag;
     }
 
     /* enable/disable the device usage controls */
@@ -641,6 +964,105 @@ GetParentNode:
                             dap);
     }
 
+    /* find out how many new device property sheets to add.
+       fake a PROPSHEETHEADER structure, we don't plan to
+       call PropertySheet again!*/
+    psh.dwSize = sizeof(PROPSHEETHEADER);
+    psh.dwFlags = 0;
+    psh.nPages = 0;
+
+    /* get the number of device property sheets for the device */
+    if (!SetupDiGetClassDevPropertySheets(DeviceInfoSet,
+                                          DeviceInfoData,
+                                          &psh,
+                                          0,
+                                          &nDriverPages,
+                                          dap->PropertySheetType) &&
+        nDriverPages != 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+    {
+        dap->nDevPropSheets += nDriverPages;
+    }
+    else
+    {
+        nDriverPages = 0;
+    }
+
+    /* include the driver page */
+    if (dap->HasDriverPage)
+        dap->nDevPropSheets++;
+
+    /* add the device property sheets */
+    if (dap->nDevPropSheets != 0)
+    {
+        dap->DevPropSheets = HeapAlloc(GetProcessHeap(),
+                                       HEAP_ZERO_MEMORY,
+                                       dap->nDevPropSheets * sizeof(HPROPSHEETPAGE));
+        if (dap->DevPropSheets != NULL)
+        {
+            if (nDriverPages != 0)
+            {
+                psh.phpage = dap->DevPropSheets;
+
+                /* query the device property sheet pages to add */
+                if (SetupDiGetClassDevPropertySheets(DeviceInfoSet,
+                                                     DeviceInfoData,
+                                                     &psh,
+                                                     dap->nDevPropSheets,
+                                                     NULL,
+                                                     dap->PropertySheetType))
+                {
+                    /* add the property sheets */
+                    for (iPage = 0;
+                         iPage != nDriverPages;
+                         iPage++)
+                    {
+                        PropSheet_AddPage(hPropSheetDlg,
+                                          dap->DevPropSheets[iPage]);
+                    }
+
+                    dap->FreeDevPropSheets = TRUE;
+                }
+                else
+                {
+                    /* cleanup, we were unable to get the device property sheets */
+                    iPage = nDriverPages;
+                    dap->nDevPropSheets -= nDriverPages;
+                    nDriverPages = 0;
+                }
+            }
+            else
+                iPage = 0;
+
+            /* add the driver page if necessary */
+            if (dap->HasDriverPage)
+            {
+                PROPSHEETPAGE pspDriver = {0};
+                pspDriver.dwSize = sizeof(PROPSHEETPAGE);
+                pspDriver.dwFlags = PSP_DEFAULT;
+                pspDriver.hInstance = hDllInstance;
+                pspDriver.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICEDRIVER);
+                pspDriver.pfnDlgProc = AdvProcDriverDlgProc;
+                pspDriver.lParam = (LPARAM)dap;
+                dap->DevPropSheets[iPage] = dap->pCreatePropertySheetPageW(&pspDriver);
+                if (dap->DevPropSheets[iPage] != NULL)
+                {
+                    if (PropSheet_AddPage(hPropSheetDlg,
+                                          dap->DevPropSheets[iPage]))
+                    {
+                        iPage++;
+                    }
+                    else
+                    {
+                        dap->pDestroyPropertySheetPage(dap->DevPropSheets[iPage]);
+                        dap->DevPropSheets[iPage] = NULL;
+                    }
+                }
+            }
+        }
+        else
+            dap->nDevPropSheets = 0;
+    }
+
     /* finally, disable the apply button */
     PropSheet_UnChanged(hPropSheetDlg,
                         hwndDlg);
@@ -785,9 +1207,12 @@ AdvPropGeneralDlgProc(IN HWND hwndDlg,
                         }
                     }
 
-                    UpdateDevInfo(hwndDlg,
-                                  dap,
-                                  FALSE);
+                    /* do not call UpdateDevInfo directly in here because it modifies
+                       the pages of the property sheet! */
+                    PostMessage(hwndDlg,
+                                PM_INITIALIZE,
+                                0,
+                                0);
                 }
                 Ret = TRUE;
                 break;
@@ -803,27 +1228,27 @@ AdvPropGeneralDlgProc(IN HWND hwndDlg,
                 break;
             }
 
-            case WM_DESTROY:
+            case PM_INITIALIZE:
             {
-                HICON hDevIcon;
+                UpdateDevInfo(hwndDlg,
+                              dap,
+                              FALSE);
+                dap->PageInitialized = TRUE;
+                break;
+            }
 
+            case WM_DESTROY:
+            {
                 /* restore the old window proc of the subclassed parent window */
                 if (dap->hWndParent != NULL && dap->ParentOldWndProc != NULL)
                 {
-                    SetWindowLongPtr(dap->hWndParent,
-                                     GWLP_WNDPROC,
-                                     (LONG_PTR)dap->ParentOldWndProc);
-                }
-
-                /* destroy the device icon */
-                hDevIcon = (HICON)SendDlgItemMessage(hwndDlg,
-                                                     IDC_DEVICON,
-                                                     STM_GETICON,
-                                                     0,
-                                                     0);
-                if (hDevIcon != NULL)
-                {
-                    DestroyIcon(hDevIcon);
+                    if (SetWindowLongPtr(dap->hWndParent,
+                                         GWLP_WNDPROC,
+                                         (LONG_PTR)dap->ParentOldWndProc) == (LONG_PTR)DlgParentSubWndProc)
+                    {
+                        RemoveProp(dap->hWndParent,
+                                   L"DevMgrDevChangeSub");
+                    }
                 }
                 break;
             }
@@ -845,7 +1270,6 @@ DisplayDeviceAdvancedProperties(IN HWND hWndParent,
 {
     PROPSHEETHEADER psh = {0};
     PROPSHEETPAGE pspGeneral = {0};
-    DWORD nPropSheets = 0;
     PPROPERTYSHEETW pPropertySheetW;
     PCREATEPROPERTYSHEETPAGEW pCreatePropertySheetPageW;
     PDESTROYPROPERTYSHEETPAGE pDestroyPropertySheetPage;
@@ -895,7 +1319,7 @@ DisplayDeviceAdvancedProperties(IN HWND hWndParent,
         DevIdSize = (DWORD)wcslen(lpDeviceID) + 1;
     }
 
-    if (lpMachineName != NULL)
+    if (lpMachineName != NULL && lpMachineName[0] != L'\0')
     {
         CONFIGRET cr = CM_Connect_Machine(lpMachineName,
                                           &hMachine);
@@ -942,10 +1366,13 @@ DisplayDeviceAdvancedProperties(IN HWND hWndParent,
     DevAdvPropInfo->CurrentDeviceInfoSet = INVALID_HANDLE_VALUE;
     DevAdvPropInfo->CurrentDeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
 
+    DevAdvPropInfo->ShowRemotePages = (lpMachineName != NULL && lpMachineName[0] != L'\0');
     DevAdvPropInfo->hMachine = hMachine;
     DevAdvPropInfo->lpMachineName = lpMachineName;
     DevAdvPropInfo->szDevName[0] = L'\0';
     DevAdvPropInfo->hComCtl32 = hComCtl32;
+    DevAdvPropInfo->pCreatePropertySheetPageW = pCreatePropertySheetPageW;
+    DevAdvPropInfo->pDestroyPropertySheetPage = pDestroyPropertySheetPage;
 
     DevAdvPropInfo->IsAdmin = IsUserAdmin();
     DevAdvPropInfo->DoDefaultDevAction = ((dwFlags & DPF_DEVICE_STATUS_ACTION) != 0);
@@ -955,31 +1382,13 @@ DisplayDeviceAdvancedProperties(IN HWND hWndParent,
     psh.hwndParent = hWndParent;
     psh.pszCaption = DevAdvPropInfo->szDevName;
 
-    DevAdvPropInfo->PropertySheetType = lpMachineName != NULL ?
+    DevAdvPropInfo->PropertySheetType = DevAdvPropInfo->ShowRemotePages ?
                                             DIGCDP_FLAG_REMOTE_ADVANCED :
                                             DIGCDP_FLAG_ADVANCED;
 
-    /* find out how many property sheets we need */
-    if (SetupDiGetClassDevPropertySheets(DeviceInfoSet,
-                                         &DevAdvPropInfo->DeviceInfoData,
-                                         &psh,
-                                         0,
-                                         &nPropSheets,
-                                         DevAdvPropInfo->PropertySheetType) &&
-        nPropSheets != 0)
-    {
-        DPRINT1("SetupDiGetClassDevPropertySheets unexpectedly returned TRUE!\n");
-        goto Cleanup;
-    }
-
-    if (nPropSheets != 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
-    {
-        goto Cleanup;
-    }
-
     psh.phpage = HeapAlloc(GetProcessHeap(),
                            HEAP_ZERO_MEMORY,
-                           (nPropSheets + 1) * sizeof(HPROPSHEETPAGE));
+                           1 * sizeof(HPROPSHEETPAGE));
     if (psh.phpage == NULL)
     {
         goto Cleanup;
@@ -992,31 +1401,13 @@ DisplayDeviceAdvancedProperties(IN HWND hWndParent,
     pspGeneral.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICEGENERAL);
     pspGeneral.pfnDlgProc = AdvPropGeneralDlgProc;
     pspGeneral.lParam = (LPARAM)DevAdvPropInfo;
-    psh.phpage[0] = pCreatePropertySheetPageW(&pspGeneral);
-    if (psh.phpage[0] != NULL)
+    psh.phpage[psh.nPages] = pCreatePropertySheetPageW(&pspGeneral);
+    if (psh.phpage[psh.nPages] != NULL)
     {
         psh.nPages++;
     }
 
-    DevAdvPropInfo->nDevPropSheets = nPropSheets;
-
-    if (nPropSheets != 0)
-    {
-        DevAdvPropInfo->DevPropSheets = psh.phpage + psh.nPages;
-
-        /* create the device property sheets */
-        if (!SetupDiGetClassDevPropertySheets(DeviceInfoSet,
-                                              &DevAdvPropInfo->DeviceInfoData,
-                                              &psh,
-                                              nPropSheets + psh.nPages,
-                                              NULL,
-                                              DevAdvPropInfo->PropertySheetType))
-        {
-            goto Cleanup;
-        }
-    }
-
-    /* FIXME - add the "Driver" property sheet if necessary */
+    DevAdvPropInfo->nDevPropSheets = psh.nPages;
 
     if (psh.nPages != 0)
     {
@@ -1066,6 +1457,11 @@ Cleanup:
             SetupDiDestroyDeviceInfoList(DevAdvPropInfo->CurrentDeviceInfoSet);
         }
 
+        if (DevAdvPropInfo->hDevIcon != NULL)
+        {
+            DestroyIcon(DevAdvPropInfo->hDevIcon);
+        }
+
         HeapFree(GetProcessHeap(),
                  0,
                  DevAdvPropInfo);