[DEVMGR]
authorGed Murphy <gedmurphy@reactos.org>
Tue, 7 Jul 2015 11:43:15 +0000 (11:43 +0000)
committerGed Murphy <gedmurphy@reactos.org>
Tue, 7 Jul 2015 11:43:15 +0000 (11:43 +0000)
I know this *_new thing is a bit overused, but there are a lot of changes coming to devmgr and rather than take it out of the build for a few days, it's easier to do it this way

svn path=/trunk/; revision=68369

53 files changed:
reactos/dll/win32/devmgr_new/CMakeLists.txt [new file with mode: 0644]
reactos/dll/win32/devmgr_new/advprop.c [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgmt/ClassNode.cpp [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgmt/ClassNode.h [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgmt/DeviceNode.cpp [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgmt/DeviceNode.h [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgmt/DeviceView.cpp [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgmt/DeviceView.h [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgmt/MainWindow.cpp [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgmt/MainWindow.h [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgmt/Node.cpp [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgmt/Node.h [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgmt/Resource.h [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgmt/RootNode.cpp [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgmt/RootNode.h [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgmt/devmgmt.h [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgmt/lang/en-US.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgmt/lang/tr-TR.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgmt/res/computer.ico [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgmt/res/root.bmp [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgmt/res/toolbar.bmp [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgmt/rsrc.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgmt/stdafx.h [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgr.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devmgr.spec [new file with mode: 0644]
reactos/dll/win32/devmgr_new/devprblm.c [new file with mode: 0644]
reactos/dll/win32/devmgr_new/hwpage.c [new file with mode: 0644]
reactos/dll/win32/devmgr_new/hwresource.c [new file with mode: 0644]
reactos/dll/win32/devmgr_new/lang/bg-BG.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/lang/cs-CZ.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/lang/de-DE.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/lang/el-GR.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/lang/en-US.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/lang/es-ES.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/lang/fr-FR.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/lang/he-IL.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/lang/hu-HU.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/lang/id-ID.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/lang/it-IT.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/lang/no-NO.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/lang/pl-PL.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/lang/pt-BR.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/lang/ro-RO.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/lang/ru-RU.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/lang/sk-SK.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/lang/sq-AL.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/lang/tr-TR.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/lang/uk-UA.rc [new file with mode: 0644]
reactos/dll/win32/devmgr_new/misc.c [new file with mode: 0644]
reactos/dll/win32/devmgr_new/precomp.h [new file with mode: 0644]
reactos/dll/win32/devmgr_new/resource.h [new file with mode: 0644]
reactos/dll/win32/devmgr_new/resources/devmgr.ico [new file with mode: 0644]
reactos/dll/win32/devmgr_new/stubs.c [new file with mode: 0644]

diff --git a/reactos/dll/win32/devmgr_new/CMakeLists.txt b/reactos/dll/win32/devmgr_new/CMakeLists.txt
new file mode 100644 (file)
index 0000000..179e0ce
--- /dev/null
@@ -0,0 +1,23 @@
+
+spec2def(devmgr.dll devmgr.spec ADD_IMPORTLIB)
+
+list(APPEND SOURCE
+    advprop.c
+    devprblm.c
+    hwpage.c
+    hwresource.c
+    misc.c
+    stubs.c
+    precomp.h
+    ${CMAKE_CURRENT_BINARY_DIR}/devmgr_stubs.c)
+
+add_library(devmgr SHARED
+    ${SOURCE}
+    devmgr.rc
+    ${CMAKE_CURRENT_BINARY_DIR}/devmgr.def)
+
+set_module_type(devmgr win32dll UNICODE)
+target_link_libraries(devmgr uuid wine)
+add_importlibs(devmgr setupapi advapi32 newdev user32 version msvcrt kernel32 ntdll)
+add_pch(devmgr precomp.h SOURCE)
+add_cd_file(TARGET devmgr DESTINATION reactos/system32 FOR all)
diff --git a/reactos/dll/win32/devmgr_new/advprop.c b/reactos/dll/win32/devmgr_new/advprop.c
new file mode 100644 (file)
index 0000000..2b83fb5
--- /dev/null
@@ -0,0 +1,3308 @@
+/*
+ * ReactOS Device Manager Applet
+ * Copyright (C) 2004 - 2005 ReactOS Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+/*
+ *
+ * PROJECT:         ReactOS devmgr.dll
+ * FILE:            lib/devmgr/advprop.c
+ * PURPOSE:         ReactOS Device Manager
+ * PROGRAMMER:      Thomas Weidenmueller <w3seek@reactos.com>
+ *                  Ged Murphy <gedmurphy@reactos.org>
+ * UPDATE HISTORY:
+ *      04-04-2004  Created
+ */
+
+#include "precomp.h"
+
+#include <winver.h>
+
+
+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;
+    (void)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;
+
+    (void)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;
+                    (void)ListView_SetColumn(hDriversListView,
+                                             0,
+                                             &lvc);
+
+                    /* highlight the first item from list */
+                    if (ListView_GetSelectedCount(hDriversListView) != 0)
+                    {
+                        ListView_SetItemState(hDriversListView,
+                                              0,
+                                              LVIS_FOCUSED | LVIS_SELECTED,
+                                              LVIS_FOCUSED | LVIS_SELECTED);
+                    }
+                }
+            }
+
+            SetupCloseFileQueue(queueHandle);
+        }
+    }
+}
+
+
+static VOID
+UpdateDriverVersionInfoDetails(IN HWND hwndDlg,
+                               IN LPCWSTR lpszDriverPath)
+{
+    DWORD dwHandle;
+    DWORD dwVerInfoSize;
+    LPVOID lpData = NULL;
+    LPVOID lpInfo;
+    UINT uInfoLen;
+    DWORD dwLangId;
+    WCHAR szLangInfo[255];
+    WCHAR szLangPath[MAX_PATH];
+    LPWSTR lpCompanyName = NULL;
+    LPWSTR lpFileVersion = NULL;
+    LPWSTR lpLegalCopyright = NULL;
+    LPWSTR lpDigitalSigner = NULL;
+    UINT uBufLen;
+    WCHAR szNotAvailable[255];
+
+    /* extract version info from selected file */
+    dwVerInfoSize = GetFileVersionInfoSize(lpszDriverPath,
+                                           &dwHandle);
+    if (!dwVerInfoSize)
+        goto done;
+
+    lpData = HeapAlloc(GetProcessHeap(),
+                       HEAP_ZERO_MEMORY,
+                       dwVerInfoSize);
+    if (!lpData)
+        goto done;
+
+    if (!GetFileVersionInfo(lpszDriverPath,
+                            dwHandle,
+                            dwVerInfoSize,
+                            lpData))
+        goto done;
+
+    if (!VerQueryValue(lpData,
+                       L"\\VarFileInfo\\Translation",
+                       &lpInfo,
+                       &uInfoLen))
+        goto done;
+
+    dwLangId = *(LPDWORD)lpInfo;
+    swprintf(szLangInfo, L"\\StringFileInfo\\%04x%04x\\",
+             LOWORD(dwLangId), HIWORD(dwLangId));
+
+    /* read CompanyName */
+    wcscpy(szLangPath, szLangInfo);
+    wcscat(szLangPath, L"CompanyName");
+
+    VerQueryValue(lpData,
+                  szLangPath,
+                  (void **)&lpCompanyName,
+                  (PUINT)&uBufLen);
+
+    /* read FileVersion */
+    wcscpy(szLangPath, szLangInfo);
+    wcscat(szLangPath, L"FileVersion");
+
+    VerQueryValue(lpData,
+                  szLangPath,
+                  (void **)&lpFileVersion,
+                  (PUINT)&uBufLen);
+
+    /* read LegalTrademarks */
+    wcscpy(szLangPath, szLangInfo);
+    wcscat(szLangPath, L"LegalCopyright");
+
+    VerQueryValue(lpData,
+                  szLangPath,
+                  (void **)&lpLegalCopyright,
+                  (PUINT)&uBufLen);
+
+    /* TODO: read digital signer info */
+
+done:
+    if (!LoadString(hDllInstance,
+                    IDS_NOTAVAILABLE,
+                    szNotAvailable,
+                    sizeof(szNotAvailable) / sizeof(WCHAR)))
+    {
+        wcscpy(szNotAvailable, L"n/a");
+    }
+
+    /* update labels */
+    if (!lpCompanyName)
+        lpCompanyName = szNotAvailable;
+    SetDlgItemText(hwndDlg,
+                   IDC_FILEPROVIDER,
+                   lpCompanyName);
+
+    if (!lpFileVersion)
+        lpFileVersion = szNotAvailable;
+    SetDlgItemText(hwndDlg,
+                   IDC_FILEVERSION,
+                   lpFileVersion);
+
+    if (!lpLegalCopyright)
+        lpLegalCopyright = szNotAvailable;
+    SetDlgItemText(hwndDlg,
+                   IDC_FILECOPYRIGHT,
+                   lpLegalCopyright);
+
+    if (!lpDigitalSigner)
+        lpDigitalSigner = szNotAvailable;
+    SetDlgItemText(hwndDlg,
+                   IDC_DIGITALSIGNER,
+                   lpDigitalSigner);
+
+    /* release version info */
+    if (lpData)
+        HeapFree(GetProcessHeap(),
+                 0,
+                 lpData);
+}
+
+
+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:
+                    case IDCANCEL:
+                    {
+                        EndDialog(hwndDlg,
+                                  IDOK);
+                        break;
+                    }
+                }
+                break;
+            }
+
+            case WM_CLOSE:
+            {
+                EndDialog(hwndDlg,
+                          IDCANCEL);
+                break;
+            }
+
+            case WM_INITDIALOG:
+            {
+                LV_COLUMN lvc;
+                HWND hDriversListView;
+                WCHAR szBuffer[260];
+
+                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;
+                    (void)ListView_InsertColumn(hDriversListView,
+                                                0,
+                                                &lvc);
+
+                    UpdateDriverDetailsDlg(hwndDlg,
+                                           hDriversListView,
+                                           dap);
+
+                    if (ListView_GetItemCount(hDriversListView) == 0)
+                    {
+                        if(LoadStringW(hDllInstance, IDS_NODRIVERS, szBuffer, _countof(szBuffer)))
+                            MessageBoxW(hwndDlg, szBuffer, dap->szDevName, MB_OK);
+                        EndDialog(hwndDlg, IDCANCEL);
+                    }
+                }
+
+                Ret = TRUE;
+                break;
+            }
+
+            case WM_NOTIFY:
+            {
+                LPNMHDR pnmhdr = (LPNMHDR)lParam;
+
+                switch (pnmhdr->code)
+                {
+                case LVN_ITEMCHANGED:
+                    {
+                        LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam;
+                        HWND hDriversListView = GetDlgItem(hwndDlg,
+                                                           IDC_DRIVERFILES);
+
+                        if (ListView_GetSelectedCount(hDriversListView) == 0)
+                        {
+                            /* nothing is selected - empty the labels */
+                            SetDlgItemText(hwndDlg,
+                                           IDC_FILEPROVIDER,
+                                           NULL);
+                            SetDlgItemText(hwndDlg,
+                                           IDC_FILEVERSION,
+                                           NULL);
+                            SetDlgItemText(hwndDlg,
+                                           IDC_FILECOPYRIGHT,
+                                           NULL);
+                            SetDlgItemText(hwndDlg,
+                                           IDC_DIGITALSIGNER,
+                                           NULL);
+                        }
+                        else if (pnmv->uNewState != 0)
+                        {
+                            /* extract version info and update the labels */
+                            WCHAR szDriverPath[MAX_PATH];
+
+                            ListView_GetItemText(hDriversListView,
+                                                 pnmv->iItem,
+                                                 pnmv->iSubItem,
+                                                 szDriverPath,
+                                                 MAX_PATH);
+
+                            UpdateDriverVersionInfoDetails(hwndDlg,
+                                                           szDriverPath);
+                        }
+                    }
+                }
+                break;
+            }
+        }
+    }
+
+    return Ret;
+}
+
+
+static
+VOID
+UpdateDriver(
+    IN HWND hwndDlg,
+    IN PDEVADVPROP_INFO dap)
+{
+    TOKEN_PRIVILEGES Privileges;
+    HANDLE hToken;
+    DWORD dwReboot;
+    BOOL NeedReboot = FALSE;
+
+    // Better use InstallDevInst:
+    //     BOOL
+    //     WINAPI
+    //     InstallDevInst(
+    //         HWND hWnd,
+    //         LPWSTR wszDeviceId,
+    //         BOOL bUpdate,
+    //         DWORD *dwReboot);
+    // See: http://comp.os.ms-windows.programmer.win32.narkive.com/J8FTd4KK/signature-of-undocumented-installdevinstex
+
+    if (!InstallDevInst(hwndDlg, dap->szDeviceID, TRUE, &dwReboot))
+        return;
+
+    if (NeedReboot == FALSE)
+        return;
+
+    //FIXME: load text from resource file
+    if (MessageBoxW(hwndDlg, L"Reboot now?", L"Reboot required", MB_YESNO | MB_ICONQUESTION) != IDYES)
+        return;
+
+    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
+    {
+        ERR("OpenProcessToken failed\n");
+        return;
+    }
+
+    /* Get the LUID for the Shutdown privilege */
+    if (!LookupPrivilegeValueW(NULL, SE_SHUTDOWN_NAME, &Privileges.Privileges[0].Luid))
+    {
+        ERR("LookupPrivilegeValue failed\n");
+        CloseHandle(hToken);
+        return;
+    }
+
+    /* Assign the Shutdown privilege to our process */
+    Privileges.PrivilegeCount = 1;
+    Privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+    if (!AdjustTokenPrivileges(hToken, FALSE, &Privileges, 0, NULL, NULL))
+    {
+        ERR("AdjustTokenPrivileges failed\n");
+        CloseHandle(hToken);
+        return;
+    }
+
+    /* Finally shut down the system */
+    if (!ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER | SHTDN_REASON_FLAG_PLANNED))
+    {
+        ERR("ExitWindowsEx failed\n");
+        CloseHandle(hToken);
+    }
+}
+
+
+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;
+
+                    case IDC_UPDATEDRIVER:
+                        UpdateDriver(hwndDlg, 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
+SetListViewText(HWND hwnd,
+                INT iItem,
+                LPWSTR lpText)
+{
+    LVITEM li;
+
+    li.mask = LVIF_TEXT | LVIF_STATE;
+    li.iItem = iItem;
+    li.iSubItem = 0;
+    li.state = 0; //(li.iItem == 0 ? LVIS_SELECTED : 0);
+    li.stateMask = LVIS_SELECTED;
+    li.pszText = lpText;
+    (void)ListView_InsertItem(hwnd,
+                              &li);
+}
+
+
+static VOID
+UpdateDetailsDlg(IN HWND hwndDlg,
+                 IN PDEVADVPROP_INFO dap)
+{
+    HWND hwndComboBox;
+    HWND hwndListView;
+    LV_COLUMN lvc;
+    RECT rcClient;
+
+    UINT i;
+    UINT Properties[] =
+    {
+        IDS_PROP_DEVICEID,
+        IDS_PROP_HARDWAREIDS,
+        IDS_PROP_COMPATIBLEIDS,
+        IDS_PROP_MATCHINGDEVICEID,
+        IDS_PROP_SERVICE,
+        IDS_PROP_ENUMERATOR,
+        IDS_PROP_CAPABILITIES,
+        IDS_PROP_DEVNODEFLAGS,
+        IDS_PROP_CONFIGFLAGS,
+        IDS_PROP_CSCONFIGFLAGS,
+        IDS_PROP_EJECTIONRELATIONS,
+        IDS_PROP_REMOVALRELATIONS,
+        IDS_PROP_BUSRELATIONS,
+        IDS_PROP_DEVUPPERFILTERS,
+        IDS_PROP_DEVLOWERFILTERS,
+        IDS_PROP_CLASSUPPERFILTERS,
+        IDS_PROP_CLASSLOWERFILTERS,
+        IDS_PROP_CLASSINSTALLER,
+        IDS_PROP_CLASSCOINSTALLER,
+        IDS_PROP_DEVICECOINSTALLER,
+        IDS_PROP_FIRMWAREREVISION,
+        IDS_PROP_CURRENTPOWERSTATE,
+        IDS_PROP_POWERCAPABILITIES,
+        IDS_PROP_POWERSTATEMAPPINGS
+    };
+
+
+    /* 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);
+
+
+    hwndComboBox = GetDlgItem(hwndDlg,
+                              IDC_DETAILSPROPNAME);
+
+    hwndListView = GetDlgItem(hwndDlg,
+                              IDC_DETAILSPROPVALUE);
+
+    for (i = 0; i != sizeof(Properties) / sizeof(Properties[0]); i++)
+    {
+        /* fill in the device usage combo box */
+        if (LoadString(hDllInstance,
+                       Properties[i],
+                       dap->szTemp,
+                       sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
+        {
+            SendMessage(hwndComboBox,
+                        CB_ADDSTRING,
+                        0,
+                        (LPARAM)dap->szTemp);
+        }
+    }
+
+
+    GetClientRect(hwndListView,
+                  &rcClient);
+
+    /* add a column to the list view control */
+    lvc.mask = LVCF_FMT | LVCF_WIDTH;
+    lvc.fmt = LVCFMT_LEFT;
+    lvc.cx = rcClient.right;
+    (void)ListView_InsertColumn(hwndListView,
+                                0,
+                                &lvc);
+
+    SendMessage(hwndComboBox,
+                CB_SETCURSEL,
+                0,
+                0);
+
+    SetListViewText(hwndListView, 0, dap->szDeviceID);
+
+    SetFocus(hwndComboBox);
+}
+
+
+static VOID
+DisplayDevicePropertyText(IN PDEVADVPROP_INFO dap,
+                          IN HWND hwndListView,
+                          IN DWORD dwProperty)
+{
+    HDEVINFO DeviceInfoSet;
+    PSP_DEVINFO_DATA DeviceInfoData;
+    DWORD dwType;
+    DWORD dwSize;
+    DWORD dwValue;
+    LPBYTE lpBuffer;
+    LPWSTR lpStr;
+    INT len;
+    INT index;
+
+    if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
+    {
+        DeviceInfoSet = dap->CurrentDeviceInfoSet;
+        DeviceInfoData = &dap->CurrentDeviceInfoData;
+    }
+    else
+    {
+        DeviceInfoSet = dap->DeviceInfoSet;
+        DeviceInfoData = &dap->DeviceInfoData;
+    }
+
+    dwSize = 0;
+    SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
+                                     DeviceInfoData,
+                                     dwProperty,
+                                     &dwType,
+                                     NULL,
+                                     0,
+                                     &dwSize);
+    if (dwSize == 0)
+    {
+        if (GetLastError() != ERROR_FILE_NOT_FOUND)
+        {
+            swprintf(dap->szTemp, L"Error: Getting the size failed! (Error: %ld)", GetLastError());
+            SetListViewText(hwndListView, 0, dap->szTemp);
+        }
+        return;
+    }
+
+    if (dwType == REG_SZ)
+        dwSize += sizeof(WCHAR);
+
+    lpBuffer = HeapAlloc(GetProcessHeap(),
+                         HEAP_ZERO_MEMORY,
+                         dwSize);
+    if (lpBuffer == NULL)
+    {
+        SetListViewText(hwndListView, 0, L"Error: Allocating the buffer failed!");
+        return;
+    }
+
+    if (SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
+                                         DeviceInfoData,
+                                         dwProperty,
+                                         &dwType,
+                                         lpBuffer,
+                                         dwSize,
+                                         &dwSize))
+    {
+        if (dwType == REG_SZ)
+        {
+            SetListViewText(hwndListView, 0, (LPWSTR)lpBuffer);
+        }
+        else if (dwType == REG_MULTI_SZ)
+        {
+            lpStr = (LPWSTR)lpBuffer;
+            index = 0;
+            while (*lpStr != 0)
+            {
+                len = wcslen(lpStr) + 1;
+
+                SetListViewText(hwndListView, index, lpStr);
+
+                lpStr += len;
+                index++;
+            }
+        }
+        else if (dwType == REG_DWORD)
+        {
+            dwValue = *(DWORD *) lpBuffer;
+
+            switch (dwProperty)
+            {
+                case SPDRP_CAPABILITIES:
+                    index = 0;
+                    if (dwValue & CM_DEVCAP_LOCKSUPPORTED)
+                        SetListViewText(hwndListView, index++, L"CM_DEVCAP_LOCKSUPPORTED");
+                    if (dwValue & CM_DEVCAP_EJECTSUPPORTED)
+                        SetListViewText(hwndListView, index++, L"CM_DEVCAP_EJECTSUPPORTED");
+                    if (dwValue & CM_DEVCAP_REMOVABLE)
+                        SetListViewText(hwndListView, index++, L"CM_DEVCAP_REMOVABLE");
+                    if (dwValue & CM_DEVCAP_DOCKDEVICE)
+                        SetListViewText(hwndListView, index++, L"CM_DEVCAP_DOCKDEVICE");
+                    if (dwValue & CM_DEVCAP_UNIQUEID)
+                        SetListViewText(hwndListView, index++, L"CM_DEVCAP_UNIQUEID");
+                    if (dwValue & CM_DEVCAP_SILENTINSTALL)
+                        SetListViewText(hwndListView, index++, L"CM_DEVCAP_SILENTINSTALL");
+                    if (dwValue & CM_DEVCAP_RAWDEVICEOK)
+                        SetListViewText(hwndListView, index++, L"CM_DEVCAP_RAWDEVICEOK");
+                    if (dwValue & CM_DEVCAP_SURPRISEREMOVALOK)
+                        SetListViewText(hwndListView, index++, L"CM_DEVCAP_SURPRISEREMOVALOK");
+                    if (dwValue & CM_DEVCAP_HARDWAREDISABLED)
+                        SetListViewText(hwndListView, index++, L"CM_DEVCAP_HARDWAREDISABLED");
+                    if (dwValue & CM_DEVCAP_NONDYNAMIC)
+                        SetListViewText(hwndListView, index++, L"CM_DEVCAP_NONDYNAMIC");
+                    break;
+
+                case SPDRP_CONFIGFLAGS:
+                    index = 0;
+                    if (dwValue & CONFIGFLAG_DISABLED)
+                        SetListViewText(hwndListView, index++, L"CONFIGFLAG_DISABLED");
+                    if (dwValue & CONFIGFLAG_REMOVED)
+                        SetListViewText(hwndListView, index++, L"CONFIGFLAG_REMOVED");
+                    if (dwValue & CONFIGFLAG_MANUAL_INSTALL)
+                        SetListViewText(hwndListView, index++, L"CONFIGFLAG_MANUAL_INSTALL");
+                    if (dwValue & CONFIGFLAG_IGNORE_BOOT_LC)
+                        SetListViewText(hwndListView, index++, L"CONFIGFLAG_IGNORE_BOOT_LC");
+                    if (dwValue & CONFIGFLAG_NET_BOOT)
+                        SetListViewText(hwndListView, index++, L"CONFIGFLAG_NET_BOOT");
+                    if (dwValue & CONFIGFLAG_REINSTALL)
+                        SetListViewText(hwndListView, index++, L"CONFIGFLAG_REINSTALL");
+                    if (dwValue & CONFIGFLAG_FAILEDINSTALL)
+                        SetListViewText(hwndListView, index++, L"CONFIGFLAG_FAILEDINSTALL");
+                    if (dwValue & CONFIGFLAG_CANTSTOPACHILD)
+                        SetListViewText(hwndListView, index++, L"CONFIGFLAG_CANTSTOPACHILD");
+                    if (dwValue & CONFIGFLAG_OKREMOVEROM)
+                        SetListViewText(hwndListView, index++, L"CONFIGFLAG_OKREMOVEROM");
+                    if (dwValue & CONFIGFLAG_NOREMOVEEXIT)
+                        SetListViewText(hwndListView, index++, L"CONFIGFLAG_NOREMOVEEXIT");
+                    break;
+
+                default:
+                    swprintf(dap->szTemp, L"0x%08lx", dwValue);
+                    SetListViewText(hwndListView, 0, dap->szTemp);
+                    break;
+            }
+        }
+        else
+        {
+            SetListViewText(hwndListView, 0, L"Error: Unsupported value type!");
+
+        }
+    }
+    else
+    {
+        SetListViewText(hwndListView, 0, L"Error: Retrieving the value failed!");
+    }
+
+    HeapFree(GetProcessHeap(),
+             0,
+             lpBuffer);
+}
+
+static VOID
+DisplayDevNodeFlags(IN PDEVADVPROP_INFO dap,
+                    IN HWND hwndListView)
+{
+    DWORD dwStatus = 0;
+    DWORD dwProblem = 0;
+    INT index;
+
+    CM_Get_DevNode_Status_Ex(&dwStatus,
+                             &dwProblem,
+                             dap->DeviceInfoData.DevInst,
+                             0,
+                             dap->hMachine);
+
+    index = 0;
+    if (dwStatus & DN_ROOT_ENUMERATED)
+        SetListViewText(hwndListView, index++, L"DN_ROOT_ENUMERATED");
+    if (dwStatus & DN_DRIVER_LOADED)
+        SetListViewText(hwndListView, index++, L"DN_DRIVER_LOADED");
+    if (dwStatus & DN_ENUM_LOADED)
+        SetListViewText(hwndListView, index++, L"DN_ENUM_LOADED");
+    if (dwStatus & DN_STARTED)
+        SetListViewText(hwndListView, index++, L"DN_STARTED");
+    if (dwStatus & DN_MANUAL)
+        SetListViewText(hwndListView, index++, L"DN_MANUAL");
+    if (dwStatus & DN_NEED_TO_ENUM)
+        SetListViewText(hwndListView, index++, L"DN_NEED_TO_ENUM");
+    if (dwStatus & DN_DRIVER_BLOCKED)
+        SetListViewText(hwndListView, index++, L"DN_DRIVER_BLOCKED");
+    if (dwStatus & DN_HARDWARE_ENUM)
+        SetListViewText(hwndListView, index++, L"DN_HARDWARE_ENUM");
+    if (dwStatus & DN_NEED_RESTART)
+        SetListViewText(hwndListView, index++, L"DN_NEED_RESTART");
+    if (dwStatus & DN_CHILD_WITH_INVALID_ID)
+        SetListViewText(hwndListView, index++, L"DN_CHILD_WITH_INVALID_ID");
+    if (dwStatus & DN_HAS_PROBLEM)
+        SetListViewText(hwndListView, index++, L"DN_HAS_PROBLEM");
+    if (dwStatus & DN_FILTERED)
+        SetListViewText(hwndListView, index++, L"DN_FILTERED");
+    if (dwStatus & DN_LEGACY_DRIVER)
+        SetListViewText(hwndListView, index++, L"DN_LEGACY_DRIVER");
+    if (dwStatus & DN_DISABLEABLE)
+        SetListViewText(hwndListView, index++, L"DN_DISABLEABLE");
+    if (dwStatus & DN_REMOVABLE)
+        SetListViewText(hwndListView, index++, L"DN_REMOVABLE");
+    if (dwStatus & DN_PRIVATE_PROBLEM)
+        SetListViewText(hwndListView, index++, L"DN_PRIVATE_PROBLEM");
+    if (dwStatus & DN_MF_PARENT)
+        SetListViewText(hwndListView, index++, L"DN_MF_PARENT");
+    if (dwStatus & DN_MF_CHILD)
+        SetListViewText(hwndListView, index++, L"DN_MF_CHILD");
+    if (dwStatus & DN_WILL_BE_REMOVED)
+        SetListViewText(hwndListView, index++, L"DN_WILL_BE_REMOVED");
+
+    if (dwStatus & DN_NOT_FIRST_TIMEE)
+        SetListViewText(hwndListView, index++, L"DN_NOT_FIRST_TIMEE");
+    if (dwStatus & DN_STOP_FREE_RES)
+        SetListViewText(hwndListView, index++, L"DN_STOP_FREE_RES");
+    if (dwStatus & DN_REBAL_CANDIDATE)
+        SetListViewText(hwndListView, index++, L"DN_REBAL_CANDIDATE");
+    if (dwStatus & DN_BAD_PARTIAL)
+        SetListViewText(hwndListView, index++, L"DN_BAD_PARTIAL");
+    if (dwStatus & DN_NT_ENUMERATOR)
+        SetListViewText(hwndListView, index++, L"DN_NT_ENUMERATOR");
+    if (dwStatus & DN_NT_DRIVER)
+        SetListViewText(hwndListView, index++, L"DN_NT_DRIVER");
+
+    if (dwStatus & DN_NEEDS_LOCKING)
+        SetListViewText(hwndListView, index++, L"DN_NEEDS_LOCKING");
+    if (dwStatus & DN_ARM_WAKEUP)
+        SetListViewText(hwndListView, index++, L"DN_ARM_WAKEUP");
+    if (dwStatus & DN_APM_ENUMERATOR)
+        SetListViewText(hwndListView, index++, L"DN_APM_ENUMERATOR");
+    if (dwStatus & DN_APM_DRIVER)
+        SetListViewText(hwndListView, index++, L"DN_APM_DRIVER");
+    if (dwStatus & DN_SILENT_INSTALL)
+        SetListViewText(hwndListView, index++, L"DN_SILENT_INSTALL");
+    if (dwStatus & DN_NO_SHOW_IN_DM)
+        SetListViewText(hwndListView, index++, L"DN_NO_SHOW_IN_DM");
+    if (dwStatus & DN_BOOT_LOG_PROB)
+        SetListViewText(hwndListView, index++, L"DN_BOOT_LOG_PROB");
+
+//    swprintf(dap->szTemp, L"0x%08x", dwStatus);
+//    SetListViewText(hwndListView, 0, dap->szTemp);
+}
+
+
+static VOID
+DisplayDevNodeEnumerator(IN PDEVADVPROP_INFO dap,
+                         IN HWND hwndListView)
+{
+    PSP_DEVINFO_DATA DeviceInfoData;
+
+    DWORD dwType = 0;
+    WCHAR szBuffer[256];
+    DWORD dwSize = 256 * sizeof(WCHAR);
+
+    if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
+    {
+        DeviceInfoData = &dap->CurrentDeviceInfoData;
+    }
+    else
+    {
+        DeviceInfoData = &dap->DeviceInfoData;
+    }
+
+    CM_Get_DevNode_Registry_Property_ExW(DeviceInfoData->DevInst,
+                                         CM_DRP_ENUMERATOR_NAME,
+                                         &dwType,
+                                         &szBuffer,
+                                         &dwSize,
+                                         0,
+                                         dap->hMachine);
+
+    SetListViewText(hwndListView, 0, szBuffer);
+}
+
+
+static VOID
+DisplayCsFlags(IN PDEVADVPROP_INFO dap,
+               IN HWND hwndListView)
+{
+    DWORD dwValue = 0;
+    INT index;
+
+    CM_Get_HW_Prof_Flags_Ex(dap->szDevName,
+                            0, /* current hardware profile */
+                            &dwValue,
+                            0,
+                            dap->hMachine);
+
+    index = 0;
+    if (dwValue & CSCONFIGFLAG_DISABLED)
+        SetListViewText(hwndListView, index++, L"CSCONFIGFLAG_DISABLED");
+
+    if (dwValue & CSCONFIGFLAG_DO_NOT_CREATE)
+        SetListViewText(hwndListView, index++, L"CSCONFIGFLAG_DO_NOT_CREATE");
+
+    if (dwValue & CSCONFIGFLAG_DO_NOT_START)
+        SetListViewText(hwndListView, index++, L"CSCONFIGFLAG_DO_NOT_START");
+}
+
+
+static VOID
+DisplayMatchingDeviceId(IN PDEVADVPROP_INFO dap,
+                        IN HWND hwndListView)
+{
+    HDEVINFO DeviceInfoSet;
+    PSP_DEVINFO_DATA DeviceInfoData;
+    WCHAR szBuffer[256];
+    HKEY hKey;
+    DWORD dwSize;
+    DWORD dwType;
+
+    if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
+    {
+        DeviceInfoSet = dap->CurrentDeviceInfoSet;
+        DeviceInfoData = &dap->CurrentDeviceInfoData;
+    }
+    else
+    {
+        DeviceInfoSet = dap->DeviceInfoSet;
+        DeviceInfoData = &dap->DeviceInfoData;
+    }
+
+    hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
+                                DeviceInfoData,
+                                DICS_FLAG_GLOBAL,
+                                0,
+                                DIREG_DRV,
+                                KEY_QUERY_VALUE);
+    if (hKey != INVALID_HANDLE_VALUE)
+    {
+        dwSize = 256 * sizeof(WCHAR);
+        if (RegQueryValueEx(hKey,
+                            L"MatchingDeviceId",
+                            NULL,
+                            &dwType,
+                            (LPBYTE)szBuffer,
+                            &dwSize) == ERROR_SUCCESS)
+        {
+            SetListViewText(hwndListView, 0, szBuffer);
+        }
+
+        RegCloseKey(hKey);
+    }
+}
+
+
+static VOID
+DisplayClassCoinstallers(IN PDEVADVPROP_INFO dap,
+                          IN HWND hwndListView)
+{
+    HDEVINFO DeviceInfoSet;
+    PSP_DEVINFO_DATA DeviceInfoData;
+    WCHAR szClassGuid[45];
+    HKEY hKey = INVALID_HANDLE_VALUE;
+    DWORD dwSize;
+    DWORD dwType;
+    LPBYTE lpBuffer = NULL;
+    LPWSTR lpStr;
+    INT index;
+    INT len;
+    LONG lError;
+
+    if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
+    {
+        DeviceInfoSet = dap->CurrentDeviceInfoSet;
+        DeviceInfoData = &dap->CurrentDeviceInfoData;
+    }
+    else
+    {
+        DeviceInfoSet = dap->DeviceInfoSet;
+        DeviceInfoData = &dap->DeviceInfoData;
+    }
+
+    dwSize = 45 * sizeof(WCHAR);
+    if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
+                                          DeviceInfoData,
+                                          SPDRP_CLASSGUID,
+                                          &dwType,
+                                          (LPBYTE)szClassGuid,
+                                          dwSize,
+                                          &dwSize))
+        return;
+
+    lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+                           L"SYSTEM\\CurrentControlSet\\Control\\CoDeviceInstallers",
+                           0,
+                           GENERIC_READ,
+                           &hKey);
+    if (lError != ERROR_SUCCESS)
+        return;
+
+    dwSize = 0;
+    lError = RegQueryValueEx(hKey,
+                             szClassGuid,
+                             NULL,
+                             &dwType,
+                             NULL,
+                             &dwSize);
+    if (lError != ERROR_SUCCESS)
+        goto done;
+
+    if (dwSize == 0)
+        goto done;
+
+    lpBuffer = HeapAlloc(GetProcessHeap(),
+                         HEAP_ZERO_MEMORY,
+                         dwSize);
+
+    RegQueryValueEx(hKey,
+                    szClassGuid,
+                    NULL,
+                    &dwType,
+                    lpBuffer,
+                    &dwSize);
+
+    lpStr = (LPWSTR)lpBuffer;
+    index = 0;
+    while (*lpStr != 0)
+    {
+        len = wcslen(lpStr) + 1;
+
+        SetListViewText(hwndListView, index, lpStr);
+
+        lpStr += len;
+        index++;
+    }
+
+done:
+    if (lpBuffer != NULL)
+        HeapFree(GetProcessHeap(), 0, lpBuffer);
+
+    if (hKey != INVALID_HANDLE_VALUE)
+        RegCloseKey(hKey);
+}
+
+
+static VOID
+DisplayDeviceCoinstallers(IN PDEVADVPROP_INFO dap,
+                          IN HWND hwndListView)
+{
+    HDEVINFO DeviceInfoSet;
+    PSP_DEVINFO_DATA DeviceInfoData;
+    HKEY hKey;
+    DWORD dwSize;
+    DWORD dwType;
+    LPBYTE lpBuffer;
+    LPWSTR lpStr;
+    INT index;
+    INT len;
+
+    if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
+    {
+        DeviceInfoSet = dap->CurrentDeviceInfoSet;
+        DeviceInfoData = &dap->CurrentDeviceInfoData;
+    }
+    else
+    {
+        DeviceInfoSet = dap->DeviceInfoSet;
+        DeviceInfoData = &dap->DeviceInfoData;
+    }
+
+    hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
+                                DeviceInfoData,
+                                DICS_FLAG_GLOBAL,
+                                0,
+                                DIREG_DRV,
+                                KEY_QUERY_VALUE);
+    if (hKey != INVALID_HANDLE_VALUE)
+    {
+        dwSize = 0;
+        if (RegQueryValueEx(hKey,
+                            L"CoInstallers32",
+                            NULL,
+                            &dwType,
+                            NULL,
+                            &dwSize) == ERROR_SUCCESS &&
+            dwSize > 0)
+        {
+
+            lpBuffer = HeapAlloc(GetProcessHeap(),
+                                 HEAP_ZERO_MEMORY,
+                                 dwSize);
+
+            RegQueryValueEx(hKey,
+                            L"CoInstallers32",
+                            NULL,
+                            &dwType,
+                            lpBuffer,
+                            &dwSize);
+
+            lpStr = (LPWSTR)lpBuffer;
+            index = 0;
+            while (*lpStr != 0)
+            {
+                len = wcslen(lpStr) + 1;
+
+                SetListViewText(hwndListView, index, lpStr);
+
+                lpStr += len;
+                index++;
+            }
+
+            HeapFree(GetProcessHeap(),
+                     0,
+                     lpBuffer);
+        }
+
+        RegCloseKey(hKey);
+    }
+}
+
+
+static VOID
+DisplayClassProperties(IN PDEVADVPROP_INFO dap,
+                       IN HWND hwndListView,
+                       IN LPWSTR lpProperty)
+{
+    HDEVINFO DeviceInfoSet;
+    PSP_DEVINFO_DATA DeviceInfoData;
+    WCHAR szClassGuid[45];
+    DWORD dwSize;
+    DWORD dwType;
+    HKEY hKey;
+    GUID ClassGuid;
+    LPBYTE lpBuffer;
+    LPWSTR lpStr;
+    INT index = 0;
+    INT len;
+
+    if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
+    {
+        DeviceInfoSet = dap->CurrentDeviceInfoSet;
+        DeviceInfoData = &dap->CurrentDeviceInfoData;
+    }
+    else
+    {
+        DeviceInfoSet = dap->DeviceInfoSet;
+        DeviceInfoData = &dap->DeviceInfoData;
+    }
+
+    dwSize = 45 * sizeof(WCHAR);
+    if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
+                                          DeviceInfoData,
+                                          SPDRP_CLASSGUID,
+                                          &dwType,
+                                          (LPBYTE)szClassGuid,
+                                          dwSize,
+                                          &dwSize))
+        return;
+
+    pSetupGuidFromString(szClassGuid,
+                         &ClassGuid);
+
+    hKey = SetupDiOpenClassRegKey(&ClassGuid,
+                                  KEY_QUERY_VALUE);
+    if (hKey != INVALID_HANDLE_VALUE)
+    {
+        dwSize = 0;
+        if (RegQueryValueEx(hKey,
+                            lpProperty,
+                            NULL,
+                            &dwType,
+                            NULL,
+                            &dwSize) == ERROR_SUCCESS &&
+            dwSize > 0)
+        {
+            lpBuffer = HeapAlloc(GetProcessHeap(),
+                                 HEAP_ZERO_MEMORY,
+                                 dwSize);
+
+            RegQueryValueEx(hKey,
+                            lpProperty,
+                            NULL,
+                            &dwType,
+                            lpBuffer,
+                            &dwSize);
+
+            if (dwType == REG_SZ)
+            {
+                SetListViewText(hwndListView, 0, (LPWSTR)lpBuffer);
+            }
+            else if (dwType == REG_MULTI_SZ)
+            {
+                lpStr = (LPWSTR)lpBuffer;
+                index = 0;
+                while (*lpStr != 0)
+                {
+                    len = wcslen(lpStr) + 1;
+
+                    SetListViewText(hwndListView, index, lpStr);
+
+                    lpStr += len;
+                    index++;
+                }
+            }
+
+            HeapFree(GetProcessHeap(),
+                     0,
+                     lpBuffer);
+        }
+
+        RegCloseKey(hKey);
+    }
+}
+
+
+static VOID
+DisplayDeviceRelations(
+    IN PDEVADVPROP_INFO dap,
+    IN HWND hwndListView,
+    IN ULONG ulFlags)
+{
+    ULONG ulLength = 0;
+    LPWSTR pszBuffer = NULL, pszStr;
+    INT index = 0, len;
+
+    CONFIGRET ret;
+
+    ret = CM_Get_Device_ID_List_Size_ExW(&ulLength,
+                                         dap->szDeviceID,
+                                         ulFlags,
+                                         NULL);
+    if (ret != CR_SUCCESS)
+        return;
+
+    pszBuffer = HeapAlloc(GetProcessHeap(),
+                          HEAP_ZERO_MEMORY,
+                          ulLength);
+    if (pszBuffer == NULL)
+        return;
+
+    ret = CM_Get_Device_ID_List_ExW(dap->szDeviceID,
+                                    pszBuffer,
+                                    ulLength,
+                                    ulFlags,
+                                    NULL);
+    if (ret != CR_SUCCESS)
+    {
+        HeapFree(GetProcessHeap(), 0, pszBuffer);
+        return;
+    }
+
+    pszStr = pszBuffer;
+    index = 0;
+    while (*pszStr != 0)
+    {
+        len = wcslen(pszStr) + 1;
+
+        SetListViewText(hwndListView, index, pszStr);
+
+        pszStr += len;
+        index++;
+    }
+
+    HeapFree(GetProcessHeap(), 0, pszBuffer);
+}
+
+
+static VOID
+DisplayDeviceProperties(IN PDEVADVPROP_INFO dap,
+                        IN HWND hwndComboBox,
+                        IN HWND hwndListView)
+{
+    INT Index;
+
+    Index = (INT)SendMessage(hwndComboBox,
+                             CB_GETCURSEL,
+                             0,
+                             0);
+    if (Index == CB_ERR)
+        return;
+
+    (void)ListView_DeleteAllItems(hwndListView);
+
+    switch (Index)
+    {
+        case 0:
+            SetListViewText(hwndListView, 0, dap->szDeviceID);
+            break;
+
+        case 1: /* Hardware ID */
+            DisplayDevicePropertyText(dap,
+                                      hwndListView,
+                                      SPDRP_HARDWAREID);
+            break;
+
+        case 2: /* Compatible IDs */
+            DisplayDevicePropertyText(dap,
+                                      hwndListView,
+                                      SPDRP_COMPATIBLEIDS);
+            break;
+
+        case 3: /* Matching ID */
+            DisplayMatchingDeviceId(dap,
+                                    hwndListView);
+            break;
+
+        case 4: /* Service */
+            DisplayDevicePropertyText(dap,
+                                      hwndListView,
+                                      SPDRP_SERVICE);
+            break;
+
+        case 5: /* Enumerator */
+            DisplayDevNodeEnumerator(dap,
+                                     hwndListView);
+            break;
+
+        case 6: /* Capabilities */
+            DisplayDevicePropertyText(dap,
+                                      hwndListView,
+                                      SPDRP_CAPABILITIES);
+            break;
+
+        case 7: /* Devnode Flags */
+            DisplayDevNodeFlags(dap,
+                                hwndListView);
+            break;
+
+        case 8: /* Config Flags */
+            DisplayDevicePropertyText(dap,
+                                      hwndListView,
+                                      SPDRP_CONFIGFLAGS);
+            break;
+
+        case 9: /* CSConfig Flags */
+            DisplayCsFlags(dap,
+                           hwndListView);
+            break;
+
+        case 10: /* Ejection relation */
+            DisplayDeviceRelations(dap,
+                                   hwndListView,
+                                   CM_GETIDLIST_FILTER_EJECTRELATIONS);
+            break;
+
+        case 11: /* Removal relations */
+            DisplayDeviceRelations(dap,
+                                   hwndListView,
+                                   CM_GETIDLIST_FILTER_REMOVALRELATIONS);
+            break;
+
+        case 12: /* Bus relation */
+            DisplayDeviceRelations(dap,
+                                   hwndListView,
+                                   CM_GETIDLIST_FILTER_BUSRELATIONS);
+            break;
+
+        case 13: /* Device Upper Filters */
+            DisplayDevicePropertyText(dap,
+                                      hwndListView,
+                                      SPDRP_UPPERFILTERS);
+            break;
+
+        case 14: /* Device Lower Filters */
+            DisplayDevicePropertyText(dap,
+                                      hwndListView,
+                                      SPDRP_LOWERFILTERS);
+            break;
+
+        case 15: /* Class Upper Filters */
+            DisplayClassProperties(dap,
+                                   hwndListView,
+                                   L"UpperFilters");
+            break;
+
+        case 16: /* Class Lower Filters */
+            DisplayClassProperties(dap,
+                                   hwndListView,
+                                   L"LowerFilters");
+            break;
+
+        case 17: /* Class Installer */
+            DisplayClassProperties(dap,
+                                   hwndListView,
+                                   L"Installer32");
+            break;
+
+        case 18: /* Class Coinstaller */
+            DisplayClassCoinstallers(dap,
+                                     hwndListView);
+            break;
+
+        case 19: /* Device Coinstaller */
+            DisplayDeviceCoinstallers(dap,
+                                      hwndListView);
+            break;
+
+#if 0
+        case 20: /* Firmware Revision */
+            break;
+
+        case 21: /* Current Power State */
+            break;
+
+        case 20: /* Power Capabilities */
+            break;
+
+        case 21: /* Power State Mappings */
+            break;
+#endif
+
+        default:
+            SetListViewText(hwndListView, 0, L"<Not implemented yet>");
+            break;
+    }
+}
+
+
+static INT_PTR
+CALLBACK
+AdvProcDetailsDlgProc(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_DETAILSPROPNAME:
+                        if (HIWORD(wParam) == CBN_SELCHANGE)
+                        {
+                            DisplayDeviceProperties(dap,
+                                                    GetDlgItem(hwndDlg, IDC_DETAILSPROPNAME),
+                                                    GetDlgItem(hwndDlg, IDC_DETAILSPROPVALUE));
+                        }
+                        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);
+
+                    UpdateDetailsDlg(hwndDlg,
+                                     dap);
+                }
+                Ret = TRUE;
+                break;
+            }
+        }
+    }
+
+    return Ret;
+}
+
+
+static VOID
+InitDevUsageActions(IN HWND hwndDlg,
+                    IN HWND hComboBox,
+                    IN PDEVADVPROP_INFO dap)
+{
+    INT Index;
+    UINT i;
+    UINT Actions[] =
+    {
+        IDS_ENABLEDEVICE,
+        IDS_DISABLEDEVICE,
+    };
+
+    for (i = 0;
+         i != sizeof(Actions) / sizeof(Actions[0]);
+         i++)
+    {
+        /* fill in the device usage combo box */
+        if (LoadString(hDllInstance,
+                       Actions[i],
+                       dap->szTemp,
+                       sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
+        {
+            Index = (INT)SendMessage(hComboBox,
+                                     CB_ADDSTRING,
+                                     0,
+                                     (LPARAM)dap->szTemp);
+            if (Index != CB_ERR)
+            {
+                SendMessage(hComboBox,
+                            CB_SETITEMDATA,
+                            (WPARAM)Index,
+                            (LPARAM)Actions[i]);
+
+                switch (Actions[i])
+                {
+                    case IDS_ENABLEDEVICE:
+                        if (dap->DeviceStarted)
+                        {
+                            SendMessage(hComboBox,
+                                        CB_SETCURSEL,
+                                        (WPARAM)Index,
+                                        0);
+                        }
+                        break;
+
+                    case IDS_DISABLEDEVICE:
+                        if (!dap->DeviceStarted)
+                        {
+                            SendMessage(hComboBox,
+                                        CB_SETCURSEL,
+                                        (WPARAM)Index,
+                                        0);
+                        }
+                        break;
+
+                    default:
+                        break;
+                }
+            }
+        }
+    }
+}
+
+
+static UINT
+GetSelectedUsageAction(IN HWND hComboBox)
+{
+    INT Index;
+    UINT Ret = 0;
+
+    Index = (INT)SendMessage(hComboBox,
+                             CB_GETCURSEL,
+                             0,
+                             0);
+    if (Index != CB_ERR)
+    {
+        INT iRet = (INT) SendMessage(hComboBox,
+                               CB_GETITEMDATA,
+                               (WPARAM)Index,
+                               0);
+        if (iRet != CB_ERR)
+        {
+            Ret = (UINT)iRet;
+        }
+    }
+
+    return Ret;
+}
+
+
+static BOOL
+ApplyGeneralSettings(IN HWND hwndDlg,
+                     IN PDEVADVPROP_INFO dap)
+{
+    BOOL Ret = FALSE;
+
+    if (dap->DeviceUsageChanged && dap->IsAdmin && dap->CanDisable)
+    {
+        UINT SelectedUsageAction;
+        BOOL NeedReboot = FALSE;
+
+        SelectedUsageAction = GetSelectedUsageAction(GetDlgItem(hwndDlg,
+                                                                IDC_DEVUSAGE));
+        switch (SelectedUsageAction)
+        {
+            case IDS_ENABLEDEVICE:
+                if (!dap->DeviceStarted)
+                {
+                    Ret = EnableDevice(dap->DeviceInfoSet,
+                                       &dap->DeviceInfoData,
+                                       TRUE,
+                                       0,
+                                       &NeedReboot);
+                }
+                break;
+
+            case IDS_DISABLEDEVICE:
+                if (dap->DeviceStarted)
+                {
+                    Ret = EnableDevice(dap->DeviceInfoSet,
+                                       &dap->DeviceInfoData,
+                                       FALSE,
+                                       0,
+                                       &NeedReboot);
+                }
+                break;
+
+            default:
+                break;
+        }
+
+        if (Ret)
+        {
+            if (NeedReboot)
+            {
+                /* make PropertySheet() return PSM_REBOOTSYSTEM */
+                PropSheet_RebootSystem(hwndDlg);
+            }
+        }
+        else
+        {
+            /* FIXME - display an error message */
+            FIXME("Failed to enable/disable device! LastError: %d\n",
+                  GetLastError());
+        }
+    }
+    else
+        Ret = !dap->DeviceUsageChanged;
+
+    /* disable the apply button */
+    PropSheet_UnChanged(GetParent(hwndDlg),
+                        hwndDlg);
+    dap->DeviceUsageChanged = FALSE;
+    return Ret;
+}
+
+
+static VOID
+UpdateDevInfo(IN HWND hwndDlg,
+              IN PDEVADVPROP_INFO dap,
+              IN BOOL ReOpen)
+{
+    HWND hDevUsage, hPropSheetDlg, hDevProbBtn;
+    CONFIGRET cr;
+    ULONG Status, ProblemNumber;
+    SP_DEVINSTALL_PARAMS_W InstallParams;
+    UINT TroubleShootStrId = IDS_TROUBLESHOOTDEV;
+    BOOL bFlag, bDevActionAvailable = TRUE;
+    BOOL bDrvInstalled = FALSE;
+    DWORD iPage;
+    HDEVINFO DeviceInfoSet = NULL;
+    PSP_DEVINFO_DATA DeviceInfoData = NULL;
+    PROPSHEETHEADER psh;
+    DWORD nDriverPages = 0;
+    BOOL RecalcPages = FALSE;
+
+    TRACE("UpdateDevInfo()\n");
+
+    hPropSheetDlg = GetParent(hwndDlg);
+
+    if (dap->PageInitialized)
+    {
+        /* switch to the General page */
+        PropSheet_SetCurSelByID(hPropSheetDlg,
+                                IDD_DEVICEGENERAL);
+
+        /* remove and destroy the existing device property sheet pages */
+        if (dap->DevPropSheets != NULL)
+        {
+            for (iPage = 0;
+                 iPage != dap->nDevPropSheets;
+                 iPage++)
+            {
+                if (dap->DevPropSheets[iPage] != NULL)
+                {
+                    PropSheet_RemovePage(hPropSheetDlg,
+                                         (WPARAM) -1,
+                                         dap->DevPropSheets[iPage]);
+                    RecalcPages = TRUE;
+                }
+            }
+        }
+    }
+
+    iPage = 0;
+
+    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;
+
+    if (ReOpen)
+    {
+        /* create a new device info set and re-open the device */
+        if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
+        {
+            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->CurrentDeviceInfoData))
+            {
+                if (dap->CloseDevInst)
+                {
+                    SetupDiDestroyDeviceInfoList(dap->DeviceInfoSet);
+                }
+
+                dap->CloseDevInst = TRUE;
+                dap->DeviceInfoSet = dap->CurrentDeviceInfoSet;
+                dap->DeviceInfoData = dap->CurrentDeviceInfoData;
+                dap->CurrentDeviceInfoSet = INVALID_HANDLE_VALUE;
+            }
+            else
+                goto GetParentNode;
+        }
+        else
+        {
+GetParentNode:
+            /* get the parent node from the initial devinst */
+            CM_Get_Parent_Ex(&dap->ParentDevInst,
+                             dap->DeviceInfoData.DevInst,
+                             0,
+                             dap->hMachine);
+        }
+
+        if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
+        {
+            DeviceInfoSet = dap->CurrentDeviceInfoSet;
+            DeviceInfoData = &dap->CurrentDeviceInfoData;
+        }
+        else
+        {
+            DeviceInfoSet = dap->DeviceInfoSet;
+            DeviceInfoData = &dap->DeviceInfoData;
+        }
+    }
+    else
+    {
+        DeviceInfoSet = dap->DeviceInfoSet;
+        DeviceInfoData = &dap->DeviceInfoData;
+    }
+
+    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))
+        {
+            /* get install params */
+            InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
+            if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet,
+                                                DeviceInfoData,
+                                                &InstallParams))
+            {
+                /* zero the flags */
+                InstallParams.Flags = 0;
+            }
+
+            dap->HasDriverPage = !(InstallParams.Flags & DI_DRIVERPAGE_ADDED);
+            dap->HasResourcePage = !(InstallParams.Flags & DI_RESOURCEPAGE_ADDED);
+            dap->HasPowerPage = !(InstallParams.Flags & DI_FLAGSEX_POWERPAGE_ADDED);
+        }
+    }
+
+    /* get the device icon */
+    if (dap->hDevIcon != NULL)
+    {
+        DestroyIcon(dap->hDevIcon);
+        dap->hDevIcon = NULL;
+    }
+    if (!SetupDiLoadClassIcon(&DeviceInfoData->ClassGuid,
+                              &dap->hDevIcon,
+                              NULL))
+    {
+        dap->hDevIcon = NULL;
+    }
+
+    /* get the device name */
+    if (GetDeviceDescriptionString(DeviceInfoSet,
+                                   DeviceInfoData,
+                                   dap->szDevName,
+                                   sizeof(dap->szDevName) / sizeof(dap->szDevName[0])))
+    {
+        PropSheet_SetTitle(hPropSheetDlg,
+                           PSH_PROPTITLE,
+                           dap->szDevName);
+    }
+
+    /* 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);
+
+    /* set the device type edit control text */
+    if (GetDeviceTypeString(DeviceInfoData,
+                            dap->szTemp,
+                            sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
+    {
+        SetDlgItemText(hwndDlg,
+                       IDC_DEVTYPE,
+                       dap->szTemp);
+    }
+
+    /* set the device manufacturer edit control text */
+    if (GetDeviceManufacturerString(DeviceInfoSet,
+                                    DeviceInfoData,
+                                    dap->szTemp,
+                                    sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
+    {
+        SetDlgItemText(hwndDlg,
+                       IDC_DEVMANUFACTURER,
+                       dap->szTemp);
+    }
+
+    /* set the device location edit control text */
+    if (GetDeviceLocationString(DeviceInfoSet,
+                                DeviceInfoData,
+                                dap->ParentDevInst,
+                                dap->szTemp,
+                                sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
+    {
+        SetDlgItemText(hwndDlg,
+                       IDC_DEVLOCATION,
+                       dap->szTemp);
+    }
+
+    /* set the device status edit control text */
+    if (GetDeviceStatusString(DeviceInfoData->DevInst,
+                              dap->hMachine,
+                              dap->szTemp,
+                              sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
+    {
+        SetDlgItemText(hwndDlg,
+                       IDC_DEVSTATUS,
+                       dap->szTemp);
+    }
+
+    /* set the device troubleshoot button text and disable it if necessary */
+    hDevProbBtn = GetDlgItem(hwndDlg,
+                             IDC_DEVPROBLEM);
+    cr = CM_Get_DevNode_Status_Ex(&Status,
+                                  &ProblemNumber,
+                                  DeviceInfoData->DevInst,
+                                  0,
+                                  dap->hMachine);
+    if (cr == CR_SUCCESS && (Status & DN_HAS_PROBLEM))
+    {
+        switch (ProblemNumber)
+        {
+            case CM_PROB_DEVLOADER_FAILED:
+            {
+                /* FIXME - only if it's not a root bus devloader,
+                           disable the button otherwise */
+                TroubleShootStrId = IDS_UPDATEDRV;
+                break;
+            }
+
+            case CM_PROB_OUT_OF_MEMORY:
+            case CM_PROB_ENTRY_IS_WRONG_TYPE:
+            case CM_PROB_LACKED_ARBITRATOR:
+            case CM_PROB_FAILED_START:
+            case CM_PROB_LIAR:
+            case CM_PROB_UNKNOWN_RESOURCE:
+            {
+                TroubleShootStrId = IDS_UPDATEDRV;
+                break;
+            }
+
+            case CM_PROB_BOOT_CONFIG_CONFLICT:
+            case CM_PROB_NORMAL_CONFLICT:
+            case CM_PROB_REENUMERATION:
+            {
+                /* FIXME - Troubleshoot conflict */
+                break;
+            }
+
+            case CM_PROB_FAILED_FILTER:
+            case CM_PROB_REINSTALL:
+            case CM_PROB_FAILED_INSTALL:
+            {
+                TroubleShootStrId = IDS_REINSTALLDRV;
+                break;
+            }
+
+            case CM_PROB_DEVLOADER_NOT_FOUND:
+            {
+                /* FIXME - 4 cases:
+                   1) if it's a missing system devloader:
+                      - disable the button (Reinstall Driver)
+                   2) if it's not a system devloader but still missing:
+                      - Reinstall Driver
+                   3) if it's not a system devloader but the file can be found:
+                      - Update Driver
+                   4) if it's a missing or empty software key
+                      - Update Driver
+                 */
+                break;
+            }
+
+            case CM_PROB_INVALID_DATA:
+            case CM_PROB_PARTIAL_LOG_CONF:
+            case CM_PROB_NO_VALID_LOG_CONF:
+            case CM_PROB_HARDWARE_DISABLED:
+            case CM_PROB_CANT_SHARE_IRQ:
+            case CM_PROB_TRANSLATION_FAILED:
+            case CM_PROB_SYSTEM_SHUTDOWN:
+            case CM_PROB_PHANTOM:
+                bDevActionAvailable = FALSE;
+                break;
+
+            case CM_PROB_NOT_VERIFIED:
+            case CM_PROB_DEVICE_NOT_THERE:
+                /* FIXME - search hardware */
+                break;
+
+            case CM_PROB_NEED_RESTART:
+            case CM_PROB_WILL_BE_REMOVED:
+            case CM_PROB_MOVED:
+            case CM_PROB_TOO_EARLY:
+            case CM_PROB_DISABLED_SERVICE:
+                TroubleShootStrId = IDS_REBOOT;
+                break;
+
+            case CM_PROB_REGISTRY:
+                /* FIXME - check registry? */
+                break;
+
+            case CM_PROB_DISABLED:
+                /* if device was disabled by the user: */
+                TroubleShootStrId = IDS_ENABLEDEV;
+                /* FIXME - otherwise disable button because the device was
+                           disabled by the system*/
+                break;
+
+            case CM_PROB_DEVLOADER_NOT_READY:
+                /* FIXME - if it's a graphics adapter:
+                           - if it's a a secondary adapter and the main adapter
+                             couldn't be found
+                             - disable  button
+                           - else
+                             - Properties
+                         - else
+                           - Update driver
+                 */
+                break;
+
+            case CM_PROB_FAILED_ADD:
+                TroubleShootStrId = IDS_PROPERTIES;
+                break;
+        }
+    }
+
+    if (LoadString(hDllInstance,
+                   TroubleShootStrId,
+                   dap->szTemp,
+                   sizeof(dap->szTemp) / sizeof(dap->szTemp[0])) != 0)
+    {
+        SetWindowText(hDevProbBtn,
+                      dap->szTemp);
+    }
+    EnableWindow(hDevProbBtn,
+                 dap->IsAdmin && bDevActionAvailable);
+
+    /* check if the device can be enabled/disabled */
+    hDevUsage = GetDlgItem(hwndDlg,
+                           IDC_DEVUSAGE);
+
+    dap->CanDisable = FALSE;
+    dap->DeviceStarted = FALSE;
+
+    if (CanDisableDevice(DeviceInfoData->DevInst,
+                         dap->hMachine,
+                         &bFlag))
+    {
+        dap->CanDisable = bFlag;
+    }
+
+    if (IsDeviceStarted(DeviceInfoData->DevInst,
+                        dap->hMachine,
+                        &bFlag))
+    {
+        dap->DeviceStarted = bFlag;
+    }
+
+    /* enable/disable the device usage controls */
+    EnableWindow(GetDlgItem(hwndDlg,
+                            IDC_DEVUSAGELABEL),
+                 dap->CanDisable && dap->IsAdmin);
+    EnableWindow(hDevUsage,
+                 dap->CanDisable && dap->IsAdmin);
+
+    /* clear the combobox */
+    SendMessage(hDevUsage,
+                CB_RESETCONTENT,
+                0,
+                0);
+    if (dap->CanDisable)
+    {
+        InitDevUsageActions(hwndDlg,
+                            hDevUsage,
+                            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)
+    {
+TRACE("Count %d additional pages!\n", nDriverPages);
+        dap->nDevPropSheets += nDriverPages;
+    }
+    else
+    {
+        nDriverPages = 0;
+    }
+
+    /* include the driver page */
+    if (dap->HasDriverPage)
+        dap->nDevPropSheets++;
+
+    /* include the details page */
+    if (dap->Extended)
+        dap->nDevPropSheets++;
+
+    if (dap->HasResourcePage)
+        dap->nDevPropSheets++;
+
+    /* add the device property sheets */
+    if (dap->nDevPropSheets != 0)
+    {
+TRACE("Show %d pages!\n", dap->nDevPropSheets);
+        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++)
+                    {
+TRACE("Add page %d\n", iPage);
+TRACE("Sheet %p\n", dap->DevPropSheets[iPage]);
+
+                        if (PropSheet_AddPage(hPropSheetDlg,
+                                              dap->DevPropSheets[iPage]))
+                        {
+                            RecalcPages = TRUE;
+                        }
+                        else
+                        {
+TRACE("PropSheet_AddPage() failed\n");
+                        }
+                    }
+
+                    dap->FreeDevPropSheets = TRUE;
+                }
+                else
+                {
+TRACE("SetupDiGetClassDevPropertySheets() failed\n");
+                    /* 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++;
+                        RecalcPages = TRUE;
+                    }
+                    else
+                    {
+                        dap->pDestroyPropertySheetPage(dap->DevPropSheets[iPage]);
+                        dap->DevPropSheets[iPage] = NULL;
+                    }
+                }
+            }
+
+            if (dap->Extended)
+            {
+                /* Add the details page */
+                PROPSHEETPAGE pspDetails = {0};
+                pspDetails.dwSize = sizeof(PROPSHEETPAGE);
+                pspDetails.dwFlags = PSP_DEFAULT;
+                pspDetails.hInstance = hDllInstance;
+                pspDetails.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICEDETAILS);
+                pspDetails.pfnDlgProc = AdvProcDetailsDlgProc;
+                pspDetails.lParam = (LPARAM)dap;
+                dap->DevPropSheets[iPage] = dap->pCreatePropertySheetPageW(&pspDetails);
+                if (dap->DevPropSheets[iPage] != NULL)
+                {
+                    if (PropSheet_AddPage(hPropSheetDlg,
+                                          dap->DevPropSheets[iPage]))
+                    {
+                        iPage++;
+                        RecalcPages = TRUE;
+                    }
+                    else
+                    {
+                        dap->pDestroyPropertySheetPage(dap->DevPropSheets[iPage]);
+                        dap->DevPropSheets[iPage] = NULL;
+                    }
+                }
+            }
+
+            if (dap->HasResourcePage)
+            {
+                PROPSHEETPAGE pspDriver = {0};
+                pspDriver.dwSize = sizeof(PROPSHEETPAGE);
+                pspDriver.dwFlags = PSP_DEFAULT;
+                pspDriver.hInstance = hDllInstance;
+                pspDriver.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICERESOURCES);
+                pspDriver.pfnDlgProc = ResourcesProcDriverDlgProc;
+                pspDriver.lParam = (LPARAM)dap;
+                dap->DevPropSheets[iPage] = dap->pCreatePropertySheetPageW(&pspDriver);
+                if (dap->DevPropSheets[iPage] != NULL)
+                {
+                    if (PropSheet_AddPage(hPropSheetDlg,
+                                          dap->DevPropSheets[iPage]))
+                    {
+                        iPage++;
+                        RecalcPages = TRUE;
+                    }
+                    else
+                    {
+                        dap->pDestroyPropertySheetPage(dap->DevPropSheets[iPage]);
+                        dap->DevPropSheets[iPage] = NULL;
+                    }
+                }
+            }
+            /* FIXME: Add the power page */
+        }
+        else
+            dap->nDevPropSheets = 0;
+    }
+
+    if (RecalcPages)
+    {
+        PropSheet_RecalcPageSizes(hPropSheetDlg);
+    }
+
+    /* finally, disable the apply button */
+    PropSheet_UnChanged(hPropSheetDlg,
+                        hwndDlg);
+    dap->DeviceUsageChanged = FALSE;
+}
+
+
+static LRESULT
+CALLBACK
+DlgParentSubWndProc(IN HWND hwnd,
+                    IN UINT uMsg,
+                    IN WPARAM wParam,
+                    IN LPARAM lParam)
+{
+    PDEVADVPROP_INFO dap;
+
+    dap = (PDEVADVPROP_INFO)GetProp(hwnd,
+                                    L"DevMgrDevChangeSub");
+    if (dap != NULL)
+    {
+        if (uMsg == WM_DEVICECHANGE && !IsWindowVisible(dap->hWndGeneralPage))
+        {
+            SendMessage(dap->hWndGeneralPage,
+                        WM_DEVICECHANGE,
+                        wParam,
+                        lParam);
+        }
+
+        /* pass the message the the old window proc */
+        return CallWindowProc(dap->ParentOldWndProc,
+                              hwnd,
+                              uMsg,
+                              wParam,
+                              lParam);
+    }
+    else
+    {
+        /* this is not a good idea if the subclassed window was an ansi
+           window, but we failed finding out the previous window proc
+           so we can't use CallWindowProc. This should rarely - if ever -
+           happen. */
+
+        return DefWindowProc(hwnd,
+                             uMsg,
+                             wParam,
+                             lParam);
+    }
+}
+
+
+static INT_PTR
+CALLBACK
+AdvPropGeneralDlgProc(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_DEVUSAGE:
+                    {
+                        if (HIWORD(wParam) == CBN_SELCHANGE)
+                        {
+                            PropSheet_Changed(GetParent(hwndDlg),
+                                              hwndDlg);
+                            dap->DeviceUsageChanged = TRUE;
+                        }
+                        break;
+                    }
+
+                    case IDC_DEVPROBLEM:
+                    {
+                        if (dap->IsAdmin)
+                        {
+                            /* display the device problem wizard */
+                            ShowDeviceProblemWizard(hwndDlg,
+                                                    dap->DeviceInfoSet,
+                                                    &dap->DeviceInfoData,
+                                                    dap->hMachine);
+                        }
+                        break;
+                    }
+                }
+                break;
+            }
+
+            case WM_NOTIFY:
+            {
+                NMHDR *hdr = (NMHDR*)lParam;
+                switch (hdr->code)
+                {
+                    case PSN_APPLY:
+                        ApplyGeneralSettings(hwndDlg,
+                                             dap);
+                        break;
+                }
+                break;
+            }
+
+            case WM_INITDIALOG:
+            {
+                dap = (PDEVADVPROP_INFO)((LPPROPSHEETPAGE)lParam)->lParam;
+                if (dap != NULL)
+                {
+                    HWND hWndParent;
+
+                    dap->hWndGeneralPage = hwndDlg;
+
+                    SetWindowLongPtr(hwndDlg,
+                                     DWL_USER,
+                                     (DWORD_PTR)dap);
+
+                    /* subclass the parent window to always receive
+                       WM_DEVICECHANGE messages */
+                    hWndParent = GetParent(hwndDlg);
+                    if (hWndParent != NULL)
+                    {
+                        /* subclass the parent window. This is not safe
+                           if the parent window belongs to another thread! */
+                        dap->ParentOldWndProc = (WNDPROC)SetWindowLongPtr(hWndParent,
+                                                                          GWLP_WNDPROC,
+                                                                          (LONG_PTR)DlgParentSubWndProc);
+
+                        if (dap->ParentOldWndProc != NULL &&
+                            SetProp(hWndParent,
+                                    L"DevMgrDevChangeSub",
+                                    (HANDLE)dap))
+                        {
+                            dap->hWndParent = hWndParent;
+                        }
+                    }
+
+                    /* 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;
+            }
+
+            case WM_DEVICECHANGE:
+            {
+                /* FIXME - don't call UpdateDevInfo for all events */
+                UpdateDevInfo(hwndDlg,
+                              dap,
+                              TRUE);
+                Ret = TRUE;
+                break;
+            }
+
+            case PM_INITIALIZE:
+            {
+                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)
+                {
+                    if (SetWindowLongPtr(dap->hWndParent,
+                                         GWLP_WNDPROC,
+                                         (LONG_PTR)dap->ParentOldWndProc) == (LONG_PTR)DlgParentSubWndProc)
+                    {
+                        RemoveProp(dap->hWndParent,
+                                   L"DevMgrDevChangeSub");
+                    }
+                }
+                break;
+            }
+        }
+    }
+
+    return Ret;
+}
+
+
+INT_PTR
+DisplayDeviceAdvancedProperties(IN HWND hWndParent,
+                                IN LPCWSTR lpDeviceID  OPTIONAL,
+                                IN HDEVINFO DeviceInfoSet,
+                                IN PSP_DEVINFO_DATA DeviceInfoData,
+                                IN HINSTANCE hComCtl32,
+                                IN LPCWSTR lpMachineName,
+                                IN DWORD dwFlags)
+{
+    PROPSHEETHEADER psh = {0};
+    PROPSHEETPAGE pspGeneral = {0};
+    PPROPERTYSHEETW pPropertySheetW;
+    PCREATEPROPERTYSHEETPAGEW pCreatePropertySheetPageW;
+    PDESTROYPROPERTYSHEETPAGE pDestroyPropertySheetPage;
+    PDEVADVPROP_INFO DevAdvPropInfo;
+    HMACHINE hMachine = NULL;
+    DWORD DevIdSize = 0;
+    INT_PTR Ret = -1;
+
+    /* we don't want to statically link against comctl32, so find the
+       functions we need dynamically */
+    pPropertySheetW =
+        (PPROPERTYSHEETW)GetProcAddress(hComCtl32,
+                                        "PropertySheetW");
+    pCreatePropertySheetPageW =
+        (PCREATEPROPERTYSHEETPAGEW)GetProcAddress(hComCtl32,
+                                                  "CreatePropertySheetPageW");
+    pDestroyPropertySheetPage =
+        (PDESTROYPROPERTYSHEETPAGE)GetProcAddress(hComCtl32,
+                                                  "DestroyPropertySheetPage");
+    if (pPropertySheetW == NULL ||
+        pCreatePropertySheetPageW == NULL ||
+        pDestroyPropertySheetPage == NULL)
+    {
+        return -1;
+    }
+
+    if (lpDeviceID == NULL)
+    {
+        /* find out how much size is needed for the device id */
+        if (SetupDiGetDeviceInstanceId(DeviceInfoSet,
+                                       DeviceInfoData,
+                                       NULL,
+                                       0,
+                                       &DevIdSize))
+        {
+            ERR("SetupDiGetDeviceInstanceId unexpectedly returned TRUE!\n");
+            return -1;
+        }
+
+        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+        {
+            return -1;
+        }
+    }
+    else
+    {
+        DevIdSize = (DWORD)wcslen(lpDeviceID) + 1;
+    }
+
+    if (lpMachineName != NULL && lpMachineName[0] != L'\0')
+    {
+        CONFIGRET cr = CM_Connect_Machine(lpMachineName,
+                                          &hMachine);
+        if (cr != CR_SUCCESS)
+        {
+            return -1;
+        }
+    }
+
+    /* create the internal structure associated with the "General",
+       "Driver", ... pages */
+    DevAdvPropInfo = HeapAlloc(GetProcessHeap(),
+                               HEAP_ZERO_MEMORY,
+                               FIELD_OFFSET(DEVADVPROP_INFO,
+                                            szDeviceID) +
+                                   (DevIdSize * sizeof(WCHAR)));
+    if (DevAdvPropInfo == NULL)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        goto Cleanup;
+    }
+
+    if (lpDeviceID == NULL)
+    {
+        /* read the device instance id */
+        if (!SetupDiGetDeviceInstanceId(DeviceInfoSet,
+                                        DeviceInfoData,
+                                        DevAdvPropInfo->szDeviceID,
+                                        DevIdSize,
+                                        NULL))
+        {
+            goto Cleanup;
+        }
+    }
+    else
+    {
+        /* copy the device instance id supplied by the caller */
+        wcscpy(DevAdvPropInfo->szDeviceID,
+               lpDeviceID);
+    }
+
+    DevAdvPropInfo->DeviceInfoSet = DeviceInfoSet;
+    DevAdvPropInfo->DeviceInfoData = *DeviceInfoData;
+    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);
+    DevAdvPropInfo->Extended = ((dwFlags & DPF_EXTENDED) != 0);
+
+    psh.dwSize = sizeof(PROPSHEETHEADER);
+    psh.dwFlags = PSH_PROPTITLE | PSH_NOAPPLYNOW;
+    psh.hwndParent = hWndParent;
+    psh.pszCaption = DevAdvPropInfo->szDevName;
+
+    DevAdvPropInfo->PropertySheetType = DevAdvPropInfo->ShowRemotePages ?
+                                            DIGCDP_FLAG_REMOTE_ADVANCED :
+                                            DIGCDP_FLAG_ADVANCED;
+
+    psh.phpage = HeapAlloc(GetProcessHeap(),
+                           HEAP_ZERO_MEMORY,
+                           1 * sizeof(HPROPSHEETPAGE));
+    if (psh.phpage == NULL)
+    {
+        goto Cleanup;
+    }
+
+    /* add the "General" property sheet */
+    pspGeneral.dwSize = sizeof(PROPSHEETPAGE);
+    pspGeneral.dwFlags = PSP_DEFAULT;
+    pspGeneral.hInstance = hDllInstance;
+    pspGeneral.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICEGENERAL);
+    pspGeneral.pfnDlgProc = AdvPropGeneralDlgProc;
+    pspGeneral.lParam = (LPARAM)DevAdvPropInfo;
+    psh.phpage[psh.nPages] = pCreatePropertySheetPageW(&pspGeneral);
+    if (psh.phpage[psh.nPages] != NULL)
+    {
+        psh.nPages++;
+    }
+
+    DevAdvPropInfo->nDevPropSheets = psh.nPages;
+
+    if (psh.nPages != 0)
+    {
+        Ret = pPropertySheetW(&psh);
+
+        /* NOTE: no need to destroy the property sheets anymore! */
+    }
+    else
+    {
+        UINT i;
+
+Cleanup:
+        /* in case of failure the property sheets must be destroyed */
+        if (psh.phpage != NULL)
+        {
+            for (i = 0;
+                 i < psh.nPages;
+                 i++)
+            {
+                if (psh.phpage[i] != NULL)
+                {
+                    pDestroyPropertySheetPage(psh.phpage[i]);
+                }
+            }
+        }
+    }
+
+    if (DevAdvPropInfo != NULL)
+    {
+        if (DevAdvPropInfo->FreeDevPropSheets)
+        {
+            /* don't free the array if it's the one allocated in
+               DisplayDeviceAdvancedProperties */
+            HeapFree(GetProcessHeap(),
+                     0,
+                     DevAdvPropInfo->DevPropSheets);
+        }
+
+        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);
+        }
+
+        if (DevAdvPropInfo->hDevIcon != NULL)
+        {
+            DestroyIcon(DevAdvPropInfo->hDevIcon);
+        }
+
+        HeapFree(GetProcessHeap(),
+                 0,
+                 DevAdvPropInfo);
+    }
+
+    if (psh.phpage != NULL)
+    {
+        HeapFree(GetProcessHeap(),
+                 0,
+                 psh.phpage);
+    }
+
+    if (hMachine != NULL)
+    {
+        CM_Disconnect_Machine(hMachine);
+    }
+
+    return Ret;
+}
+
+
+static BOOL
+GetDeviceAndComputerName(LPWSTR lpString,
+                         WCHAR szDeviceID[],
+                         WCHAR szMachineName[])
+{
+    BOOL ret = FALSE;
+
+    szDeviceID[0] = L'\0';
+    szMachineName[0] = L'\0';
+
+    while (*lpString != L'\0')
+    {
+        if (*lpString == L'/')
+        {
+            lpString++;
+            if(!_wcsnicmp(lpString, L"DeviceID", 8))
+            {
+                lpString += 9;
+                if (*lpString != L'\0')
+                {
+                    int i = 0;
+                    while ((*lpString != L' ') &&
+                           (*lpString != L'\0') &&
+                           (i <= MAX_DEVICE_ID_LEN))
+                    {
+                        szDeviceID[i++] = *lpString++;
+                    }
+                    szDeviceID[i] = L'\0';
+                    ret = TRUE;
+                }
+            }
+            else if (!_wcsnicmp(lpString, L"MachineName", 11))
+            {
+                lpString += 12;
+                if (*lpString != L'\0')
+                {
+                    int i = 0;
+                    while ((*lpString != L' ') &&
+                           (*lpString != L'\0') &&
+                           (i <= MAX_COMPUTERNAME_LENGTH))
+                    {
+                        szMachineName[i++] = *lpString++;
+                    }
+                    szMachineName[i] = L'\0';
+                }
+            }
+            /* knock the pointer back one and let the next
+             * pointer deal with incrementing, otherwise we
+             * go past the end of the string */
+             lpString--;
+        }
+        lpString++;
+    }
+
+    return ret;
+}
+
+
+/***************************************************************************
+ * NAME                                                         EXPORTED
+ *      DeviceAdvancedPropertiesW
+ *
+ * DESCRIPTION
+ *   Invokes the device properties dialog, this version may add some property pages
+ *   for some devices
+ *
+ * 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
+ *
+ * RETURN VALUE
+ *   Always returns -1, a call to GetLastError returns 0 if successful
+ *
+ * @implemented
+ */
+INT_PTR
+WINAPI
+DeviceAdvancedPropertiesW(IN HWND hWndParent  OPTIONAL,
+                          IN LPCWSTR lpMachineName  OPTIONAL,
+                          IN LPCWSTR lpDeviceID)
+{
+    HDEVINFO hDevInfo;
+    SP_DEVINFO_DATA DevInfoData;
+    HINSTANCE hComCtl32;
+    INT_PTR Ret = -1;
+
+    if (lpDeviceID == NULL)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    /* 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,
+                                                      0);
+            }
+
+            SetupDiDestroyDeviceInfoList(hDevInfo);
+        }
+
+        FreeLibrary(hComCtl32);
+    }
+
+    return Ret;
+}
+
+
+/***************************************************************************
+ * NAME                                                         EXPORTED
+ *      DeviceAdvancedPropertiesA
+ *
+ * DESCRIPTION
+ *   Invokes the device properties dialog, this version may add some property pages
+ *   for some devices
+ *
+ * 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
+ *
+ * RETURN VALUE
+ *   Always returns -1, a call to GetLastError returns 0 if successful
+ *
+ * @implemented
+ */
+INT_PTR
+WINAPI
+DeviceAdvancedPropertiesA(IN HWND hWndParent  OPTIONAL,
+                          IN LPCSTR lpMachineName  OPTIONAL,
+                          IN LPCSTR lpDeviceID)
+{
+    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 = DeviceAdvancedPropertiesW(hWndParent,
+                                    lpMachineNameW,
+                                    lpDeviceIDW);
+
+Cleanup:
+    if (lpMachineNameW != NULL)
+    {
+        HeapFree(GetProcessHeap(),
+                 0,
+                 lpMachineNameW);
+    }
+    if (lpDeviceIDW != NULL)
+    {
+        HeapFree(GetProcessHeap(),
+                 0,
+                 lpDeviceIDW);
+    }
+
+    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, optional if
+ *                  bShowDevMgr is nonzero
+ *   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, optional if
+ *                  bShowDevMgr is nonzero
+ *   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
+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_EXTENDED | DPF_DEVICE_STATUS_ACTION))
+    {
+        FIXME("DevPropertiesExW: Invalid flags: 0x%x\n",
+                dwFlags & ~(DPF_EXTENDED | DPF_DEVICE_STATUS_ACTION));
+        SetLastError(ERROR_INVALID_FLAGS);
+        return -1;
+    }
+
+    if (bShowDevMgr)
+    {
+        FIXME("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;
+}
+
+
+/***************************************************************************
+ * NAME                                                         EXPORTED
+ *      DevicePropertiesA
+ *
+ * DESCRIPTION
+ *   Invokes the device properties dialog directly
+ *
+ * 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
+ *   bShowDevMgr:   If non-zero it displays the device manager instead of
+ *                  the device property dialog
+ *
+ * RETURN VALUE
+ *   >=0: if no errors occured
+ *   -1:  if errors occured
+ *
+ * REVISIONS
+ *
+ * @implemented
+ */
+int
+WINAPI
+DevicePropertiesA(HWND hWndParent,
+                  LPCSTR lpMachineName,
+                  LPCSTR lpDeviceID,
+                  BOOL bShowDevMgr)
+{
+    return DevicePropertiesExA(hWndParent,
+                               lpMachineName,
+                               lpDeviceID,
+                               DPF_EXTENDED,
+                               bShowDevMgr);
+}
+
+
+/***************************************************************************
+ * NAME                                                         EXPORTED
+ *      DevicePropertiesW
+ *
+ * DESCRIPTION
+ *   Invokes the device properties dialog directly
+ *
+ * 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
+ *   bShowDevMgr:   If non-zero it displays the device manager instead of
+ *                  the device property dialog
+ *
+ * RETURN VALUE
+ *   >=0: if no errors occured
+ *   -1:  if errors occured
+ *
+ * REVISIONS
+ *
+ * @implemented
+ */
+int
+WINAPI
+DevicePropertiesW(HWND hWndParent,
+                  LPCWSTR lpMachineName,
+                  LPCWSTR lpDeviceID,
+                  BOOL bShowDevMgr)
+{
+    return DevicePropertiesExW(hWndParent,
+                               lpMachineName,
+                               lpDeviceID,
+                               DPF_EXTENDED,
+                               bShowDevMgr);
+}
+
+
+/***************************************************************************
+ * NAME                                                         EXPORTED
+ *      DeviceProperties_RunDLLA
+ *
+ * DESCRIPTION
+ *   Invokes the device properties dialog
+ *
+ * ARGUMENTS
+ *   hWndParent:  Handle to the parent window
+ *   hInst:       Handle to the application instance
+ *   lpDeviceCmd: A command that includes the DeviceID of the properties to be shown,
+ *                also see NOTEs
+ *   nCmdShow:    Specifies how the window should be shown
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *   - lpDeviceCmd is a string in the form of "/MachineName MACHINE /DeviceID DEVICEPATH"
+ *     (/MachineName is optional). This function only parses this string and eventually
+ *     calls DeviceProperties().
+ *
+ * @implemented
+ */
+VOID
+WINAPI
+DeviceProperties_RunDLLA(HWND hWndParent,
+                         HINSTANCE hInst,
+                         LPCSTR lpDeviceCmd,
+                         int nCmdShow)
+{
+    LPWSTR lpDeviceCmdW = NULL;
+
+    if (lpDeviceCmd != NULL)
+    {
+        if ((lpDeviceCmdW = ConvertMultiByteToUnicode(lpDeviceCmd,
+                                                      CP_ACP)))
+        {
+            DeviceProperties_RunDLLW(hWndParent,
+                                     hInst,
+                                     lpDeviceCmdW,
+                                     nCmdShow);
+        }
+    }
+
+    if (lpDeviceCmdW != NULL)
+    {
+        HeapFree(GetProcessHeap(),
+                 0,
+                 lpDeviceCmdW);
+    }
+}
+
+
+/***************************************************************************
+ * NAME                                                         EXPORTED
+ *      DeviceProperties_RunDLLW
+ *
+ * DESCRIPTION
+ *   Invokes the device properties dialog
+ *
+ * ARGUMENTS
+ *   hWndParent:  Handle to the parent window
+ *   hInst:       Handle to the application instance
+ *   lpDeviceCmd: A command that includes the DeviceID of the properties to be shown,
+ *                also see NOTEs
+ *   nCmdShow:    Specifies how the window should be shown
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *   - lpDeviceCmd is a string in the form of "/MachineName MACHINE /DeviceID DEVICEPATH"
+ *     (/MachineName is optional). This function only parses this string and eventually
+ *     calls DeviceProperties().
+ *
+ * @implemented
+ */
+VOID
+WINAPI
+DeviceProperties_RunDLLW(HWND hWndParent,
+                         HINSTANCE hInst,
+                         LPCWSTR lpDeviceCmd,
+                         int nCmdShow)
+{
+    WCHAR szDeviceID[MAX_DEVICE_ID_LEN+1];
+    WCHAR szMachineName[MAX_COMPUTERNAME_LENGTH+1];
+    LPWSTR lpString = (LPWSTR)lpDeviceCmd;
+
+    if (!GetDeviceAndComputerName(lpString,
+                                  szDeviceID,
+                                  szMachineName))
+    {
+        ERR("DeviceProperties_RunDLLW DeviceID: %S, MachineName: %S\n", szDeviceID, szMachineName);
+        return;
+    }
+
+    DevicePropertiesW(hWndParent,
+                      szMachineName,
+                      szDeviceID,
+                      FALSE);
+}
diff --git a/reactos/dll/win32/devmgr_new/devmgmt/ClassNode.cpp b/reactos/dll/win32/devmgr_new/devmgmt/ClassNode.cpp
new file mode 100644 (file)
index 0000000..249925c
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+* PROJECT:     ReactOS Device Manager
+* LICENSE:     GPL - See COPYING in the top level directory
+* FILE:        dll/win32/devmgr/devmgr/ClassNode.cpp
+* PURPOSE:     Class object for 
+* COPYRIGHT:   Copyright 2015 Ged Murphy <gedmurphy@reactos.org>
+*
+*/
+
+#include "stdafx.h"
+#include "devmgmt.h"
+#include "ClassNode.h"
+
+
+CClassNode::CClassNode(
+    _In_ LPGUID ClassGuid,
+    _In_ PSP_CLASSIMAGELIST_DATA ImageListData
+    ) :
+    CNode(ClassNode, ImageListData)
+{
+    CopyMemory(&m_ClassGuid, ClassGuid, sizeof(GUID));
+}
+
+
+CClassNode::~CClassNode()
+{
+}
+
+
+bool
+CClassNode::SetupNode()
+{
+    DWORD RequiredSize, Type, Size;
+    DWORD Success;
+    HKEY hKey;
+
+    // Open the registry key for this class
+    hKey = SetupDiOpenClassRegKeyExW(&m_ClassGuid,
+                                     MAXIMUM_ALLOWED,
+                                     DIOCR_INSTALLER,
+                                     NULL,
+                                     0);
+    if (hKey != INVALID_HANDLE_VALUE)
+    {
+        Size = DISPLAY_NAME_LEN;
+        Type = REG_SZ;
+
+        // Lookup the class description (win7+)
+        Success = RegQueryValueExW(hKey,
+                                   L"ClassDesc",
+                                   NULL,
+                                   &Type,
+                                   (LPBYTE)m_DisplayName,
+                                   &Size);
+        if (Success == ERROR_SUCCESS)
+        {
+            // Check if the string starts with an @
+            if (m_DisplayName[0] == L'@')
+            {
+                // The description is located in a module resource
+                Success = ConvertResourceDescriptorToString(m_DisplayName, DISPLAY_NAME_LEN);
+            }
+        }
+        else if (Success == ERROR_FILE_NOT_FOUND)
+        {
+            // WinXP stores the description in the default value
+            Success = RegQueryValueExW(hKey,
+                                       NULL,
+                                       NULL,
+                                       &Type,
+                                       (LPBYTE)m_DisplayName,
+                                       &Size);
+        }
+
+        // Close the registry key
+        RegCloseKey(hKey);
+    }
+    else
+    {
+        Success = GetLastError();
+    }
+
+    // Check if we failed to get the class description
+    if (Success != ERROR_SUCCESS)
+    {
+        // Use the class name as the description
+        RequiredSize = DISPLAY_NAME_LEN;
+        (VOID)SetupDiClassNameFromGuidW(&m_ClassGuid,
+                                        m_DisplayName,
+                                        RequiredSize,
+                                        &RequiredSize);
+    }
+
+    // Get the image index for this class
+    (VOID)SetupDiGetClassImageIndex(m_ImageListData,
+                                    &m_ClassGuid,
+                                    &m_ClassImage);
+
+    return true;
+}
+
+
+DWORD
+CClassNode::ConvertResourceDescriptorToString(
+    _Inout_z_ LPWSTR ResourceDescriptor,
+    _In_ DWORD ResourceDescriptorSize
+    )
+{
+    WCHAR ModulePath[MAX_PATH];
+    WCHAR ResString[256];
+    INT ResourceId;
+    HMODULE hModule;
+    LPWSTR ptr;
+    DWORD Size;
+    DWORD dwError;
+
+
+    // First check for a semi colon */
+    ptr = wcschr(ResourceDescriptor, L';');
+    if (ptr)
+    {
+        // This must be an inf based descriptor, the desc is after the semi colon
+        StringCbCopyW(ResourceDescriptor, ResourceDescriptorSize, ++ptr);
+        dwError = ERROR_SUCCESS;
+    }
+    else
+    {
+        // This must be a dll resource based descriptor. Find the comma
+        ptr = wcschr(ResourceDescriptor, L',');
+        if (ptr == NULL) return ERROR_INVALID_DATA;
+
+        // Terminate the string where the comma was
+        *ptr = UNICODE_NULL;
+
+        // Expand any environment strings
+        Size = ExpandEnvironmentStringsW(&ResourceDescriptor[1], ModulePath, MAX_PATH);
+        if (Size > MAX_PATH) return ERROR_BUFFER_OVERFLOW;
+        if (Size == 0) return GetLastError();
+
+        // Put the comma back and move past it
+        *ptr = L',';
+        ptr++;
+
+        // Load the dll
+        hModule = LoadLibraryExW(ModulePath, NULL, LOAD_LIBRARY_AS_DATAFILE);
+        if (hModule == NULL) return GetLastError();
+
+        // Convert the resource id to a number
+        ResourceId = _wtoi(ptr);
+
+        // If the number is negative, make it positive
+        if (ResourceId < 0) ResourceId = -ResourceId;
+
+        // Load the string from the dll
+        if (LoadStringW(hModule, ResourceId, ResString, 256))
+        {
+            StringCbCopyW(ResourceDescriptor, ResourceDescriptorSize, ResString);
+            dwError = ERROR_SUCCESS;
+        }
+        else
+        {
+            dwError = GetLastError();
+        }
+
+        // Free the library
+        FreeLibrary(hModule);
+    }
+
+    return dwError;
+}
diff --git a/reactos/dll/win32/devmgr_new/devmgmt/ClassNode.h b/reactos/dll/win32/devmgr_new/devmgmt/ClassNode.h
new file mode 100644 (file)
index 0000000..39db56b
--- /dev/null
@@ -0,0 +1,24 @@
+#pragma once
+#include "Node.h"
+
+class CClassNode : public CNode
+{
+public:
+
+    CClassNode(
+        _In_ LPGUID ClassGuid,
+        _In_ PSP_CLASSIMAGELIST_DATA ImageListData
+        );
+
+    ~CClassNode();
+
+    virtual bool SetupNode();
+
+private:
+
+    DWORD ConvertResourceDescriptorToString(
+        _Inout_z_ LPWSTR ResourceDescriptor,
+        _In_ DWORD ResourceDescriptorSize
+        );
+};
+
diff --git a/reactos/dll/win32/devmgr_new/devmgmt/DeviceNode.cpp b/reactos/dll/win32/devmgr_new/devmgmt/DeviceNode.cpp
new file mode 100644 (file)
index 0000000..b15ce5a
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+* PROJECT:     ReactOS Device Manager
+* LICENSE:     GPL - See COPYING in the top level directory
+* FILE:        dll/win32/devmgr/devmgr/ClassNode.cpp
+* PURPOSE:     Class object for
+* COPYRIGHT:   Copyright 2015 Ged Murphy <gedmurphy@reactos.org>
+*
+*/
+
+#include "stdafx.h"
+#include "devmgmt.h"
+#include "DeviceNode.h"
+
+
+CDeviceNode::CDeviceNode(
+    _In_opt_ DEVINST Device,
+    _In_ PSP_CLASSIMAGELIST_DATA ImageListData
+    ) :
+    CNode(DeviceNode, ImageListData),
+    m_DevInst(Device),
+    m_hDevInfo(NULL),
+    m_Status(0),
+    m_ProblemNumber(0),
+    m_OverlayImage(0)
+{
+    ZeroMemory(&m_DevinfoData, sizeof(SP_DEVINFO_DATA));
+}
+
+CDeviceNode::~CDeviceNode()
+{
+    Cleanup();
+}
+
+bool
+CDeviceNode::SetupNode()
+{
+    WCHAR ClassGuidString[MAX_GUID_STRING_LEN];
+    ULONG ulLength;
+    CONFIGRET cr;
+
+    // Get the length of the device id string
+    cr = CM_Get_Device_ID_Size(&ulLength, m_DevInst, 0);
+    if (cr == CR_SUCCESS)
+    {
+        // We alloc heap here because this will be stored in the lParam of the TV
+        m_DeviceId = new WCHAR[ulLength + 1];
+
+        // Now get the actual device id
+        cr = CM_Get_Device_IDW(m_DevInst,
+                                m_DeviceId,
+                                ulLength + 1,
+                                0);
+        if (cr != CR_SUCCESS)
+        {
+            delete[] m_DeviceId;
+            m_DeviceId = NULL;
+        }
+
+    }
+
+    // Make sure we got the string
+    if (m_DeviceId == NULL)
+        return false;
+
+    // Build up a handle a and devinfodata struct
+    m_hDevInfo = SetupDiCreateDeviceInfoListExW(NULL,
+                                                NULL,
+                                                NULL,
+                                                NULL);
+    if (m_hDevInfo != INVALID_HANDLE_VALUE)
+    {
+        m_DevinfoData.cbSize = sizeof(SP_DEVINFO_DATA);
+        SetupDiOpenDeviceInfoW(m_hDevInfo,
+                               m_DeviceId,
+                               NULL,
+                               0,
+                               &m_DevinfoData);
+    }
+
+
+    // Set the overlay if the device has a problem
+    if (HasProblem())
+    {
+        m_OverlayImage = 1;
+    }
+
+    // The disabled overlay takes precidence over the problem overlay
+    if (IsDisabled())
+    {
+        m_OverlayImage = 2;
+    }
+
+
+    // Get the class guid for this device
+    ulLength = MAX_GUID_STRING_LEN * sizeof(WCHAR);
+    cr = CM_Get_DevNode_Registry_PropertyW(m_DevInst,
+                                           CM_DRP_CLASSGUID,
+                                           NULL,
+                                           ClassGuidString,
+                                           &ulLength,
+                                           0);
+    if (cr == CR_SUCCESS)
+    {
+        // Convert the string to a proper guid
+        CLSIDFromString(ClassGuidString, &m_ClassGuid);
+    }
+    else
+    {
+        // It's a device with no driver
+        m_ClassGuid = GUID_DEVCLASS_UNKNOWN;
+    }
+
+
+    // Get the image for the class this device is in
+    SetupDiGetClassImageIndex(m_ImageListData,
+                              &m_ClassGuid,
+                              &m_ClassImage);
+
+    // Get the description for the device
+    ulLength = DISPLAY_NAME_LEN * sizeof(WCHAR);
+    cr = CM_Get_DevNode_Registry_PropertyW(m_DevInst,
+                                           CM_DRP_FRIENDLYNAME,
+                                           NULL,
+                                           m_DisplayName,
+                                           &ulLength,
+                                           0);
+    if (cr != CR_SUCCESS)
+    {
+        ulLength = DISPLAY_NAME_LEN * sizeof(WCHAR);
+        cr = CM_Get_DevNode_Registry_PropertyW(m_DevInst,
+                                               CM_DRP_DEVICEDESC,
+                                               NULL,
+                                               m_DisplayName,
+                                               &ulLength,
+                                               0);
+
+    }
+
+    // Cleanup if something failed
+    if (cr != CR_SUCCESS)
+    {
+        Cleanup();
+        return false;
+    }
+
+    return true;
+}
+
+bool
+CDeviceNode::HasProblem()
+{
+    CONFIGRET cr;
+    cr = CM_Get_DevNode_Status_Ex(&m_Status,
+                                  &m_ProblemNumber,
+                                  m_DevInst,
+                                  0,
+                                  NULL);
+    if (cr == CR_SUCCESS)
+    {
+        return ((m_Status & (DN_HAS_PROBLEM | DN_PRIVATE_PROBLEM)) != 0);
+    }
+
+    return false;
+}
+
+bool
+CDeviceNode::IsHidden()
+{
+    CONFIGRET cr;
+    cr = CM_Get_DevNode_Status_Ex(&m_Status,
+                                  &m_ProblemNumber,
+                                  m_DevInst,
+                                  0,
+                                  NULL);
+    if (cr == CR_SUCCESS)
+    {
+        return ((m_Status & DN_NO_SHOW_IN_DM) != 0);
+    }
+
+    return false;
+}
+
+bool
+CDeviceNode::CanDisable()
+{
+    CONFIGRET cr;
+    cr = CM_Get_DevNode_Status_Ex(&m_Status,
+                                  &m_ProblemNumber,
+                                  m_DevInst,
+                                  0,
+                                  NULL);
+    if (cr == CR_SUCCESS)
+    {
+        return ((m_Status & DN_DISABLEABLE) != 0);
+    }
+
+    return false;
+}
+
+bool
+CDeviceNode::IsDisabled()
+{
+    CONFIGRET cr;
+    cr = CM_Get_DevNode_Status_Ex(&m_Status,
+                                  &m_ProblemNumber,
+                                  m_DevInst,
+                                  0,
+                                  NULL);
+    if (cr == CR_SUCCESS)
+    {
+        return ((m_ProblemNumber & (CM_PROB_DISABLED | CM_PROB_HARDWARE_DISABLED)) != 0);
+    }
+
+    return false;
+}
+
+bool
+CDeviceNode::IsStarted()
+{
+    CONFIGRET cr;
+    cr = CM_Get_DevNode_Status_Ex(&m_Status,
+                                  &m_ProblemNumber,
+                                  m_DevInst,
+                                  0,
+                                  NULL);
+    if (cr == CR_SUCCESS)
+    {
+        return ((m_Status & DN_STARTED) != 0);
+    }
+
+    return false;
+}
+
+bool
+CDeviceNode::IsInstalled()
+{
+    CONFIGRET cr;
+    cr = CM_Get_DevNode_Status_Ex(&m_Status,
+                                  &m_ProblemNumber,
+                                  m_DevInst,
+                                  0,
+                                  NULL);
+    if (cr == CR_SUCCESS)
+    {
+        return ((m_Status & DN_HAS_PROBLEM) != 0 ||
+                (m_Status & (DN_DRIVER_LOADED | DN_STARTED)) != 0);
+    }
+
+    return false;
+}
+
+bool
+CDeviceNode::CanUninstall()
+{
+    CONFIGRET cr;
+    cr = CM_Get_DevNode_Status_Ex(&m_Status,
+                                  &m_ProblemNumber,
+                                  m_DevInst,
+                                  0,
+                                  NULL);
+    if (cr == CR_SUCCESS)
+    {
+        if ((m_Status & DN_ROOT_ENUMERATED) != 0 &&
+            (m_Status & DN_DISABLEABLE) == 0)
+                return false;
+    }
+
+    return true;
+}
+
+bool
+CDeviceNode::EnableDevice(
+    _In_ bool Enable,
+    _Out_ bool &NeedsReboot
+    )
+{
+    bool Canceled = false;
+
+    SetFlags(DI_NODI_DEFAULTACTION, 0);
+
+    SP_PROPCHANGE_PARAMS pcp;
+    pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
+    pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
+    pcp.StateChange = (Enable ? DICS_ENABLE : DICS_DISABLE);
+    pcp.HwProfile = 0;
+
+
+    // check both scopes to make sure we can make the change
+    for (int i = 0; i < 2; i++)
+    {
+        // Check globally first, then check config specific
+        pcp.Scope = (i == 0) ? DICS_FLAG_GLOBAL : DICS_FLAG_CONFIGSPECIFIC;
+
+        if (SetupDiSetClassInstallParamsW(m_hDevInfo,
+                                          &m_DevinfoData,
+                                          &pcp.ClassInstallHeader,
+                                          sizeof(SP_PROPCHANGE_PARAMS)))
+        {
+            SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
+                                      m_hDevInfo,
+                                      &m_DevinfoData);
+        }
+
+        if (GetLastError() == ERROR_CANCELLED)
+        {
+            Canceled = true;
+            break;
+        }
+    }
+
+    if (Canceled == false)
+    {
+        pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
+        if (SetupDiSetClassInstallParamsW(m_hDevInfo,
+                                          &m_DevinfoData,
+                                          &pcp.ClassInstallHeader,
+                                          sizeof(SP_PROPCHANGE_PARAMS)))
+        {
+            SetupDiChangeState(m_hDevInfo, &m_DevinfoData);
+        }
+
+        if (Enable)
+        {
+            // config specific enabling first, then global enabling.
+            // The global appears to be the one that starts the device
+            pcp.Scope = DICS_FLAG_GLOBAL;
+            if (SetupDiSetClassInstallParamsW(m_hDevInfo,
+                                              &m_DevinfoData,
+                                              &pcp.ClassInstallHeader,
+                                              sizeof(SP_PROPCHANGE_PARAMS)))
+            {
+                SetupDiChangeState(m_hDevInfo, &m_DevinfoData);
+            }
+        }
+
+        SetFlags(DI_PROPERTIES_CHANGE, 0);
+
+        NeedsReboot = ((GetFlags() & (DI_NEEDRESTART | DI_NEEDREBOOT)) != 0);
+    }
+
+    RemoveFlags(DI_NODI_DEFAULTACTION, 0);
+
+    return true;
+}
+
+bool
+CDeviceNode::UninstallDevice()
+{
+
+    if (CanUninstall() == false)
+        return false;
+
+    SP_REMOVEDEVICE_PARAMS RemoveDevParams;
+    RemoveDevParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
+    RemoveDevParams.ClassInstallHeader.InstallFunction = DIF_REMOVE;
+    RemoveDevParams.Scope = DI_REMOVEDEVICE_GLOBAL;
+    RemoveDevParams.HwProfile = 0;
+
+    //
+    // We probably need to walk all the siblings of this 
+    // device and ask if they're happy with the uninstall
+    //
+
+
+    // Remove it
+    SetupDiSetClassInstallParamsW(m_hDevInfo,
+                                  &m_DevinfoData,
+                                  &RemoveDevParams.ClassInstallHeader,
+                                  sizeof(SP_REMOVEDEVICE_PARAMS));
+    SetupDiCallClassInstaller(DIF_REMOVE, m_hDevInfo, &m_DevinfoData);
+
+    // Clear the install params
+    SetupDiSetClassInstallParamsW(m_hDevInfo,
+                                  &m_DevinfoData,
+                                  NULL,
+                                  0);
+
+    return true;
+
+}
+
+/* PRIVATE METHODS ******************************************************/
+
+void
+CDeviceNode::Cleanup()
+{
+    if (m_DeviceId)
+    {
+        delete[] m_DeviceId;
+        m_DeviceId = NULL;
+    }
+    if (m_hDevInfo)
+    {
+        SetupDiDestroyDeviceInfoList(m_hDevInfo);
+        m_hDevInfo = NULL;
+    }
+}
+
+DWORD
+CDeviceNode::GetFlags(
+    )
+{
+    SP_DEVINSTALL_PARAMS DevInstallParams;
+    DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+    if (SetupDiGetDeviceInstallParamsW(m_hDevInfo,
+                                       &m_DevinfoData,
+                                       &DevInstallParams))
+    {
+        return DevInstallParams.Flags;
+    }
+    return 0;
+}
+
+bool
+CDeviceNode::SetFlags(
+    _In_ DWORD Flags,
+    _In_ DWORD FlagsEx
+    )
+{
+    SP_DEVINSTALL_PARAMS DevInstallParams;
+    DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+    if (SetupDiGetDeviceInstallParamsW(m_hDevInfo,
+                                       &m_DevinfoData,
+                                       &DevInstallParams))
+    {
+        DevInstallParams.Flags |= Flags;
+        DevInstallParams.FlagsEx |= FlagsEx;
+        return (SetupDiSetDeviceInstallParamsW(m_hDevInfo,
+                                               &m_DevinfoData,
+                                               &DevInstallParams) != 0);
+    }
+    return false;
+}
+
+bool
+CDeviceNode::RemoveFlags(
+    _In_ DWORD Flags,
+    _In_ DWORD FlagsEx
+    )
+{
+    SP_DEVINSTALL_PARAMS DevInstallParams;
+    DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+    if (SetupDiGetDeviceInstallParamsW(m_hDevInfo,
+                                       &m_DevinfoData,
+                                       &DevInstallParams))
+    {
+        DevInstallParams.Flags &= ~Flags;
+        DevInstallParams.FlagsEx &= ~FlagsEx;
+        return (SetupDiSetDeviceInstallParamsW(m_hDevInfo,
+                                               &m_DevinfoData,
+                                               &DevInstallParams) != 0);
+    }
+    return false;
+}
+
+
diff --git a/reactos/dll/win32/devmgr_new/devmgmt/DeviceNode.h b/reactos/dll/win32/devmgr_new/devmgmt/DeviceNode.h
new file mode 100644 (file)
index 0000000..e03eaf1
--- /dev/null
@@ -0,0 +1,61 @@
+#pragma once
+#include "Node.h"
+
+class CDeviceNode : public CNode
+{
+private:
+    SP_DEVINFO_DATA m_DevinfoData;
+    HDEVINFO m_hDevInfo;
+    DEVINST m_DevInst;
+    ULONG m_Status;
+    ULONG m_ProblemNumber;
+    int m_OverlayImage;
+
+public:
+    CDeviceNode(
+        _In_opt_ DEVINST Device,
+        _In_ PSP_CLASSIMAGELIST_DATA ImageListData
+        );
+
+    ~CDeviceNode();
+
+    virtual bool SetupNode();
+
+    DEVINST GetDeviceInst() { return m_DevInst; }
+    int GetOverlayImage() { return m_OverlayImage; }
+
+    bool HasProblem();
+    bool IsHidden();
+    bool CanDisable();
+    virtual bool IsDisabled();
+    bool IsStarted();
+    bool IsInstalled();
+    bool CanUninstall();
+    virtual bool CanUpdate() { return true; } // unimplemented
+
+    bool EnableDevice(
+        _In_ bool Enable,
+        _Out_ bool &NeedsReboot
+        );
+
+    bool UninstallDevice(
+        );
+
+private:
+    void Cleanup(
+        );
+
+    bool SetFlags(
+        _In_ DWORD Flags,
+        _In_ DWORD FlagsEx
+        );
+
+    bool RemoveFlags(
+        _In_ DWORD Flags,
+        _In_ DWORD FlagsEx
+        );
+
+    DWORD GetFlags(
+        );
+};
+
diff --git a/reactos/dll/win32/devmgr_new/devmgmt/DeviceView.cpp b/reactos/dll/win32/devmgr_new/devmgmt/DeviceView.cpp
new file mode 100644 (file)
index 0000000..ba6cae9
--- /dev/null
@@ -0,0 +1,1163 @@
+/*
+ * PROJECT:     ReactOS Device Manager
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        dll/win32/devmgr/devmgr/DeviceView.cpp
+ * PURPOSE:     Implements the tree view which contains the devices
+ * COPYRIGHT:   Copyright 2015 Ged Murphy <gedmurphy@reactos.org>
+ */
+
+
+
+#include "stdafx.h"
+#include "devmgmt.h"
+#include "DeviceView.h"
+
+
+// DATA ********************************************/
+
+#define CLASS_NAME_LEN      256
+#define CLASS_DESC_LEN      256
+#define ROOT_NAME_SIZE      MAX_COMPUTERNAME_LENGTH + 1
+
+extern "C" {
+INT_PTR
+WINAPI
+DevicePropertiesExW(
+    IN HWND hWndParent OPTIONAL,
+    IN LPCWSTR lpMachineName OPTIONAL,
+    IN LPCWSTR lpDeviceID OPTIONAL,
+    IN DWORD dwFlags OPTIONAL,
+    IN BOOL bShowDevMgr
+);
+}
+typedef INT_PTR(WINAPI *pDevicePropertiesExW)(HWND,LPCWSTR,LPCWSTR,DWORD,BOOL);
+
+struct RefreshThreadData
+{
+    CDeviceView *This;
+    BOOL ScanForChanges;
+    BOOL UpdateView;
+    LPWSTR DeviceId;
+};
+
+
+// PUBLIC METHODS ************************************/
+
+CDeviceView::CDeviceView(
+    HWND hMainWnd
+    ) :
+    m_hMainWnd(hMainWnd),
+    m_hTreeView(NULL),
+    m_hPropertyDialog(NULL),
+    m_hMenu(NULL),
+    m_ViewType(DevicesByType),
+    m_ShowHidden(FALSE),
+    m_RootNode(NULL)
+{
+    ZeroMemory(&m_ImageListData, sizeof(SP_CLASSIMAGELIST_DATA));
+}
+
+CDeviceView::~CDeviceView(void)
+{
+}
+
+bool
+CDeviceView::Initialize()
+{
+    // Get the device image list
+    m_ImageListData.cbSize = sizeof(SP_CLASSIMAGELIST_DATA);
+    BOOL bSuccess = SetupDiGetClassImageList(&m_ImageListData);
+    if (bSuccess == FALSE) return false;
+
+    // Create the main treeview
+    m_hTreeView = CreateWindowExW(WS_EX_CLIENTEDGE,
+                                  WC_TREEVIEW,
+                                  NULL,
+                                  WS_CHILD | WS_VISIBLE | WS_BORDER | TVS_HASLINES |
+                                  TVS_HASBUTTONS | TVS_SHOWSELALWAYS | TVS_LINESATROOT,
+                                  0, 0, 0, 0,
+                                  m_hMainWnd,
+                                  (HMENU)IDC_TREEVIEW,
+                                  g_hInstance,
+                                  NULL);
+    if (m_hTreeView)
+    {
+        // Set the image list against the treeview
+        (void)TreeView_SetImageList(m_hTreeView,
+                                    m_ImageListData.ImageList,
+                                    TVSIL_NORMAL);
+
+        // Give the treeview arrows instead of +/- boxes (on Win7)
+        SetWindowTheme(m_hTreeView, L"explorer", NULL);
+    }
+
+
+
+    return !!(m_hTreeView);
+}
+
+bool
+CDeviceView::Uninitialize()
+{
+    EmptyDeviceView();
+
+    if (m_ImageListData.ImageList != NULL)
+    {
+        SetupDiDestroyClassImageList(&m_ImageListData);
+        ZeroMemory(&m_ImageListData, sizeof(SP_CLASSIMAGELIST_DATA));
+    }
+
+    return true;
+}
+
+LRESULT
+CDeviceView::OnSize(
+    _In_ int x,
+    _In_ int y,
+    _In_ int cx,
+    _In_ int cy
+    )
+{
+    // Resize the treeview
+    SetWindowPos(m_hTreeView,
+                 NULL,
+                 x,
+                 y,
+                 cx,
+                 cy,
+                 SWP_NOZORDER);
+
+    return 0;
+}
+
+LRESULT
+CDeviceView::OnRightClick(
+    _In_ LPNMHDR NmHdr
+    )
+{
+    HTREEITEM hItem = TreeView_GetNextItem(NmHdr->hwndFrom, 0, TVGN_DROPHILITE);
+    if (hItem)
+    {
+        TreeView_SelectItem(NmHdr->hwndFrom, hItem);
+    }
+
+    return 0;
+}
+
+LRESULT
+CDeviceView::OnContextMenu(
+    _In_ LPARAM lParam
+    )
+{
+    HTREEITEM hSelected = TreeView_GetSelection(m_hTreeView);
+
+    RECT rc;
+    if (TreeView_GetItemRect(m_hTreeView,
+                             hSelected,
+                             &rc,
+                             TRUE))
+    {
+        POINT pt;
+        if (GetCursorPos(&pt) &&
+            ScreenToClient(m_hTreeView, &pt) &&
+            PtInRect(&rc, pt))
+        {
+            CNode *Node = GetSelectedNode();
+            if (Node)
+            {
+                // Create the context menu
+                HMENU hContextMenu = CreatePopupMenu();
+
+                // Add the actions for this node
+                BuildActionMenuForNode(hContextMenu, Node, false);
+
+                INT xPos = GET_X_LPARAM(lParam);
+                INT yPos = GET_Y_LPARAM(lParam);
+
+                // Display the menu
+                TrackPopupMenuEx(hContextMenu,
+                                 TPM_RIGHTBUTTON,
+                                 xPos,
+                                 yPos,
+                                 m_hMainWnd,
+                                 NULL);
+
+                DestroyMenu(hContextMenu);
+            }
+        }
+    }
+
+    return 0;
+}
+
+
+void
+CDeviceView::Refresh(
+    _In_ ViewType Type,
+    _In_ bool ScanForChanges,
+    _In_ bool UpdateView,
+    _In_opt_ LPWSTR DeviceId
+    )
+{
+    // Enum devices on a seperate thread to keep the gui responsive
+
+    m_ViewType = Type;
+
+    RefreshThreadData *ThreadData;
+    ThreadData = new RefreshThreadData();
+    ThreadData->This = this;
+    ThreadData->ScanForChanges = ScanForChanges;
+    ThreadData->UpdateView = UpdateView;
+    ThreadData->DeviceId = NULL;
+
+    if (DeviceId)
+    {
+        // Node gets deleted on refresh so we copy it to another block
+        size_t Length = wcslen(DeviceId) + 1;
+        ThreadData->DeviceId = new WCHAR[Length];
+        StringCbCopyW(ThreadData->DeviceId, Length, DeviceId);
+    }
+
+
+    HANDLE hThread;
+    hThread = (HANDLE)_beginthreadex(NULL,
+                                     0,
+                                     &RefreshThread,
+                                     ThreadData,
+                                     0,
+                                     NULL);
+
+    if (hThread) CloseHandle(hThread);
+}
+
+LRESULT
+CDeviceView::OnAction(
+    _In_ UINT Action
+)
+{
+    switch (Action)
+    {
+        case IDC_PROPERTIES:
+        {
+            DisplayPropertySheet();
+            break;
+        }
+
+        case IDC_SCAN_HARDWARE:
+        {
+            Refresh(GetCurrentView(),
+                    true,
+                    true,
+                    NULL);
+            break;
+        }
+
+        case IDC_ENABLE_DRV:
+        {
+            bool NeedsReboot;
+            if (EnableSelectedDevice(true, NeedsReboot) &&
+                NeedsReboot)
+            {
+                MessageBox(m_hMainWnd, L"Rebooting", L"Enable", MB_OK);
+            }
+            break;
+        }
+
+        case IDC_DISABLE_DRV:
+        {
+            bool NeedsReboot;
+            EnableSelectedDevice(false, NeedsReboot);
+            break;
+        }
+
+        case IDC_UPDATE_DRV:
+        {
+            MessageBox(m_hMainWnd, L"Not yet implemented", L"Update Driver", MB_OK);
+            break;
+        }
+
+        case IDC_UNINSTALL_DRV:
+        {
+            UninstallSelectedDevice();
+            break;
+        }
+
+        case IDC_ADD_HARDWARE:
+        {
+            MessageBox(m_hMainWnd, L"Not yet implemented", L"Add Hardware", MB_OK);
+            break;
+        }
+    }
+
+    return 0;
+}
+
+void
+CDeviceView::DisplayPropertySheet()
+{
+    //
+    // In ReactOS we can link to DevicePropertiesEx but
+    // not in windows as it's not part of the SDK 
+
+#ifndef __REACTOS__
+    HMODULE hModule = LoadLibraryW(L"devmgr.dll");
+    if (hModule == NULL) return;
+
+    pDevicePropertiesExW DevicePropertiesExW;
+    DevicePropertiesExW = (pDevicePropertiesExW)GetProcAddress(hModule,
+                                                               "DevicePropertiesExW");
+    if (DevicePropertiesExW == NULL)
+    {
+        FreeLibrary(hModule);
+        return;
+    }
+#endif
+
+    CNode *Node = GetSelectedNode();
+    if (Node && Node->HasProperties())
+    {
+        DevicePropertiesExW(m_hTreeView,
+                            NULL,
+                            Node->GetDeviceId(),
+                            1,//DPF_EXTENDED,
+                            FALSE);
+    }
+
+#ifndef __REACTOS__
+    FreeLibrary(hModule);
+#endif
+}
+
+void
+CDeviceView::SetFocus()
+{
+}
+
+bool
+CDeviceView::CreateActionMenu(
+    _In_ HMENU OwnerMenu,
+    _In_ bool MainMenu
+    )
+{
+    CNode *Node = GetSelectedNode();
+    if (Node)
+    {
+        BuildActionMenuForNode(OwnerMenu, Node, MainMenu);
+        return true;
+    }
+
+    return false;
+}
+
+CNode*
+CDeviceView::GetSelectedNode()
+{
+    TV_ITEM TvItem;
+    TvItem.hItem = TreeView_GetSelection(m_hTreeView);
+    return GetNode(&TvItem);
+}
+
+
+
+// PRIVATE METHODS *******************************************/
+
+bool
+CDeviceView::AddRootDevice()
+{
+    m_hTreeRoot = InsertIntoTreeView(NULL, m_RootNode);
+    return (m_hTreeRoot != NULL);
+}
+
+bool
+CDeviceView::GetNextClass(
+    _In_ ULONG ClassIndex,
+    _Out_ LPGUID ClassGuid,
+    _Out_ HDEVINFO *hDevInfo
+    )
+{
+    CONFIGRET cr;
+
+    // Get the next class in the list
+    cr = CM_Enumerate_Classes(ClassIndex,
+                              ClassGuid,
+                              0);
+    if (cr != CR_SUCCESS) return false;
+
+    // Check if this is the unknown class
+    if (IsEqualGUID(*ClassGuid, GUID_DEVCLASS_UNKNOWN))
+    {
+        // Get device info for all devices
+        *hDevInfo = SetupDiGetClassDevsW(NULL,
+                                         NULL,
+                                         NULL,
+                                         DIGCF_ALLCLASSES);
+    }
+    else
+    {
+        // We only want the devices for this class
+        *hDevInfo = SetupDiGetClassDevsW(ClassGuid,
+                                         NULL,
+                                         NULL,
+                                         DIGCF_PRESENT);
+    }
+
+    return (hDevInfo != INVALID_HANDLE_VALUE);
+}
+
+unsigned int __stdcall CDeviceView::RefreshThread(void *Param)
+{
+    RefreshThreadData *ThreadData = (RefreshThreadData *)Param;
+    CDeviceView *This = ThreadData->This;
+
+
+    // Empty the treeview
+    This->EmptyDeviceView();
+    This->m_hTreeRoot = NULL;
+
+    // Refresh the devices only if requested. This means
+    // switching views uses the cache and remains fast
+    if (ThreadData->ScanForChanges)
+    {
+        This->RefreshDeviceList();
+    }
+
+    // display the type of view the user wants
+    switch (This->m_ViewType)
+    {
+        case DevicesByType:
+            (void)This->ListDevicesByType();
+            break;
+
+        case DevicesByConnection:
+            (VOID)This->ListDevicesByConnection();
+            break;
+
+        case ResourcesByType:
+            break;
+
+        case ResourcesByConnection:
+            break;
+    }
+
+
+    This->SelectNode(ThreadData->DeviceId);
+
+    if (ThreadData->DeviceId)
+        delete[] ThreadData->DeviceId;
+    delete ThreadData;
+
+    return 0;
+}
+
+
+bool
+CDeviceView::ListDevicesByType()
+{
+    CClassNode *ClassNode;
+    CDeviceNode *DeviceNode;
+    HDEVINFO hDevInfo;
+    HTREEITEM hTreeItem = NULL;
+    GUID ClassGuid;
+    INT ClassIndex;
+    BOOL bClassSuccess, bSuccess;
+
+    // Start by adding the root node to the tree
+    bSuccess = AddRootDevice();
+    if (bSuccess == false) return false;
+
+    ClassIndex = 0;
+    do
+    {
+        // Loop through all the device classes
+        bClassSuccess = GetNextClass(ClassIndex, &ClassGuid, &hDevInfo);
+        if (bClassSuccess)
+        {
+            bool bClassUnknown = false;
+            bool AddedParent = false;
+            INT DeviceIndex = 0;
+            bool MoreItems = false;
+
+            // Get the cached class node
+            ClassNode = GetClassNode(&ClassGuid);
+            if (ClassNode == NULL)
+            {
+                ATLASSERT(FALSE);
+                ClassIndex++;
+                continue;
+            }
+
+            // Set a flag is this is the (special case) unknown class
+            if (IsEqualGUID(ClassGuid, GUID_DEVCLASS_UNKNOWN))
+                bClassUnknown = true;
+
+            do
+            {
+                // Get a handle to all the devices in this class
+                SP_DEVINFO_DATA DeviceInfoData;
+                ZeroMemory(&DeviceInfoData, sizeof(SP_DEVINFO_DATA));
+                DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
+                bSuccess = SetupDiEnumDeviceInfo(hDevInfo,
+                                                 DeviceIndex,
+                                                 &DeviceInfoData);
+                if (bSuccess == FALSE && GetLastError() == ERROR_NO_MORE_ITEMS)
+                    MoreItems = false;
+
+                if (bSuccess)
+                {
+                    MoreItems = true;
+
+                    // The unknown class handle contains all devices on the system,
+                    // and we're just looking for the ones with a null GUID
+                    if (bClassUnknown)
+                    {
+                        if (IsEqualGUID(DeviceInfoData.ClassGuid, GUID_NULL) == FALSE)
+                        {
+                            // This is a known device, we aren't interested in it
+                            DeviceIndex++;
+                            continue;
+                        }
+                    }
+
+                    // Get the cached device node
+                    DeviceNode = GetDeviceNode(DeviceInfoData.DevInst);
+                    if (DeviceNode == NULL)
+                    {
+                        ATLASSERT(bClassUnknown == true);
+                        DeviceIndex++;
+                        continue;
+                    }
+
+                    // Check if this is a hidden device
+                    if (DeviceNode->IsHidden())
+                    {
+                        // Ignore this device if we aren't displaying hidden devices
+                        if (m_ShowHidden == FALSE)
+                        {
+                            DeviceIndex++;
+                            continue;
+                        }
+                    }
+
+                    // We have a device, we need to add the parent if it hasn't yet been added
+                    if (AddedParent == false)
+                    {
+                        // Insert the new class under the root item
+                        hTreeItem = InsertIntoTreeView(m_hTreeRoot,
+                                                       ClassNode);
+                        AddedParent = true;
+                    }
+
+                    // Add the device under the class item node
+                    (void)InsertIntoTreeView(hTreeItem, DeviceNode);
+
+                    // Expand the class if it has a problem device
+                    if (DeviceNode->HasProblem())
+                    {
+                        (void)TreeView_Expand(m_hTreeView,
+                                              hTreeItem,
+                                              TVE_EXPAND);
+                    }
+                }
+
+                DeviceIndex++;
+
+            } while (MoreItems);
+
+            // If this class has devices, sort them alphabetically
+            if (AddedParent == true)
+            {
+                (void)TreeView_SortChildren(m_hTreeView,
+                                            hTreeItem,
+                                            0);
+            }
+        }
+
+        ClassIndex++;
+
+    } while (bClassSuccess);
+
+    // Sort the classes alphabetically
+    (void)TreeView_SortChildren(m_hTreeView,
+                                m_hTreeRoot,
+                                0);
+
+    // Expand the root item
+    (void)TreeView_Expand(m_hTreeView,
+                          m_hTreeRoot,
+                          TVE_EXPAND);
+
+    // Pre-select the root item
+    (VOID)TreeView_SelectItem(m_hTreeView,
+                              m_hTreeRoot);
+
+    return 0;
+}
+
+bool
+CDeviceView::ListDevicesByConnection()
+{
+    bool bSuccess;
+
+    // Start by adding the root node to the tree
+    bSuccess = AddRootDevice();
+    if (bSuccess == false) return false;
+
+    // Walk the device tree and add all the devices 
+    (void)RecurseChildDevices(m_RootNode->GetDeviceInst(), m_hTreeRoot);
+
+    // Expand the root item 
+    (void)TreeView_Expand(m_hTreeView,
+                          m_hTreeRoot,
+                          TVE_EXPAND);
+
+    return true;
+}
+
+bool
+CDeviceView::RecurseChildDevices(
+    _In_ DEVINST ParentDevice,
+    _In_ HTREEITEM hParentTreeItem
+    )
+{
+    HTREEITEM hDevItem = NULL;
+    DEVINST Device;
+    bool HasProblem = false;
+    bool bSuccess;
+
+    // Check if the parent has any child devices 
+    if (GetChildDevice(ParentDevice, &Device) == FALSE)
+        return true;
+
+    // Get the cached device node
+    CDeviceNode *DeviceNode;
+    DeviceNode = dynamic_cast<CDeviceNode *>(GetDeviceNode(Device));
+    if (DeviceNode == nullptr)
+    {
+        ATLASSERT(FALSE);
+        return false;
+    }
+
+    // Don't show hidden devices if not requested
+    if ((m_ShowHidden == TRUE) || (!(DeviceNode->IsHidden())))
+    {
+        // Add this device to the tree under its parent 
+        hDevItem = InsertIntoTreeView(hParentTreeItem,
+                                      DeviceNode);
+        if (hDevItem)
+        {
+            // Check if this child has any children itself 
+            if (!RecurseChildDevices(Device, hDevItem))
+                HasProblem = true;
+        }
+
+        if (DeviceNode->HasProblem())
+        {
+            HasProblem = true;
+        }
+    }
+
+
+    // Check for siblings
+    for (;;)
+    {
+        // Check if the parent device has anything at the same level 
+        bSuccess = GetSiblingDevice(Device, &Device);
+        if (bSuccess == FALSE) break;
+
+        DeviceNode = dynamic_cast<CDeviceNode *>(GetDeviceNode(Device));
+        if (DeviceNode == nullptr)
+        {
+            ATLASSERT(FALSE);
+        }
+
+        // Don't show hidden devices if not requested
+        if ((m_ShowHidden == TRUE) || (!(DeviceNode->IsHidden())))
+        {
+            if (DeviceNode->HasProblem())
+            {
+                HasProblem = true;
+            }
+
+            // Add this device to the tree under its parent 
+            hDevItem = InsertIntoTreeView(hParentTreeItem,
+                                          DeviceNode);
+            if (hDevItem)
+            {
+                // Check if this child has any children itself 
+                if (!RecurseChildDevices(Device, hDevItem))
+                    HasProblem = true;
+            }
+        }
+    }
+
+    (void)TreeView_SortChildren(m_hTreeView,
+                                hParentTreeItem,
+                                0);
+
+    // Expand the class if it has a problem device
+    if (HasProblem == true)
+    {
+        (void)TreeView_Expand(m_hTreeView,
+                              hParentTreeItem,
+                              TVE_EXPAND);
+    }
+
+    // If there was a problem, expand the ancestors
+    if (HasProblem) return false;
+
+    return true;
+}
+
+bool
+CDeviceView::EnableSelectedDevice(
+    _In_ bool Enable,
+    _Out_ bool &NeedsReboot
+    )
+{
+    CDeviceNode *Node = dynamic_cast<CDeviceNode *>(GetSelectedNode());
+    if (Node == nullptr) return false;
+
+    if (Enable == false)
+    {
+        CAtlStringW str;
+        if (str.LoadStringW(g_hInstance, IDS_CONFIRM_DISABLE))
+        {
+            if (MessageBoxW(m_hMainWnd,
+                str,
+                Node->GetDisplayName(),
+                MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2) != IDYES)
+            {
+                return false;
+            }
+        }
+    }
+
+    if (Node->EnableDevice(Enable, NeedsReboot))
+    {
+        Refresh(m_ViewType, true, true, Node->GetDeviceId());
+        return true;
+    }
+
+    return false;
+}
+
+bool
+CDeviceView::UninstallSelectedDevice(
+    )
+{
+    CDeviceNode *Node = dynamic_cast<CDeviceNode *>(GetSelectedNode());
+    if (Node == nullptr) return false;
+
+    return Node->UninstallDevice();
+}
+
+bool
+CDeviceView::GetChildDevice(
+    _In_ DEVINST ParentDevInst,
+    _Out_ PDEVINST DevInst
+)
+{
+    CONFIGRET cr;
+    cr = CM_Get_Child(DevInst,
+                      ParentDevInst,
+                      0);
+    return (cr == CR_SUCCESS);
+}
+
+bool
+CDeviceView::GetSiblingDevice(
+    _In_ DEVINST PrevDevice,
+    _Out_ PDEVINST DevInst
+)
+{
+    CONFIGRET cr;
+    cr = CM_Get_Sibling(DevInst,
+                        PrevDevice,
+                        0);
+    return (cr == CR_SUCCESS);
+}
+
+HTREEITEM
+CDeviceView::InsertIntoTreeView(
+    _In_opt_ HTREEITEM hParent,
+    _In_ CNode *Node
+    )
+{
+    LPWSTR lpLabel;
+    lpLabel = Node->GetDisplayName();
+
+    TV_ITEMW tvi;
+    TV_INSERTSTRUCT tvins;
+    ZeroMemory(&tvi, sizeof(tvi));
+    ZeroMemory(&tvins, sizeof(tvins));
+
+    tvi.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+    tvi.pszText = lpLabel;
+    tvi.cchTextMax = wcslen(lpLabel);
+    tvi.lParam = (LPARAM)Node;
+    tvi.iImage = Node->GetClassImage();
+    tvi.iSelectedImage = Node->GetClassImage();
+
+    // try to cast it to a device node. This will only suceed if it's the correct type
+    CDeviceNode *DeviceNode = dynamic_cast<CDeviceNode *>(Node);
+    if (DeviceNode && DeviceNode->GetOverlayImage())
+    {
+        tvi.mask |= TVIF_STATE;
+        tvi.stateMask = TVIS_OVERLAYMASK;
+        tvi.state = INDEXTOOVERLAYMASK(DeviceNode->GetOverlayImage());
+    }
+
+    tvins.item = tvi;
+    tvins.hParent = hParent;
+
+    return TreeView_InsertItem(m_hTreeView, &tvins);
+}
+
+void
+CDeviceView::BuildActionMenuForNode(
+    _In_ HMENU OwnerMenu,
+    _In_ CNode *Node,
+    _In_ bool MainMenu
+    )
+{
+    // Create a seperator structure 
+    MENUITEMINFOW MenuSeperator = { 0 };
+    MenuSeperator.cbSize = sizeof(MENUITEMINFOW);
+    MenuSeperator.fType = MFT_SEPARATOR;
+
+    // Setup the 
+    MENUITEMINFOW MenuItemInfo = { 0 };
+    MenuItemInfo.cbSize = sizeof(MENUITEMINFOW);
+    MenuItemInfo.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA | MIIM_SUBMENU;
+    MenuItemInfo.fType = MFT_STRING;
+
+    CAtlStringW String;
+    int i = 0;
+
+    // Device nodes have extra data
+    if (Node->GetNodeType() == DeviceNode)
+    {
+        CDeviceNode *DeviceNode = dynamic_cast<CDeviceNode *>(Node);
+
+        if (DeviceNode->CanUpdate())
+        {
+            String.LoadStringW(g_hInstance, IDS_MENU_UPDATE);
+            MenuItemInfo.wID = IDC_UPDATE_DRV;
+            MenuItemInfo.dwTypeData = String.GetBuffer();
+            InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo);
+            i++;
+        }
+
+        if (DeviceNode->IsDisabled())
+        {
+            String.LoadStringW(g_hInstance, IDS_MENU_ENABLE);
+            MenuItemInfo.wID = IDC_ENABLE_DRV;
+            MenuItemInfo.dwTypeData = String.GetBuffer();
+            InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo);
+            i++;
+        }
+
+        if (DeviceNode->CanDisable() && !DeviceNode->IsDisabled())
+        {
+            String.LoadStringW(g_hInstance, IDS_MENU_DISABLE);
+            MenuItemInfo.wID = IDC_DISABLE_DRV;
+            MenuItemInfo.dwTypeData = String.GetBuffer();
+            InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo);
+            i++;
+        }
+
+        if (DeviceNode->CanUninstall())
+        {
+            String.LoadStringW(g_hInstance, IDS_MENU_UNINSTALL);
+            MenuItemInfo.wID = IDC_UNINSTALL_DRV;
+            MenuItemInfo.dwTypeData = String.GetBuffer();
+            InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo);
+            i++;
+        }
+
+        InsertMenuItemW(OwnerMenu, i, TRUE, &MenuSeperator);
+        i++;
+    }
+
+    // All nodes have the scan option
+    String.LoadStringW(g_hInstance, IDS_MENU_SCAN);
+    MenuItemInfo.wID = IDC_SCAN_HARDWARE;
+    MenuItemInfo.dwTypeData = String.GetBuffer();
+    InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo);
+    i++;
+
+    if ((Node->GetNodeType() == RootNode) || (MainMenu == true))
+    {
+        String.LoadStringW(g_hInstance, IDS_MENU_ADD);
+        MenuItemInfo.wID = IDC_ADD_HARDWARE;
+        MenuItemInfo.dwTypeData = String.GetBuffer();
+        InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo);
+        i++;
+    }
+
+    if (Node->HasProperties())
+    {
+        InsertMenuItemW(OwnerMenu, i, TRUE, &MenuSeperator);
+        i++;
+
+        String.LoadStringW(g_hInstance, IDS_MENU_PROPERTIES);
+        MenuItemInfo.wID = IDC_PROPERTIES;
+        MenuItemInfo.dwTypeData = String.GetBuffer();
+        InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo);
+        i++;
+
+        SetMenuDefaultItem(OwnerMenu, IDC_PROPERTIES, FALSE);
+    }
+}
+
+HTREEITEM
+CDeviceView::RecurseFindDevice(
+    _In_ HTREEITEM hParentItem,
+    _In_ LPWSTR DeviceId
+    )
+{
+    HTREEITEM FoundItem;
+    HTREEITEM hItem;
+    TVITEMW tvItem;
+    CNode *Node;
+
+    // Check if this node has any children
+    hItem = TreeView_GetChild(m_hTreeView, hParentItem);
+    if (hItem == NULL) return NULL;
+
+    // The lParam contains the node pointer data
+    tvItem.hItem = hItem;
+    tvItem.mask = TVIF_PARAM;
+    if (TreeView_GetItem(m_hTreeView, &tvItem) &&
+        tvItem.lParam != NULL)
+    {
+        // check for a matching deviceid
+        Node = reinterpret_cast<CNode *>(tvItem.lParam);
+        if (Node->GetDeviceId() &&
+            (wcscmp(Node->GetDeviceId(), DeviceId) == 0))
+        {
+            return hItem;
+        }
+    }
+
+    // This node may have its own children
+    FoundItem = RecurseFindDevice(hItem, DeviceId);
+    if (FoundItem) return FoundItem;
+
+    // Loop all the siblings
+    for (;;)
+    {
+        // Get the next item at this level
+        hItem = TreeView_GetNextSibling(m_hTreeView, hItem);
+        if (hItem == NULL) break;
+
+        // The lParam contains the node pointer data
+        tvItem.hItem = hItem;
+        tvItem.mask = TVIF_PARAM;
+        if (TreeView_GetItem(m_hTreeView, &tvItem))
+        {
+            // check for a matching deviceid
+            Node = reinterpret_cast<CNode *>(tvItem.lParam);
+            if (Node->GetDeviceId() && 
+                wcscmp(Node->GetDeviceId(), DeviceId) == 0)
+            {
+                return hItem;
+            }
+        }
+
+        // This node may have its own children 
+        FoundItem = RecurseFindDevice(hItem, DeviceId);
+        if (FoundItem) return FoundItem;
+    }
+
+    return hItem;
+}
+
+void
+CDeviceView::SelectNode(
+    _In_ LPWSTR DeviceId
+    )
+{
+    HTREEITEM hRoot, hItem;
+
+    // Check if there are any items in the tree
+    hRoot = TreeView_GetRoot(m_hTreeView);
+    if (hRoot == NULL) return;
+
+    // If we don't want to set select a node, just select root
+    if (DeviceId == NULL)
+    {
+        TreeView_SelectItem(m_hTreeView, hRoot);
+        return;
+    }
+
+    // Scan the tree looking for the node we want
+    hItem = RecurseFindDevice(hRoot, DeviceId);
+    if (hItem)
+    {
+        TreeView_SelectItem(m_hTreeView, hItem);
+        TreeView_Expand(m_hTreeView, hItem, TVM_EXPAND);
+    }
+    else
+    {
+        TreeView_SelectItem(m_hTreeView, hRoot);
+    }
+}
+
+
+void
+CDeviceView::EmptyDeviceView()
+{
+    (VOID)TreeView_DeleteAllItems(m_hTreeView);
+}
+
+
+CClassNode*
+CDeviceView::GetClassNode(
+    _In_ LPGUID ClassGuid
+    )
+{
+    POSITION Pos;
+    CClassNode *Node;
+
+    Pos = m_ClassNodeList.GetHeadPosition();
+
+    do
+    {
+        Node = m_ClassNodeList.GetNext(Pos);
+        if (IsEqualGUID(*Node->GetClassGuid(), *ClassGuid))
+        {
+            //ATLASSERT(Node->GetType() == NodeClass);
+            break;
+        }
+
+        Node = NULL;
+
+    } while (Pos != NULL);
+
+    return Node;
+}
+
+CDeviceNode*
+CDeviceView::GetDeviceNode(
+    _In_ DEVINST Device
+    )
+{
+    POSITION Pos;
+    CDeviceNode *Node;
+
+    Pos = m_DeviceNodeList.GetHeadPosition();
+
+    do
+    {
+        Node = m_DeviceNodeList.GetNext(Pos);
+        if (Node->GetDeviceInst() == Device)
+        {
+            //ATLASSERT(Node->GetType() == NodeDevice);
+            break;
+        }
+
+        Node = NULL;
+
+    } while (Pos != NULL);
+
+    return Node;
+}
+
+CNode* CDeviceView::GetNode(
+    _In_ LPTV_ITEMW TvItem
+    )
+{
+    TvItem->mask = TVIF_PARAM;
+    if (TreeView_GetItem(m_hTreeView, TvItem))
+    {
+        return (CNode *)TvItem->lParam;
+    }
+    return NULL;
+}
+
+void
+CDeviceView::EmptyLists()
+{
+    CNode *Node;
+
+    while (!m_ClassNodeList.IsEmpty())
+    {
+        Node = m_ClassNodeList.RemoveTail();
+        delete Node;
+    }
+
+    while (!m_DeviceNodeList.IsEmpty())
+    {
+        Node = m_DeviceNodeList.RemoveTail();
+        delete Node;
+    }
+}
+
+bool
+CDeviceView::RefreshDeviceList()
+{
+    GUID ClassGuid;
+    CClassNode *ClassNode;
+    CDeviceNode *DeviceNode;
+    HDEVINFO hDevInfo;
+    SP_DEVINFO_DATA DeviceInfoData;
+    DWORD i;
+    BOOL Success;
+
+    ULONG ClassIndex = 0;
+
+    EmptyLists();
+
+    if (m_RootNode) delete m_RootNode;
+    m_RootNode = new CRootNode(&m_ImageListData);
+    m_RootNode->SetupNode();
+    // Loop through all the classes
+    do
+    {
+        Success = GetNextClass(ClassIndex, &ClassGuid, &hDevInfo);
+        if (Success)
+        {
+            // Create a new class node and add it to the list
+            ClassNode = new CClassNode(&ClassGuid, &m_ImageListData);
+            if (ClassNode->SetupNode())
+            {
+                m_ClassNodeList.AddTail(ClassNode);
+            }
+
+            SetupDiDestroyDeviceInfoList(hDevInfo);
+        }
+        ClassIndex++;
+    } while (Success);
+
+
+    // Get all the devices on the local machine
+    hDevInfo = SetupDiGetClassDevsW(NULL,
+                                    0,
+                                    0,
+                                    DIGCF_PRESENT | DIGCF_ALLCLASSES);
+    if (hDevInfo == INVALID_HANDLE_VALUE)
+    {
+        return false;
+    }
+
+    // loop though all the devices
+    DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
+    for (i = 0;; i++)
+    {
+        // Get the devinst for this device
+        Success = SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData);
+        if (Success == FALSE) break;
+
+        // create a new device node and add it to the list
+        DeviceNode = new CDeviceNode(DeviceInfoData.DevInst, &m_ImageListData);
+        if (DeviceNode->SetupNode())
+        {
+            m_DeviceNodeList.AddTail(DeviceNode);
+        }
+    }
+
+    SetupDiDestroyDeviceInfoList(hDevInfo);
+
+    return TRUE;
+}
\ No newline at end of file
diff --git a/reactos/dll/win32/devmgr_new/devmgmt/DeviceView.h b/reactos/dll/win32/devmgr_new/devmgmt/DeviceView.h
new file mode 100644 (file)
index 0000000..70fe84d
--- /dev/null
@@ -0,0 +1,165 @@
+#pragma once
+#include "DeviceNode.h"
+#include "ClassNode.h"
+#include "RootNode.h"
+
+enum ViewType
+{
+    DevicesByType,
+    DevicesByConnection,
+    ResourcesByType,
+    ResourcesByConnection
+};
+
+
+class CDeviceView
+{
+    CRootNode *m_RootNode;
+    CAtlList<CClassNode *> m_ClassNodeList;
+    CAtlList<CDeviceNode *> m_DeviceNodeList;
+    SP_CLASSIMAGELIST_DATA m_ImageListData;
+    HWND m_hMainWnd;
+    HWND m_hTreeView;
+    HWND m_hPropertyDialog;
+    HMENU m_hMenu;
+    ViewType m_ViewType;
+    HTREEITEM m_hTreeRoot;
+    bool m_ShowHidden;
+
+public:
+    CDeviceView(
+        HWND hMainWnd
+        );
+
+    ~CDeviceView(void);
+
+    bool Initialize();
+    bool Uninitialize();
+
+    LRESULT OnSize(
+        _In_ int x,
+        _In_ int y,
+        _In_ int cx,
+        _In_ int cy
+        );
+
+    LRESULT OnRightClick(
+        _In_ LPNMHDR NmHdr
+        );
+
+    LRESULT OnContextMenu(
+        _In_ LPARAM lParam
+        );
+
+    LRESULT OnAction(
+        UINT Action
+        );
+
+    VOID Refresh(
+        _In_ ViewType Type,
+        _In_ bool ScanForChanges,
+        _In_ bool UpdateView,
+        _In_opt_ LPWSTR DeviceId
+        );
+
+    VOID DisplayPropertySheet();
+    VOID SetFocus();
+
+    VOID SetHiddenDevices(_In_ bool ShowHidden)
+    {
+        m_ShowHidden = ShowHidden;
+    }
+
+    ViewType GetCurrentView() { return m_ViewType; }
+
+    bool CreateActionMenu(
+        _In_ HMENU OwnerMenu,
+        _In_ bool MainMenu
+        );
+
+    CNode* GetSelectedNode(
+        );
+
+    bool SelDeviceIsStarted();
+    bool SelDeviceIsInstalled();
+
+private:
+    bool AddRootDevice();
+
+    bool RefreshDeviceList();
+
+    static unsigned int __stdcall RefreshThread(
+        void *Param
+        );
+
+    bool ListDevicesByConnection(
+        );
+    bool ListDevicesByType(
+        );
+
+    bool GetNextClass(
+        _In_ ULONG ClassIndex,
+        _Out_ LPGUID ClassGuid,
+        _Out_ HDEVINFO *hDevInfo
+        );
+
+    bool RecurseChildDevices(
+        _In_ DEVINST ParentDevice,
+        _In_ HTREEITEM hParentTreeItem
+        );
+
+    bool EnableSelectedDevice(
+        _In_ bool Enable,
+        _Out_ bool &NeedsReboot
+        );
+
+    bool UninstallSelectedDevice(
+        );
+
+    bool GetChildDevice(
+        _In_ DEVINST ParentDevInst,
+        _Out_ PDEVINST DevInst
+        );
+
+    bool GetSiblingDevice(
+        _In_ DEVINST PrevDevice,
+        _Out_ PDEVINST DevInst
+        );
+
+    HTREEITEM InsertIntoTreeView(
+        _In_opt_ HTREEITEM hParent,
+        _In_ CNode *Node
+        );
+
+    void BuildActionMenuForNode(
+        _In_ HMENU OwnerMenu,
+        _In_ CNode *Node,
+        _In_ bool MainMenu
+        );
+
+    HTREEITEM RecurseFindDevice(
+        _In_ HTREEITEM hParentItem,
+        _In_ LPWSTR DeviceId
+        );
+
+    void SelectNode(
+        _In_ LPWSTR DeviceId
+        );
+
+    void EmptyDeviceView(
+        );
+
+    CNode* GetNode(
+        _In_ LPTV_ITEMW TvItem
+        );
+
+    CClassNode* GetClassNode(
+        _In_ LPGUID ClassGuid
+        );
+    CDeviceNode* GetDeviceNode(
+        _In_ DEVINST Device
+        );
+    void EmptyLists(
+        );
+};
+
diff --git a/reactos/dll/win32/devmgr_new/devmgmt/MainWindow.cpp b/reactos/dll/win32/devmgr_new/devmgmt/MainWindow.cpp
new file mode 100644 (file)
index 0000000..6f43b4f
--- /dev/null
@@ -0,0 +1,827 @@
+/*
+ * PROJECT:     ReactOS Device Manager
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        dll/win32/devmgr/devmgr/MainWindow.cpp
+ * PURPOSE:     Implements the main container window for the device view
+ * COPYRIGHT:   Copyright 2014 - 2015 Ged Murphy <gedmurphy@reactos.org>
+ */
+
+
+#include "stdafx.h"
+#include "devmgmt.h"
+#include "MainWindow.h"
+
+
+/* DATA *****************************************************/
+
+#define BTN_PROPERTIES      0
+#define BTN_SCAN_HARDWARE   1
+#define BTN_ENABLE_DRV      2
+#define BTN_DISABLE_DRV     3
+#define BTN_UPDATE_DRV      4
+#define BTN_UNINSTALL_DRV   5
+
+
+// menu hints
+static const MENU_HINT MainMenuHintTable[] =
+{
+    // File Menu
+    { IDC_EXIT, IDS_HINT_EXIT },
+
+    // Action Menu
+    { IDC_PROPERTIES, IDS_HINT_PROPERTIES },
+    { IDC_SCAN_HARDWARE, IDS_HINT_SCAN },
+    { IDC_ENABLE_DRV, IDS_HINT_ENABLE },
+    { IDC_DISABLE_DRV, IDS_HINT_DISABLE },
+    { IDC_UPDATE_DRV, IDS_HINT_UPDATE },  
+    { IDC_UNINSTALL_DRV, IDS_HINT_UNINSTALL },
+    { IDC_ADD_HARDWARE, IDS_HINT_ADD },
+    
+
+    // View Menu
+    { IDC_DEVBYTYPE, IDS_HINT_DEV_BY_TYPE},
+    { IDC_DEVBYCONN, IDS_HINT_DEV_BY_CONN},
+    { IDC_RESBYTYPE, IDS_HINT_RES_BY_TYPE},
+    { IDC_RESBYCONN, IDS_HINT_RES_BY_TYPE},
+    { IDC_SHOWHIDDEN, IDS_HINT_SHOW_HIDDEN },
+
+    { IDC_ABOUT, IDS_HINT_ABOUT }
+
+};
+
+
+// system menu hints
+static const MENU_HINT SystemMenuHintTable[] =
+{
+    {SC_RESTORE,    IDS_HINT_SYS_RESTORE},
+    {SC_MOVE,       IDS_HINT_SYS_MOVE},
+    {SC_SIZE,       IDS_HINT_SYS_SIZE},
+    {SC_MINIMIZE,   IDS_HINT_SYS_MINIMIZE},
+    {SC_MAXIMIZE,   IDS_HINT_SYS_MAXIMIZE},
+    {SC_CLOSE,      IDS_HINT_SYS_CLOSE},
+};
+
+static TBBUTTON TbButtons[] =
+{
+    { BTN_PROPERTIES, IDC_PROPERTIES, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 },
+    { BTN_SCAN_HARDWARE, IDC_SCAN_HARDWARE, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 },
+    { 2, IDC_STATIC, TBSTATE_ENABLED, BTNS_SEP, 0, 0 },
+    { BTN_ENABLE_DRV, IDC_ENABLE_DRV, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 },
+    { BTN_DISABLE_DRV, IDC_DISABLE_DRV, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 },
+    { BTN_UPDATE_DRV, IDC_UPDATE_DRV, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 },
+    { BTN_UNINSTALL_DRV, IDC_UNINSTALL_DRV, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0 }
+};
+
+
+/* PUBLIC METHODS **********************************************/
+
+CMainWindow::CMainWindow(void) :
+    m_ToolbarhImageList(NULL),
+    m_hMainWnd(NULL),
+    m_hStatusBar(NULL),
+    m_hToolBar(NULL),
+    m_CmdShow(0)
+{
+    m_szMainWndClass = L"DevMgmtWndClass";
+}
+
+CMainWindow::~CMainWindow(void)
+{
+    // Destroy any previous list
+    if (m_ToolbarhImageList) ImageList_Destroy(m_ToolbarhImageList);
+}
+
+bool
+CMainWindow::Initialize(LPCTSTR lpCaption,
+                        int nCmdShow)
+{
+    CAtlStringW szCaption;
+    WNDCLASSEXW wc = {0};
+
+    // Store the show window value
+    m_CmdShow = nCmdShow;
+
+    // Setup the window class struct
+    wc.cbSize = sizeof(WNDCLASSEXW);
+    wc.lpfnWndProc = MainWndProc;
+    wc.hInstance = g_hInstance;
+    wc.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCEW(IDI_MAIN_ICON));
+    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+    wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
+    wc.lpszMenuName = MAKEINTRESOURCEW(IDR_MAINMENU);
+    wc.lpszClassName = m_szMainWndClass;
+    wc.hIconSm = (HICON)LoadImage(g_hInstance,
+                                  MAKEINTRESOURCE(IDI_MAIN_ICON),
+                                  IMAGE_ICON,
+                                  16,
+                                  16,
+                                  LR_SHARED);
+
+    // Register the window
+    if (RegisterClassExW(&wc))
+    {
+        // Create the main window and store the object pointer
+        m_hMainWnd = CreateWindowExW(WS_EX_WINDOWEDGE,
+                                     m_szMainWndClass,
+                                     lpCaption,
+                                     WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
+                                     CW_USEDEFAULT,
+                                     CW_USEDEFAULT,
+                                     550,
+                                     500,
+                                     NULL,
+                                     NULL,
+                                     g_hInstance,
+                                     this);
+    }
+
+    // Return creation result 
+    return !!(m_hMainWnd);
+}
+
+void
+CMainWindow::Uninitialize()
+{
+    // Unregister the window class 
+    UnregisterClassW(m_szMainWndClass, g_hInstance);
+}
+
+int
+CMainWindow::Run()
+{
+    MSG Msg;
+
+    // Pump the message queue 
+    while (GetMessageW(&Msg, NULL, 0, 0 ) != 0)
+    {
+        TranslateMessage(&Msg);
+        DispatchMessageW(&Msg);
+    }
+
+    return 0;
+}
+
+
+/* PRIVATE METHODS **********************************************/
+
+bool
+CMainWindow::MainWndMenuHint(WORD CmdId,
+                             const MENU_HINT *HintArray,
+                             DWORD HintsCount,
+                             UINT DefHintId)
+{
+    bool Found = false;
+    const MENU_HINT *LastHint;
+    UINT HintId = DefHintId;
+
+    LastHint = HintArray + HintsCount;
+    while (HintArray != LastHint)
+    {
+        if (HintArray->CmdId == CmdId)
+        {
+            HintId = HintArray->HintId;
+            Found = true;
+            break;
+        }
+        HintArray++;
+    }
+
+    StatusBarLoadString(m_hStatusBar,
+                        SB_SIMPLEID,
+                        g_hInstance,
+                        HintId);
+
+    return Found;
+}
+
+void
+CMainWindow::UpdateStatusBar(
+    _In_ bool InMenuLoop
+    )
+{
+    SendMessageW(m_hStatusBar,
+                 SB_SIMPLE,
+                 (WPARAM)InMenuLoop,
+                 0);
+}
+
+bool
+CMainWindow::RefreshView(ViewType Type)
+{
+    UINT CheckId = 0;
+    BOOL bSuccess;
+
+    // Refreshed the cached view
+    m_DeviceView->Refresh(Type, FALSE, TRUE, NULL);
+
+    // Get the menu item id
+    switch (Type)
+    {
+        case DevicesByType: CheckId = IDC_DEVBYTYPE; break;
+        case DevicesByConnection: CheckId = IDC_DEVBYCONN; break;
+        case ResourcesByType: CheckId = IDC_RESBYTYPE; break;
+        case ResourcesByConnection: CheckId = IDC_RESBYCONN; break;
+        default: ATLASSERT(FALSE); break;
+    }
+
+    // Set the new check item
+    bSuccess = CheckMenuRadioItem(m_hMenu,
+                                  IDC_DEVBYTYPE,
+                                  IDC_RESBYCONN,
+                                  CheckId,
+                                  MF_BYCOMMAND);
+
+    return TRUE;
+}
+
+bool
+CMainWindow::CreateToolBar()
+{
+    TBADDBITMAP TbAddBitmap;
+    INT Index;
+
+    DWORD dwStyles = WS_CHILDWINDOW | TBSTYLE_FLAT | TBSTYLE_WRAPABLE | TBSTYLE_TOOLTIPS | CCS_NODIVIDER;
+    DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
+
+    // Create the toolbar window
+    m_hToolBar = CreateWindowExW(dwExStyles,
+                                 TOOLBARCLASSNAME,
+                                 NULL,
+                                 dwStyles,
+                                 0, 0, 0, 0,
+                                 m_hMainWnd,
+                                 (HMENU)IDC_TOOLBAR,
+                                 g_hInstance,
+                                 NULL);
+    if (m_hToolBar == NULL) return FALSE;
+
+    // Don't show clipped buttons
+    SendMessageW(m_hToolBar,
+                 TB_SETEXTENDEDSTYLE,
+                 0,
+                 TBSTYLE_EX_HIDECLIPPEDBUTTONS);
+
+    SendMessageW(m_hToolBar, TB_SETBITMAPSIZE, 0, MAKELONG(16, 16));
+
+    // Set the struct size, the toobar needs this...
+    SendMessageW(m_hToolBar,
+                 TB_BUTTONSTRUCTSIZE,
+                 sizeof(TBBUTTON),
+                 0);
+
+    TbAddBitmap.hInst = g_hInstance;
+    TbAddBitmap.nID = IDB_TOOLBAR;
+    Index = SendMessageW(m_hToolBar, TB_ADDBITMAP, _countof(TbButtons), (LPARAM)&TbAddBitmap);
+
+    SendMessageW(m_hToolBar, TB_ADDBUTTONSW, _countof(TbButtons), (LPARAM)TbButtons);
+    SendMessageW(m_hToolBar, TB_AUTOSIZE, 0, 0);
+
+    if (TRUE)
+    {
+        ShowWindow(m_hToolBar, SW_SHOW);
+    }
+
+    return TRUE;
+}
+
+bool
+CMainWindow::CreateStatusBar()
+{
+    int StatWidths[] = {110, -1}; // widths of status bar
+    bool bRet = FALSE;
+
+    // Create the status bar
+    m_hStatusBar = CreateWindowExW(0,
+                                   STATUSCLASSNAME,
+                                   NULL,
+                                   WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP,
+                                   0, 0, 0, 0,
+                                   m_hMainWnd,
+                                   (HMENU)IDC_STATUSBAR,
+                                   g_hInstance,
+                                   NULL);
+    if (m_hStatusBar)
+    {
+        // Set the width
+        bRet = (SendMessageW(m_hStatusBar,
+                             SB_SETPARTS,
+                             sizeof(StatWidths) / sizeof(int),
+                             (LPARAM)StatWidths) != 0);
+    }
+
+    return bRet;
+}
+
+void CMainWindow::UpdateToolbar()
+{
+    WORD State;
+
+    CNode *Node = m_DeviceView->GetSelectedNode();
+
+    // properties button
+    if (Node->HasProperties())
+    {
+        State = TBSTATE_ENABLED;
+    }
+    else
+    {
+        State = TBSTATE_HIDDEN;
+    }
+    SendMessageW(m_hToolBar, TB_SETSTATE, IDC_PROPERTIES, MAKELPARAM(State, 0));
+    SendMessageW(m_hToolBar, TB_SETSTATE, IDC_UPDATE_DRV, MAKELPARAM(State, 0)); //hack
+    SendMessageW(m_hToolBar, TB_SETSTATE, IDC_UNINSTALL_DRV, MAKELPARAM(State, 0)); // hack
+
+
+
+    // enable driver button
+    if (Node->GetNodeType() == DeviceNode &&
+        dynamic_cast<CDeviceNode *>(Node)->IsDisabled())
+    {
+        State = TBSTATE_ENABLED;
+    }
+    else
+    {
+        State = TBSTATE_HIDDEN;
+    }
+    SendMessageW(m_hToolBar, TB_SETSTATE, IDC_ENABLE_DRV, MAKELPARAM(State, 0));
+
+    // disable driver button
+    if (Node->GetNodeType() == DeviceNode &&
+        dynamic_cast<CDeviceNode *>(Node)->CanDisable() &&
+        !dynamic_cast<CDeviceNode *>(Node)->IsDisabled())
+    {
+        State = TBSTATE_ENABLED;
+    }
+    else
+    {
+        State = TBSTATE_HIDDEN;
+    }
+    SendMessageW(m_hToolBar, TB_SETSTATE, IDC_DISABLE_DRV, MAKELPARAM(State, 0));
+
+
+
+    
+
+}
+
+
+
+bool
+CMainWindow::StatusBarLoadString(IN HWND hStatusBar,
+                                 IN INT PartId,
+                                 IN HINSTANCE hInstance,
+                                 IN UINT uID)
+{
+    CAtlStringW szMessage;
+    bool bRet = false;
+
+    // Load the string
+    if (szMessage.LoadStringW(hInstance, uID))
+    {
+        // Show the string on the status bar
+        bRet = (SendMessageW(hStatusBar,
+                             SB_SETTEXT,
+                             (WPARAM)PartId,
+                             (LPARAM)szMessage.GetBuffer()) != 0);
+    }
+
+    return bRet;
+}
+
+LRESULT
+CMainWindow::OnCreate(HWND hwnd)
+{
+    LRESULT RetCode;
+
+    RetCode = -1;
+    m_hMainWnd = hwnd;
+
+    // Store a handle to the main menu
+    m_hMenu = GetMenu(m_hMainWnd);
+
+    // Create the toolbar and statusbar
+    if (CreateToolBar() && CreateStatusBar())
+    {
+        // Create the device view object
+        m_DeviceView = new CDeviceView(m_hMainWnd);
+        if (m_DeviceView->Initialize())
+        {
+            // Do the initial scan
+            m_DeviceView->Refresh(m_DeviceView->GetCurrentView(),
+                                  true,
+                                  true,
+                                  NULL);
+
+            // Display the window according to the user request
+            ShowWindow(hwnd, m_CmdShow);
+            RetCode = 0;
+        }
+    }
+
+    return RetCode;
+}
+
+LRESULT
+CMainWindow::OnSize()
+{
+    RECT rcClient, rcTool, rcStatus;
+    INT lvHeight, iToolHeight, iStatusHeight;
+
+    // Autosize the toolbar
+    SendMessage(m_hToolBar, TB_AUTOSIZE, 0, 0);
+
+    // Get the toolbar rect and save the height
+    GetWindowRect(m_hToolBar, &rcTool);
+    iToolHeight = rcTool.bottom - rcTool.top;
+
+    // Resize the status bar
+    SendMessage(m_hStatusBar, WM_SIZE, 0, 0);
+
+    // Get the statusbar rect and save the height
+    GetWindowRect(m_hStatusBar, &rcStatus);
+    iStatusHeight = rcStatus.bottom - rcStatus.top;
+
+    // Get the full client rect
+    GetClientRect(m_hMainWnd, &rcClient);
+
+    // Calculate the remaining height for the treeview
+    lvHeight = rcClient.bottom - iToolHeight - iStatusHeight;
+
+    // Resize the device view
+    m_DeviceView->OnSize(0,
+                         iToolHeight,
+                         rcClient.right,
+                         lvHeight);
+
+    return 0;
+}
+
+LRESULT
+CMainWindow::OnNotify(LPARAM lParam)
+{
+    LPNMHDR NmHdr = (LPNMHDR)lParam;
+    LRESULT Ret;
+
+    switch (NmHdr->code)
+    {
+        case TVN_SELCHANGED:
+        {
+            UpdateToolbar();
+            break;
+        }
+
+        case NM_DBLCLK:
+        {
+            m_DeviceView->DisplayPropertySheet();
+            break;
+        }
+
+        case NM_RCLICK:
+        {
+            Ret = m_DeviceView->OnRightClick(NmHdr);
+            break;
+        }
+
+        case NM_RETURN:
+        {
+            m_DeviceView->DisplayPropertySheet();
+            break;
+        }
+
+        case TTN_GETDISPINFO:
+        {
+             LPTOOLTIPTEXT lpttt = (LPTOOLTIPTEXT)lParam;
+
+            UINT_PTR idButton = lpttt->hdr.idFrom;
+            switch (idButton)
+            {
+                case IDC_PROPERTIES:
+                    lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_PROPERTIES);
+                    break;
+                case IDC_SCAN_HARDWARE:
+                    lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_SCAN);
+                    break;
+                case IDC_ENABLE_DRV:
+                    lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_ENABLE);
+                    break;
+                case IDC_DISABLE_DRV:
+                    lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_DISABLE);
+                    break;
+                case IDC_UPDATE_DRV:
+                    lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_UPDATE);
+                    break;
+                case IDC_UNINSTALL_DRV:
+                    lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_UNINSTALL);
+                    break;
+            }
+            break;
+        }
+    }
+
+    return 0;
+}
+
+LRESULT
+CMainWindow::OnContext(LPARAM lParam)
+{
+    return m_DeviceView->OnContextMenu(lParam);
+}
+
+LRESULT
+CMainWindow::OnCommand(WPARAM wParam,
+                       LPARAM /*lParam*/)
+{
+    LRESULT RetCode = 0;
+    WORD Msg;
+
+    // Get the message
+    Msg = LOWORD(wParam);
+
+    switch (Msg)
+    {
+        case IDC_PROPERTIES:
+        case IDC_SCAN_HARDWARE:
+        case IDC_ENABLE_DRV:
+        case IDC_DISABLE_DRV:
+        case IDC_UPDATE_DRV:
+        case IDC_UNINSTALL_DRV:
+        case IDC_ADD_HARDWARE:
+        {
+            m_DeviceView->OnAction(Msg);
+            break;
+        }
+
+        case IDC_ACTIONMENU:
+        {
+            // Create a popup menu with all the actions for the selected node
+            HMENU hMenu = CreatePopupMenu();
+            m_DeviceView->CreateActionMenu(hMenu, true);
+
+            // Calculate where to put the menu
+            RECT rc;
+            GetMenuItemRect(m_hMainWnd, m_hMenu, 1, &rc);
+            LONG Height = rc.bottom - rc.top;
+
+            // Display the menu
+            TrackPopupMenuEx(hMenu,
+                             TPM_RIGHTBUTTON,
+                             rc.left,
+                             rc.top + Height,
+                             m_hMainWnd,
+                             NULL);
+
+            DestroyMenu(hMenu);
+            break;
+        }
+
+        case IDC_DEVBYTYPE:
+        {
+            RefreshView(DevicesByType);
+            break;
+        }
+
+        case IDC_DEVBYCONN:
+        {
+            RefreshView(DevicesByConnection);
+            break;
+        }
+
+        case IDC_SHOWHIDDEN:
+        {
+            // Get the current state
+            UINT CurCheckState = GetMenuState(m_hMenu, IDC_SHOWHIDDEN, MF_BYCOMMAND);
+            if (CurCheckState == MF_CHECKED)
+            {
+                m_DeviceView->SetHiddenDevices(false);
+                CheckMenuItem(m_hMenu, IDC_SHOWHIDDEN, MF_BYCOMMAND | MF_UNCHECKED);
+            }
+            else if (CurCheckState == MF_UNCHECKED)
+            {
+                m_DeviceView->SetHiddenDevices(true);
+                CheckMenuItem(m_hMenu, IDC_SHOWHIDDEN, MF_BYCOMMAND | MF_CHECKED);
+            }
+            // Refresh the device view
+            m_DeviceView->Refresh(m_DeviceView->GetCurrentView(),
+                                  false,
+                                  true,
+                                  NULL);
+            break;
+        }
+
+        case IDC_ABOUT:
+        {
+            // Apportion blame
+            MessageBoxW(m_hMainWnd,
+                        L"ReactOS Device Manager\r\nCopyright Ged Murphy 2015",
+                        L"About",
+                        MB_OK | MB_APPLMODAL);
+
+            // Set focus back to the treeview
+            m_DeviceView->SetFocus();
+            break;
+        }
+
+        case IDC_EXIT:
+        {
+            // Post a close message to the window
+            PostMessageW(m_hMainWnd,
+                         WM_CLOSE,
+                         0,
+                         0);
+            break;
+        }
+
+        default:
+            // We didn't handle it
+            RetCode = -1;
+            break;
+    }
+
+    return RetCode;
+}
+
+LRESULT
+CMainWindow::OnDestroy()
+{
+    // Uninitialize the device view
+    m_DeviceView->Uninitialize();
+
+    // Kill the object
+    delete m_DeviceView;
+    m_DeviceView = NULL;
+
+    // Clear the user data pointer
+    SetWindowLongPtr(m_hMainWnd, GWLP_USERDATA, 0);
+
+    // Break the message loop
+    PostQuitMessage(0);
+
+    return 0;
+}
+
+LRESULT CALLBACK
+CMainWindow::MainWndProc(HWND hwnd,
+                         UINT msg,
+                         WPARAM wParam,
+                         LPARAM lParam)
+{
+    CMainWindow *This;
+    LRESULT RetCode = 0;
+
+    // Get the object pointer from window context
+    This = (CMainWindow *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+    if (This == NULL)
+    {
+        // Check that this isn't a create message
+        if (msg != WM_CREATE)
+        {
+            // Don't handle null info pointer
+            goto HandleDefaultMessage;
+        }
+    }
+
+    switch(msg)
+    {
+        case WM_CREATE:
+        {
+            // Get the object pointer from the create param
+            This = (CMainWindow *)((LPCREATESTRUCT)lParam)->lpCreateParams;
+
+            // Store the pointer in the window's global user data
+            SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)This);
+
+            // Call the create handler
+            RetCode = This->OnCreate(hwnd);
+            break;
+        }
+
+        case WM_SIZE:
+        {
+            RetCode = This->OnSize();
+            break;
+        }
+
+        case WM_NOTIFY:
+        {
+            RetCode = This->OnNotify(lParam);
+            break;
+        }
+
+        case WM_CONTEXTMENU:
+        {
+            RetCode = This->OnContext(lParam);
+            break;
+        }
+
+        case WM_MENUSELECT:
+        {
+            if (This->m_hStatusBar != NULL)
+            {
+                if (!This->MainWndMenuHint(LOWORD(wParam),
+                                           MainMenuHintTable,
+                                           sizeof(MainMenuHintTable) / sizeof(MainMenuHintTable[0]),
+                                           IDS_HINT_BLANK))
+                {
+                    This->MainWndMenuHint(LOWORD(wParam),
+                                          SystemMenuHintTable,
+                                          sizeof(SystemMenuHintTable) / sizeof(SystemMenuHintTable[0]),
+                                          IDS_HINT_BLANK);
+                }
+            }
+
+            break;
+        }
+
+        case WM_COMMAND:
+        {
+            // Handle the command message
+            RetCode = This->OnCommand(wParam, lParam);
+            if (RetCode == -1)
+            {
+                // Hand it off to the default message handler
+                goto HandleDefaultMessage;
+            }
+            break;
+        }
+
+        case WM_ENTERMENULOOP:
+        {
+            This->UpdateStatusBar(true);
+            break;
+        }
+
+        case WM_EXITMENULOOP:
+        {
+            This->UpdateStatusBar(false);
+            break;
+        }
+
+        case WM_CLOSE:
+        {
+            // Destroy the main window
+            DestroyWindow(hwnd);
+            break;
+        }
+        
+
+        case WM_DESTROY:
+        {
+            // Call the destroy handler
+            RetCode = This->OnDestroy();
+            break;
+        }
+
+        default:
+        {
+HandleDefaultMessage:
+            RetCode = DefWindowProc(hwnd, msg, wParam, lParam);
+            break;
+        }
+    }
+
+    return RetCode;
+}
+
+
+//////// MOVE ME ////////////////
+
+HINSTANCE g_hInstance = NULL;
+HANDLE ProcessHeap = NULL;
+
+BOOL
+WINAPI
+DeviceManager_ExecuteW(HWND /*hWndParent*/,
+                       HINSTANCE hInst,
+                       LPCWSTR /*lpMachineName*/,
+                       int nCmdShow)
+{
+    CMainWindow MainWindow;
+    INITCOMMONCONTROLSEX icex;
+    CAtlStringW szAppName;
+    int Ret = 1;
+
+    // Store the global values
+    g_hInstance = hInst;
+    ProcessHeap = GetProcessHeap();
+
+    // Initialize common controls
+    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+    icex.dwICC = ICC_BAR_CLASSES | ICC_COOL_CLASSES;
+    InitCommonControlsEx(&icex);
+
+    // Load the application name
+    if (szAppName.LoadStringW(g_hInstance, IDS_APPNAME))
+    {
+        // Initialize the main window
+        if (MainWindow.Initialize(szAppName, nCmdShow))
+        {
+            // Run the application
+            Ret = MainWindow.Run();
+
+            // Uninitialize the main window
+            MainWindow.Uninitialize();
+        }
+    }
+
+    return Ret;
+}
diff --git a/reactos/dll/win32/devmgr_new/devmgmt/MainWindow.h b/reactos/dll/win32/devmgr_new/devmgmt/MainWindow.h
new file mode 100644 (file)
index 0000000..75027b9
--- /dev/null
@@ -0,0 +1,73 @@
+#pragma once
+#include "DeviceView.h"
+
+typedef struct _MENU_HINT
+{
+    WORD CmdId;
+    UINT HintId;
+} MENU_HINT, *PMENU_HINT;
+
+class CMainWindow
+{
+    CAtlStringW m_szMainWndClass;
+    CDeviceView *m_DeviceView;
+    HWND m_hMainWnd;
+    HWND m_hStatusBar;
+    HWND m_hToolBar;
+    HIMAGELIST m_ToolbarhImageList;
+    HMENU m_hMenu;
+    HMENU m_hActionMenu;
+    int m_CmdShow;
+
+public:
+    CMainWindow(void);
+    ~CMainWindow(void);
+
+    bool Initialize(LPCTSTR lpCaption, int nCmdShow);
+    int Run();
+    void Uninitialize();
+
+private:
+    static LRESULT CALLBACK MainWndProc(
+        HWND hwnd,
+        UINT msg,
+        WPARAM wParam,
+        LPARAM lParam
+        );
+
+    LRESULT OnCreate(HWND hwnd);
+    LRESULT OnDestroy();
+    LRESULT OnSize();
+    LRESULT OnNotify(LPARAM lParam);
+    LRESULT OnContext(LPARAM lParam);
+    LRESULT OnCommand(WPARAM wParam, LPARAM lParam);
+
+    bool CreateToolBar();
+    bool CreateStatusBar();
+
+    void UpdateToolbar(
+        );
+
+    bool StatusBarLoadString(
+        HWND hStatusBar,
+        INT PartId,
+        HINSTANCE hInstance,
+        UINT uID
+        );
+
+    void UpdateStatusBar(
+        _In_ bool InMenuLoop
+        );
+
+    bool MainWndMenuHint(
+        WORD CmdId,
+        const MENU_HINT *HintArray,
+        DWORD HintsCount,
+        UINT DefHintId
+        );
+
+    bool RefreshView(
+        ViewType Type
+        );
+};
+
diff --git a/reactos/dll/win32/devmgr_new/devmgmt/Node.cpp b/reactos/dll/win32/devmgr_new/devmgmt/Node.cpp
new file mode 100644 (file)
index 0000000..6e3b099
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+* PROJECT:     ReactOS Device Manager
+* LICENSE:     GPL - See COPYING in the top level directory
+* FILE:        dll/win32/devmgr/devmgr/node.cpp
+* PURPOSE:     Abstract base object for each node in the tree
+* COPYRIGHT:   Copyright 2015 Ged Murphy <gedmurphy@reactos.org>
+*
+*/
+
+#include "stdafx.h"
+#include "devmgmt.h"
+#include "Node.h"
+
+
+/* PUBLIC METHODS *******************************************/
+
+CNode::CNode(_In_ NodeType Type,
+             _In_ PSP_CLASSIMAGELIST_DATA ImageListData) :
+    m_NodeType(Type),
+    m_ImageListData(ImageListData),
+    m_DeviceId(NULL),
+    m_ClassImage(0)
+{
+    m_DisplayName[0] = UNICODE_NULL;
+    m_ClassGuid = GUID_NULL;
+}
+
+CNode::~CNode()
+{
+}
diff --git a/reactos/dll/win32/devmgr_new/devmgmt/Node.h b/reactos/dll/win32/devmgr_new/devmgmt/Node.h
new file mode 100644 (file)
index 0000000..b200ba6
--- /dev/null
@@ -0,0 +1,39 @@
+#pragma once
+
+#define DISPLAY_NAME_LEN    256
+
+enum NodeType
+{
+    RootNode,
+    ClassNode,
+    DeviceNode
+};
+
+class CNode
+{
+protected:
+    PSP_CLASSIMAGELIST_DATA m_ImageListData;
+    LPWSTR m_DeviceId;
+    WCHAR m_DisplayName[DISPLAY_NAME_LEN];
+    GUID  m_ClassGuid;
+    INT m_ClassImage;
+    NodeType m_NodeType;
+
+public:
+    CNode(
+        _In_ NodeType Type,
+        _In_ PSP_CLASSIMAGELIST_DATA ImageListData
+        );
+
+    ~CNode();
+
+    virtual bool SetupNode() = 0;
+
+    NodeType GetNodeType() { return m_NodeType; }
+    LPGUID GetClassGuid() { return &m_ClassGuid; }
+    LPWSTR GetDisplayName() { return m_DisplayName; }
+    INT GetClassImage() { return m_ClassImage; }
+    LPWSTR GetDeviceId() { return m_DeviceId; }
+    bool HasProperties() { return (m_DeviceId != NULL); }
+};
+
diff --git a/reactos/dll/win32/devmgr_new/devmgmt/Resource.h b/reactos/dll/win32/devmgr_new/devmgmt/Resource.h
new file mode 100644 (file)
index 0000000..f479ce6
--- /dev/null
@@ -0,0 +1,84 @@
+#define IDC_STATIC          -1
+
+#define IDS_APPNAME         10
+
+#define IDI_MAIN_ICON       20
+#define IDB_ROOT_IMAGE      21
+#define IDB_TOOLBAR         22
+
+/* windows */
+#define IDC_TREEVIEW        50
+#define IDC_TOOLBAR         51
+#define IDC_STATUSBAR       52
+#define IDR_MAINMENU        53
+#define IDR_POPUP           54
+
+/* Actions */
+#define IDC_PROPERTIES      100
+#define IDC_SCAN_HARDWARE   101
+#define IDC_ENABLE_DRV      102
+#define IDC_DISABLE_DRV     103
+#define IDC_UPDATE_DRV      104
+#define IDC_UNINSTALL_DRV   105
+#define IDC_ADD_HARDWARE    106
+
+/* Menu items */
+#define IDC_ACTIONMENU      150
+#define IDC_ABOUT           151
+#define IDC_EXIT            152
+
+
+/* view menu */
+#define IDC_DEVBYTYPE       200
+#define IDC_DEVBYCONN       201
+#define IDC_RESBYTYPE       202
+#define IDC_RESBYCONN       203
+#define IDC_SHOWHIDDEN      204
+
+
+/* tooltips */
+#define IDS_TOOLTIP_PROPERTIES  300
+#define IDS_TOOLTIP_SCAN        301
+#define IDS_TOOLTIP_ENABLE      302
+#define IDS_TOOLTIP_DISABLE     303
+#define IDS_TOOLTIP_UPDATE      304
+#define IDS_TOOLTIP_UNINSTALL   305
+
+/* General strings */
+#define IDS_CONFIRM_DISABLE     400
+
+/* Menu strings */
+#define IDS_MENU_UPDATE         500
+#define IDS_MENU_ENABLE         501
+#define IDS_MENU_DISABLE        502
+#define IDS_MENU_UNINSTALL      503
+#define IDS_MENU_SCAN           504
+#define IDS_MENU_ADD            505
+#define IDS_MENU_PROPERTIES     506
+
+
+/* menu hints */
+#define IDS_HINT_BLANK          1000
+#define IDS_HINT_PROPERTIES     1001
+#define IDS_HINT_SCAN           1002
+#define IDS_HINT_ENABLE         1003
+#define IDS_HINT_DISABLE        1004
+#define IDS_HINT_UPDATE         1005
+#define IDS_HINT_UNINSTALL      1006
+#define IDS_HINT_ADD            1007
+#define IDS_HINT_ABOUT          20008
+#define IDS_HINT_EXIT           20009
+
+#define IDS_HINT_DEV_BY_TYPE    20020
+#define IDS_HINT_DEV_BY_CONN    20021
+#define IDS_HINT_RES_BY_TYPE    20022
+#define IDS_HINT_RES_BY_CONN    20023
+#define IDS_HINT_SHOW_HIDDEN    20024
+
+/* system menu hints */
+#define IDS_HINT_SYS_RESTORE    21001
+#define IDS_HINT_SYS_MOVE       21002
+#define IDS_HINT_SYS_SIZE       21003
+#define IDS_HINT_SYS_MINIMIZE   21004
+#define IDS_HINT_SYS_MAXIMIZE   21005
+#define IDS_HINT_SYS_CLOSE      21006
diff --git a/reactos/dll/win32/devmgr_new/devmgmt/RootNode.cpp b/reactos/dll/win32/devmgr_new/devmgmt/RootNode.cpp
new file mode 100644 (file)
index 0000000..05be76d
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+* PROJECT:     ReactOS Device Manager
+* LICENSE:     GPL - See COPYING in the top level directory
+* FILE:        dll/win32/devmgr/devmgr/RootNode.cpp
+* PURPOSE:     Root object for
+* COPYRIGHT:   Copyright 2015 Ged Murphy <gedmurphy@reactos.org>
+*
+*/
+
+#include "stdafx.h"
+#include "devmgmt.h"
+#include "RootNode.h"
+
+
+CRootNode::CRootNode(_In_ PSP_CLASSIMAGELIST_DATA ImageListData) :
+    CNode(RootNode, ImageListData)
+{
+}
+
+
+CRootNode::~CRootNode()
+{
+}
+
+
+bool
+CRootNode::SetupNode()
+{
+
+    // Load the bitmap we'll be using as the root image
+    HBITMAP hRootImage;
+    hRootImage = LoadBitmapW(g_hInstance,
+                                MAKEINTRESOURCEW(IDB_ROOT_IMAGE));
+    if (hRootImage == NULL) return FALSE;
+
+    // Add this bitmap to the device image list. This is a bit hacky, but it's safe
+    m_ClassImage = ImageList_Add(m_ImageListData->ImageList,
+                                 hRootImage,
+                                 NULL);
+    DeleteObject(hRootImage);
+
+
+    // Get the root instance 
+    CONFIGRET cr;
+    cr = CM_Locate_DevNodeW(&m_DevInst,
+                            NULL,
+                            CM_LOCATE_DEVNODE_NORMAL);
+    if (cr != CR_SUCCESS)
+    {
+        return false;
+    }
+
+    // The root name is the computer name 
+    DWORD Size = DISPLAY_NAME_LEN;
+    if (GetComputerNameW(m_DisplayName, &Size))
+        _wcslwr(m_DisplayName);
+
+    return true;
+
+
+}
\ No newline at end of file
diff --git a/reactos/dll/win32/devmgr_new/devmgmt/RootNode.h b/reactos/dll/win32/devmgr_new/devmgmt/RootNode.h
new file mode 100644 (file)
index 0000000..4c58fc5
--- /dev/null
@@ -0,0 +1,17 @@
+#pragma once
+#include "Node.h"
+
+class CRootNode : public CNode
+{
+private:
+    DEVINST m_DevInst;
+
+public:
+    CRootNode(_In_ PSP_CLASSIMAGELIST_DATA ImageListData);
+    ~CRootNode();
+
+    virtual bool SetupNode();
+
+    DEVINST GetDeviceInst() { return m_DevInst; }
+};
+
diff --git a/reactos/dll/win32/devmgr_new/devmgmt/devmgmt.h b/reactos/dll/win32/devmgr_new/devmgmt/devmgmt.h
new file mode 100644 (file)
index 0000000..f8abae2
--- /dev/null
@@ -0,0 +1,9 @@
+#pragma once
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#pragma once
+#include "resource.h"
+
+extern HINSTANCE g_hInstance;
+extern HANDLE ProcessHeap;
+
diff --git a/reactos/dll/win32/devmgr_new/devmgmt/lang/en-US.rc b/reactos/dll/win32/devmgr_new/devmgmt/lang/en-US.rc
new file mode 100644 (file)
index 0000000..4a8f138
--- /dev/null
@@ -0,0 +1,78 @@
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+IDR_MAINMENU MENU
+BEGIN
+  POPUP "&File"
+  BEGIN
+    MENUITEM "E&xit",                       IDC_EXIT
+  END
+  MENUITEM "Action"                         IDC_ACTIONMENU
+  POPUP "View"
+  BEGIN
+    MENUITEM "Devices by type",             IDC_DEVBYTYPE
+    MENUITEM "Devices by connection",       IDC_DEVBYCONN
+    MENUITEM "Resources by type",           IDC_RESBYTYPE, GRAYED
+    MENUITEM "Resources by connection",     IDC_RESBYCONN, GRAYED
+    MENUITEM SEPARATOR
+    MENUITEM "Show hidden devices",         IDC_SHOWHIDDEN
+  END
+  POPUP "Help"
+  BEGIN
+    MENUITEM "About",                       IDC_ABOUT
+  END
+END
+
+
+STRINGTABLE DISCARDABLE
+BEGIN
+  IDS_CONFIRM_DISABLE       "Disabling this device will cause it to stop functioning.\r\nDo you really want to disable it?"
+END
+STRINGTABLE DISCARDABLE
+BEGIN
+  IDS_MENU_UPDATE           "Update driver software..."
+  IDS_MENU_ENABLE           "Enable"
+  IDS_MENU_DISABLE          "Disable"
+  IDS_MENU_UNINSTALL        "Uninstall"
+  IDS_MENU_SCAN             "Scan for hardware changes"
+  IDS_MENU_ADD              "Add hardware"
+  IDS_MENU_PROPERTIES       "Properties"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+  IDS_TOOLTIP_PROPERTIES    "Properties"
+  IDS_TOOLTIP_SCAN          "Scan for hardware changes"
+  IDS_TOOLTIP_ENABLE        "Enable"
+  IDS_TOOLTIP_DISABLE       "Disable"
+  IDS_TOOLTIP_UPDATE        "Update Driver Software"
+  IDS_TOOLTIP_UNINSTALL     "Uninstall"
+END
+
+/* Hints */
+STRINGTABLE DISCARDABLE
+BEGIN
+  IDS_APPNAME           "ReactOS Device Manager"
+  IDS_HINT_BLANK        " "
+  IDS_HINT_PROPERTIES   " Open property dialog for the current selection."
+  IDS_HINT_SCAN         " Scan for changed or new plug and play devices."
+  IDS_HINT_ENABLE       " Enables the selected device."
+  IDS_HINT_DISABLE      " Disables the selected device."
+  IDS_HINT_UPDATE       " Launches the Update Driver Software wizard for the selected device."
+  IDS_HINT_UNINSTALL    " Uninstalls the driver for the selected device."
+  IDS_HINT_ADD          " Adds a legacy (non-Plug and Play) device to the computer." 
+  IDS_HINT_ABOUT        " About ReactOS Device Manager."
+  IDS_HINT_EXIT         " Exits the program."
+
+  IDS_HINT_DEV_BY_TYPE  " Displays devices by hardware type."
+  IDS_HINT_DEV_BY_CONN  " Displays devices by connection."
+  IDS_HINT_RES_BY_TYPE  " Displays resources by type."
+  IDS_HINT_RES_BY_CONN  " Displays resources by connection type."
+  IDS_HINT_SHOW_HIDDEN  " Displays legacy devices and devices that are no longer installed."
+
+  IDS_HINT_SYS_RESTORE  " Restores this window to normal size."
+  IDS_HINT_SYS_MOVE     " Moves this window."
+  IDS_HINT_SYS_SIZE     " Resizes this window."
+  IDS_HINT_SYS_MINIMIZE " Collapses this window to an icon."
+  IDS_HINT_SYS_MAXIMIZE " Expands this window to fill this screen."
+  IDS_HINT_SYS_CLOSE    " Closes this window."
+END
diff --git a/reactos/dll/win32/devmgr_new/devmgmt/lang/tr-TR.rc b/reactos/dll/win32/devmgr_new/devmgmt/lang/tr-TR.rc
new file mode 100644 (file)
index 0000000..3fd8f36
--- /dev/null
@@ -0,0 +1,98 @@
+/* TRANSLATOR: 2015 Erdem Ersoy (eersoy93) (erdemersoy@live.com) */
+
+LANGUAGE LANG_TURKISH, SUBLANG_DEFAULT
+
+IDR_MAINMENU MENU
+BEGIN
+  POPUP "&Kütük"
+  BEGIN
+    MENUITEM "&Çıkış",                       IDC_EXIT
+  END
+  POPUP "&Eylem"
+  BEGIN
+    MENUITEM "&Sürücü Yazılmını Şimdikileştir..." IDC_UPDATE_DRV
+    MENUITEM "&Etkinleştir"                  IDC_ENABLE_DRV
+    MENUITEM "E&dilginleştir"                IDC_DISABLE_DRV
+    MENUITEM "&Kaldır"                       IDC_UNINSTALL_DRV
+    MENUITEM SEPARATOR
+    MENUITEM "D&onanım Değişiklikleri İçin Tara" IDC_SCAN_HARDWARE
+    MENUITEM "Do&nanım Ekle"                 IDC_ADD_HARDWARE, GRAYED
+    MENUITEM SEPARATOR
+    MENUITEM "&Husûsiyetler",                IDC_PROPERTIES
+  END
+  POPUP "&Görünüm"
+  BEGIN
+    MENUITEM "&Türe Göre Aygıtlar",          IDC_DEVBYTYPE
+    MENUITEM "&Bağlantıya Göre Aygıtlar",    IDC_DEVBYCONN
+    MENUITEM "T&üre Göre Kaynaklar",         IDC_RESBYTYPE, GRAYED
+    MENUITEM "B&ağlantıya Göre Kaynaklar",   IDC_RESBYCONN, GRAYED
+    MENUITEM SEPARATOR
+    MENUITEM "&Gizli Aygıtları Göster",      IDC_SHOWHIDDEN
+  END
+  POPUP "&Yardım"
+  BEGIN
+    MENUITEM "&Üzerine",                     IDC_ABOUT
+  END
+END
+
+IDR_POPUP MENU
+BEGIN
+  POPUP "popup"
+  BEGIN
+    MENUITEM "&Sürücü Yazılmını Şimdikileştir..." IDC_UPDATE_DRV
+    MENUITEM "&Etkinleştir"                  IDC_ENABLE_DRV
+    MENUITEM "E&dilginleştir"                IDC_DISABLE_DRV
+    MENUITEM "&Kaldır"                       IDC_UNINSTALL_DRV
+    MENUITEM SEPARATOR
+    MENUITEM "D&onanım Değişiklikleri İçin Tara" IDC_SCAN_HARDWARE
+    MENUITEM "Do&nanım Ekle"                 IDC_ADD_HARDWARE, GRAYED
+    MENUITEM SEPARATOR
+    MENUITEM "&Husûsiyetler",                IDC_PROPERTIES
+  END
+END
+
+#define IDS_HINT_PROPERTIES     20001
+#define IDS_HINT_SCAN           20002
+#define IDS_HINT_ENABLE         20003
+#define IDS_HINT_DISABLE        20004
+#define IDS_HINT_UPDATE         20005
+#define IDS_HINT_UNINSTALL      20006
+
+STRINGTABLE DISCARDABLE
+BEGIN
+  IDS_TOOLTIP_PROPERTIES    "Husûsiyetler"
+  IDS_TOOLTIP_SCAN          "Donanım Değişiklikleri İçin Tara"
+  IDS_TOOLTIP_ENABLE        "Etkinleştir"
+  IDS_TOOLTIP_DISABLE       "Edilginleştir"
+  IDS_TOOLTIP_UPDATE        "Sürücü Yazılmını Şimdikileştir"
+  IDS_TOOLTIP_UNINSTALL     "Kaldır"
+END
+
+/* Hints */
+STRINGTABLE DISCARDABLE
+BEGIN
+  IDS_APPNAME           "Aygıt Yöneticisi"
+  IDS_HINT_BLANK        " "
+  IDS_HINT_PROPERTIES   " Şimdiki seçilen için husûsiyet penceresini açar."
+  IDS_HINT_SCAN         " Yeni ya da değiştirilmiş tak ve çalıştır aygıtları için tarar."
+  IDS_HINT_ENABLE       " Seçili aygıtı etkinleştirir."
+  IDS_HINT_DISABLE      " Seçili aygıtı edilginleştirir."
+  IDS_HINT_UPDATE       " Seçili aygıt için Sürücü Yazılımını Şimdikileştir yardımcısını başlatır."
+  IDS_HINT_UNINSTALL    " Seçili aygıt için sürücüyü kaldırır."
+  IDS_HINT_ADD          " Bilgisayara eski (Tak ve Çalıştır olmayan) bir aygıt ekler." 
+  IDS_HINT_ABOUT        " Aygıt Yöneticisi üzerine."
+  IDS_HINT_EXIT         " İzlenceden çıkar."
+
+  IDS_HINT_DEV_BY_TYPE  " Donanım türüne göre aygıtları görüntüler."
+  IDS_HINT_DEV_BY_CONN  " Bağlantıya göre aygıtları görüntüler."
+  IDS_HINT_RES_BY_TYPE  " Türe göre kaynakları görüntüler."
+  IDS_HINT_RES_BY_CONN  " Bağlantı türüne göre kaynakları görüntüler."
+  IDS_HINT_SHOW_HIDDEN  " Eski aygıtları ve artık kurulu olmayacak aygıtları görüntüler."
+
+  IDS_HINT_SYS_RESTORE  " Bu pencereyi düzgülük boyutlarına döndürür."
+  IDS_HINT_SYS_MOVE     " Bu pencereyi devindirir."
+  IDS_HINT_SYS_SIZE     " Bu pencereyi yeniden boyutlandırır."
+  IDS_HINT_SYS_MINIMIZE " Bu pencereyi bir simgeye küçültür."
+  IDS_HINT_SYS_MAXIMIZE " Bu pencereyi, bu görüntülüğü kaplatana dek genişletir."
+  IDS_HINT_SYS_CLOSE    " Bu pencereyi kapatır."
+END
diff --git a/reactos/dll/win32/devmgr_new/devmgmt/res/computer.ico b/reactos/dll/win32/devmgr_new/devmgmt/res/computer.ico
new file mode 100644 (file)
index 0000000..56edfcb
Binary files /dev/null and b/reactos/dll/win32/devmgr_new/devmgmt/res/computer.ico differ
diff --git a/reactos/dll/win32/devmgr_new/devmgmt/res/root.bmp b/reactos/dll/win32/devmgr_new/devmgmt/res/root.bmp
new file mode 100644 (file)
index 0000000..e2734fb
Binary files /dev/null and b/reactos/dll/win32/devmgr_new/devmgmt/res/root.bmp differ
diff --git a/reactos/dll/win32/devmgr_new/devmgmt/res/toolbar.bmp b/reactos/dll/win32/devmgr_new/devmgmt/res/toolbar.bmp
new file mode 100644 (file)
index 0000000..c7dd5ac
Binary files /dev/null and b/reactos/dll/win32/devmgr_new/devmgmt/res/toolbar.bmp differ
diff --git a/reactos/dll/win32/devmgr_new/devmgmt/rsrc.rc b/reactos/dll/win32/devmgr_new/devmgmt/rsrc.rc
new file mode 100644 (file)
index 0000000..2d50111
--- /dev/null
@@ -0,0 +1,80 @@
+#include <windows.h>
+#include "resource.h"
+
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+
+IDI_MAIN_ICON   ICON    "res/computer.ico"
+IDB_ROOT_IMAGE  BITMAP  "res/root.bmp"
+
+/* main toolbar icons */
+IDB_TOOLBAR    BITMAP DISCARDABLE "res/toolbar.bmp"
+
+// UTF-8
+#pragma code_page(65001)
+
+#ifdef LANGUAGE_BG_BG
+    #include "lang/bg-BG.rc"
+#endif
+#ifdef LANGUAGE_DE_DE
+    #include "lang/de-DE.rc"
+#endif
+#ifdef LANGUAGE_EL_GR
+    #include "lang/el-GR.rc"
+#endif
+#ifdef LANGUAGE_EN_US
+    #include "lang/en-US.rc"
+#endif
+#ifdef LANGUAGE_ES_ES
+    #include "lang/es-ES.rc"
+#endif
+#ifdef LANGUAGE_FR_FR
+    #include "lang/fr-FR.rc"
+#endif
+#ifdef LANGUAGE_HE_IL
+    #include "lang/he-IL.rc"
+#endif
+#ifdef LANGUAGE_ID_ID
+    #include "lang/id-ID.rc"
+#endif
+#ifdef LANGUAGE_IT_IT
+    #include "lang/it-IT.rc"
+#endif
+#ifdef LANGUAGE_JA_JP
+    #include "lang/ja-JP.rc"
+#endif
+#ifdef LANGUAGE_KO_KR
+    #include "lang/ko-KR.rc"
+#endif
+#ifdef LANGUAGE_NB_NO
+    #include "lang/no-NO.rc"
+#endif
+#ifdef LANGUAGE_PL_PL
+    #include "lang/pl-PL.rc"
+#endif
+#ifdef LANGUAGE_PT_BR
+    #include "lang/pt-BR.rc"
+#endif
+#ifdef LANGUAGE_RO_RO
+    #include "lang/ro-RO.rc"
+#endif
+#ifdef LANGUAGE_RU_RU
+    #include "lang/ru-RU.rc"
+#endif
+#ifdef LANGUAGE_SK_SK
+    #include "lang/sk-SK.rc"
+#endif
+#ifdef LANGUAGE_SV_SE
+    #include "lang/sv-SE.rc"
+#endif
+#ifdef LANGUAGE_TH_TH
+    #include "lang/th-TH.rc"
+#endif
+#ifdef LANGUAGE_TR_TR
+    #include "lang/tr-TR.rc"
+#endif
+#ifdef LANGUAGE_UK_UA
+    #include "lang/uk-UA.rc"
+#endif
+#ifdef LANGUAGE_ZH_CN
+    #include "lang/zh-CN.rc"
+#endif
diff --git a/reactos/dll/win32/devmgr_new/devmgmt/stdafx.h b/reactos/dll/win32/devmgr_new/devmgmt/stdafx.h
new file mode 100644 (file)
index 0000000..8802296
--- /dev/null
@@ -0,0 +1,53 @@
+#pragma once
+
+#ifndef __REACTOS__
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <windowsx.h>
+#include <setupapi.h>
+#include <cfgmgr32.h>
+#include <commctrl.h>
+#include <Uxtheme.h>
+#include <Cfgmgr32.h>
+#include <devguid.h>
+#include <process.h>
+
+
+#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS      // some CString constructors will be explicit
+#include <tchar.h>
+#include <atlbase.h>
+#include <atlstr.h>
+#include <atlcoll.h>
+
+#include <strsafe.h>
+#else
+
+#include <string.h>
+#include <wchar.h>
+
+#include <tchar.h>
+#include <windef.h>
+#include <winbase.h>
+#include <winreg.h>
+#include <wingdi.h>
+#include <winnls.h>
+#include <wincon.h>
+#include <shlobj.h>
+#include <shlwapi.h>
+#include <strsafe.h>
+#include <process.h>
+#include <WindowsX.h>
+#include <strsafe.h>
+
+#include <setupapi.h>
+#include <commctrl.h>
+#include <cfgmgr32.h>
+#include <Uxtheme.h>
+#include <devguid.h>
+
+#include <atlbase.h>
+#include <atlstr.h>
+#include <atlcoll.h>
+
+#endif
\ No newline at end of file
diff --git a/reactos/dll/win32/devmgr_new/devmgr.rc b/reactos/dll/win32/devmgr_new/devmgr.rc
new file mode 100644 (file)
index 0000000..e4b18a8
--- /dev/null
@@ -0,0 +1,81 @@
+#include <windef.h>
+#include <winuser.h>
+#include <commctrl.h>
+
+#include "resource.h"
+
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION  "ReactOS Device Manager"
+#define REACTOS_STR_INTERNAL_NAME     "devmgr"
+#define REACTOS_STR_ORIGINAL_FILENAME "devmgr.dll"
+#include <reactos/version.rc>
+
+IDI_DEVMGR ICON "resources/devmgr.ico"
+
+#include <reactos/manifest_dll.rc>
+
+/* UTF-8 */
+#pragma code_page(65001)
+
+#ifdef LANGUAGE_BG_BG
+    #include "lang/bg-BG.rc"
+#endif
+#ifdef LANGUAGE_CS_CZ
+    #include "lang/cs-CZ.rc"
+#endif
+#ifdef LANGUAGE_DE_DE
+    #include "lang/de-DE.rc"
+#endif
+#ifdef LANGUAGE_EL_GR
+    #include "lang/el-GR.rc"
+#endif
+#ifdef LANGUAGE_EN_US
+    #include "lang/en-US.rc"
+#endif
+#ifdef LANGUAGE_ES_ES
+    #include "lang/es-ES.rc"
+#endif
+#ifdef LANGUAGE_HE_IL
+    #include "lang/he-IL.rc"
+#endif
+#ifdef LANGUAGE_FR_FR
+    #include "lang/fr-FR.rc"
+#endif
+#ifdef LANGUAGE_HU_HU
+    #include "lang/hu-HU.rc"
+#endif
+#ifdef LANGUAGE_ID_ID
+    #include "lang/id-ID.rc"
+#endif
+#ifdef LANGUAGE_IT_IT
+    #include "lang/it-IT.rc"
+#endif
+#ifdef LANGUAGE_NB_NO
+    #include "lang/no-NO.rc"
+#endif
+#ifdef LANGUAGE_PL_PL
+    #include "lang/pl-PL.rc"
+#endif
+#ifdef LANGUAGE_PT_BR
+    #include "lang/pt-BR.rc"
+#endif
+#ifdef LANGUAGE_RO_RO
+    #include "lang/ro-RO.rc"
+#endif
+#ifdef LANGUAGE_RU_RU
+    #include "lang/ru-RU.rc"
+#endif
+#ifdef LANGUAGE_SK_SK
+    #include "lang/sk-SK.rc"
+#endif
+#ifdef LANGUAGE_SQ_AL
+    #include "lang/sq-AL.rc"
+#endif
+#ifdef LANGUAGE_TR_TR
+    #include "lang/tr-TR.rc"
+#endif
+#ifdef LANGUAGE_UK_UA
+    #include "lang/uk-UA.rc"
+#endif
diff --git a/reactos/dll/win32/devmgr_new/devmgr.spec b/reactos/dll/win32/devmgr_new/devmgr.spec
new file mode 100644 (file)
index 0000000..0ef1127
--- /dev/null
@@ -0,0 +1,27 @@
+# devmgr.dll exports
+
+ 5 stdcall DeviceProperties_RunDLLA(ptr ptr str long)
+ 6 stdcall DeviceProperties_RunDLLW(ptr ptr wstr long)
+ 7 stdcall DevicePropertiesA(ptr str str long)
+ 8 stdcall DevicePropertiesW(ptr wstr wstr long)
+ 9 stdcall DeviceManager_ExecuteA(ptr ptr str long)
+10 stdcall DeviceManager_ExecuteW(ptr ptr wstr long)
+11 stdcall DeviceProblemTextA(ptr long long str long)
+12 stdcall DeviceProblemTextW(ptr long long wstr long)
+13 stdcall DeviceProblemWizardA(ptr str str)
+14 stdcall DeviceProblemWizardW(ptr wstr wstr)
+15 stdcall DeviceManagerPrintA(str str long long ptr)
+16 stdcall DeviceManagerPrintW(wstr wstr long long ptr)
+17 stdcall DeviceAdvancedPropertiesA(ptr str str)
+18 stdcall DeviceAdvancedPropertiesW(ptr wstr wstr)
+19 stdcall DeviceCreateHardwarePage(ptr ptr)
+20 stdcall DeviceCreateHardwarePageEx(ptr ptr long long)
+21 stdcall DevicePropertiesExA(ptr str str long long)
+22 stdcall DevicePropertiesExW(ptr wstr wstr long long)
+23 stdcall DeviceProblenWizard_RunDLLA(ptr ptr str long) DeviceProblemWizard_RunDLLA
+24 stdcall DeviceProblenWizard_RunDLLW(ptr ptr wstr long) DeviceProblemWizard_RunDLLW
+
+@ stub -private DllCanUnloadNow
+@ stub -private DllGetClassObject
+@ stub -private DllRegisterServer
+@ stub -private DllUnregisterServer
diff --git a/reactos/dll/win32/devmgr_new/devprblm.c b/reactos/dll/win32/devmgr_new/devprblm.c
new file mode 100644 (file)
index 0000000..9d684db
--- /dev/null
@@ -0,0 +1,614 @@
+/*
+ * ReactOS Device Manager Applet
+ * Copyright (C) 2004 - 2005 ReactOS Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+/*
+ * PROJECT:         ReactOS devmgr.dll
+ * FILE:            lib/devmgr/devprblm.c
+ * PURPOSE:         ReactOS Device Manager
+ * PROGRAMMER:      Thomas Weidenmueller <w3seek@reactos.com>
+ * UPDATE HISTORY:
+ *      04-04-2004  Created
+ */
+
+#include "precomp.h"
+
+
+BOOL
+ShowDeviceProblemWizard(IN HWND hWndParent  OPTIONAL,
+                        IN HDEVINFO hDevInfo,
+                        IN PSP_DEVINFO_DATA DevInfoData,
+                        IN HMACHINE hMachine  OPTIONAL)
+{
+    WCHAR szDeviceInstanceId[256];
+    CONFIGRET cr;
+    ULONG Status, ProblemNumber;
+    DWORD dwReboot;
+    BOOL Ret = FALSE;
+
+    /* Get the device instance id */
+    if (!SetupDiGetDeviceInstanceId(hDevInfo,
+                                    DevInfoData,
+                                    szDeviceInstanceId,
+                                    256,
+                                    NULL))
+        return FALSE;
+
+    cr = CM_Get_DevNode_Status_Ex(&Status,
+                                  &ProblemNumber,
+                                  DevInfoData->DevInst,
+                                  0,
+                                  hMachine);
+    if (cr == CR_SUCCESS && (Status & DN_HAS_PROBLEM))
+    {
+        switch (ProblemNumber)
+        {
+            case CM_PROB_DEVLOADER_FAILED:
+            {
+                /* FIXME - only if it's not a root bus devloader */
+                /* FIXME - display the update driver wizard */
+                break;
+            }
+
+            case CM_PROB_OUT_OF_MEMORY:
+            case CM_PROB_ENTRY_IS_WRONG_TYPE:
+            case CM_PROB_LACKED_ARBITRATOR:
+            case CM_PROB_FAILED_START:
+            case CM_PROB_LIAR:
+            case CM_PROB_UNKNOWN_RESOURCE:
+            {
+                /* FIXME - display the update driver wizard */
+                InstallDevInst(hWndParent, szDeviceInstanceId, TRUE, &dwReboot);
+                break;
+            }
+
+            case CM_PROB_BOOT_CONFIG_CONFLICT:
+            case CM_PROB_NORMAL_CONFLICT:
+            case CM_PROB_REENUMERATION:
+            {
+                /* FIXME - display the conflict wizard */
+                break;
+            }
+
+            case CM_PROB_FAILED_FILTER:
+            case CM_PROB_REINSTALL:
+            case CM_PROB_FAILED_INSTALL:
+            {
+                /* FIXME - display the driver (re)installation wizard */
+                InstallDevInst(hWndParent, szDeviceInstanceId, TRUE, &dwReboot);
+                break;
+            }
+
+            case CM_PROB_DEVLOADER_NOT_FOUND:
+            {
+                /* FIXME - 4 cases:
+                   1) if it's a missing system devloader:
+                      - fail
+                   2) if it's not a system devloader but still missing:
+                      - display the driver reinstallation wizard
+                   3) if it's not a system devloader but the file can be found:
+                      - display the update driver wizard
+                   4) if it's a missing or empty software key
+                      - display the update driver wizard
+                 */
+                break;
+            }
+
+            case CM_PROB_INVALID_DATA:
+            case CM_PROB_PARTIAL_LOG_CONF:
+            case CM_PROB_NO_VALID_LOG_CONF:
+            case CM_PROB_HARDWARE_DISABLED:
+            case CM_PROB_CANT_SHARE_IRQ:
+            case CM_PROB_TRANSLATION_FAILED:
+            case CM_PROB_SYSTEM_SHUTDOWN:
+            case CM_PROB_PHANTOM:
+                /* FIXME - do nothing */
+                break;
+
+            case CM_PROB_NOT_VERIFIED:
+            case CM_PROB_DEVICE_NOT_THERE:
+                /* FIXME - display search hardware wizard */
+                break;
+
+            case CM_PROB_NEED_RESTART:
+            case CM_PROB_WILL_BE_REMOVED:
+            case CM_PROB_MOVED:
+            case CM_PROB_TOO_EARLY:
+            case CM_PROB_DISABLED_SERVICE:
+                /* FIXME - reboot computer */
+                break;
+
+            case CM_PROB_REGISTRY:
+                /* FIXME - check registry */
+                break;
+
+            case CM_PROB_DISABLED:
+            {
+                /* FIXME - if device was disabled by user display the "Enable Device" wizard,
+                           otherwise Troubleshoot because the device was disabled by the system */
+                break;
+            }
+
+            case CM_PROB_DEVLOADER_NOT_READY:
+            {
+                /* FIXME - if it's a graphics adapter:
+                           - if it's a a secondary adapter and the main adapter
+                             couldn't be found
+                             - do nothing or default action
+                           - else
+                             - display the Properties
+                         - else
+                           - Update driver
+                 */
+                break;
+            }
+
+            case CM_PROB_FAILED_ADD:
+            {
+                /* FIXME - display the properties of the sub-device */
+                break;
+            }
+
+            case CM_PROB_NO_SOFTCONFIG:
+            case CM_PROB_IRQ_TRANSLATION_FAILED:
+            case CM_PROB_FAILED_DRIVER_ENTRY:
+            case CM_PROB_DRIVER_FAILED_PRIOR_UNLOAD:
+            case CM_PROB_DRIVER_FAILED_LOAD:
+            case CM_PROB_DRIVER_SERVICE_KEY_INVALID:
+            case CM_PROB_LEGACY_SERVICE_NO_DEVICES:
+            case CM_PROB_DUPLICATE_DEVICE:
+            case CM_PROB_FAILED_POST_START:
+            case CM_PROB_HALTED:
+            case CM_PROB_HELD_FOR_EJECT:
+            case CM_PROB_DRIVER_BLOCKED:
+            case CM_PROB_REGISTRY_TOO_LARGE:
+            default:
+            {
+                /* FIXME - troubleshoot the device */
+                break;
+            }
+        }
+    }
+
+    return Ret;
+}
+
+
+/***************************************************************************
+ * NAME                                                         EXPORTED
+ *      DeviceProblemWizardA
+ *
+ * DESCRIPTION
+ *   Calls the device problem wizard
+ *
+ * ARGUMENTS
+ *   hWndParent:    Handle to the parent window
+ *   lpMachineName: Machine Name, NULL is the local machine
+ *   lpDeviceID:    Specifies the device, also see NOTEs
+ *
+ * RETURN VALUE
+ *   TRUE:  if no errors occured
+ *   FALSE: if errors occured
+ *
+ * @implemented
+ */
+BOOL
+WINAPI
+DeviceProblemWizardA(IN HWND hWndParent  OPTIONAL,
+                     IN LPCSTR lpMachineName  OPTIONAL,
+                     IN LPCSTR lpDeviceID)
+{
+    LPWSTR lpMachineNameW = NULL;
+    LPWSTR lpDeviceIDW = NULL;
+    BOOL Ret = FALSE;
+
+    if (lpMachineName != NULL)
+    {
+        if (!(lpMachineNameW = ConvertMultiByteToUnicode(lpMachineName,
+                                                         CP_ACP)))
+        {
+            goto Cleanup;
+        }
+    }
+    if (lpDeviceID != NULL)
+    {
+        if (!(lpDeviceIDW = ConvertMultiByteToUnicode(lpDeviceID,
+                                                      CP_ACP)))
+        {
+            goto Cleanup;
+        }
+    }
+
+    Ret = DeviceProblemWizardW(hWndParent,
+                               lpMachineNameW,
+                               lpDeviceIDW);
+
+Cleanup:
+    if (lpMachineNameW != NULL)
+    {
+        HeapFree(GetProcessHeap(),
+                 0,
+                 lpMachineNameW);
+    }
+    if (lpDeviceIDW != NULL)
+    {
+        HeapFree(GetProcessHeap(),
+                 0,
+                 lpDeviceIDW);
+    }
+
+    return Ret;
+}
+
+
+/***************************************************************************
+ * NAME                                                         EXPORTED
+ *      DeviceProblemWizardW
+ *
+ * DESCRIPTION
+ *   Calls the device problem wizard
+ *
+ * ARGUMENTS
+ *   hWndParent:    Handle to the parent window
+ *   lpMachineName: Machine Name, NULL is the local machine
+ *   lpDeviceID:    Specifies the device, also see NOTEs
+ *
+ * RETURN VALUE
+ *   TRUE:  if no errors occured
+ *   FALSE: if errors occured
+ *
+ * @unimplemented
+ */
+BOOL
+WINAPI
+DeviceProblemWizardW(IN HWND hWndParent  OPTIONAL,
+                     IN LPCWSTR lpMachineName  OPTIONAL,
+                     IN LPCWSTR lpDeviceID)
+{
+    HDEVINFO hDevInfo;
+    SP_DEVINFO_DATA DevInfoData;
+    HINSTANCE hComCtl32;
+    CONFIGRET cr;
+    HMACHINE hMachine;
+    BOOL Ret = FALSE;
+
+    if (lpDeviceID == NULL)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    /* dynamically load comctl32 */
+    hComCtl32 = LoadAndInitComctl32();
+    if (hComCtl32 != NULL)
+    {
+        hDevInfo = SetupDiCreateDeviceInfoListEx(NULL,
+                                                 hWndParent,
+                                                 lpMachineName,
+                                                 NULL);
+        if (hDevInfo != INVALID_HANDLE_VALUE)
+        {
+            cr = CM_Connect_Machine(lpMachineName,
+                                    &hMachine);
+            if (cr == CR_SUCCESS)
+            {
+                DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
+                if (SetupDiOpenDeviceInfo(hDevInfo,
+                                          lpDeviceID,
+                                          hWndParent,
+                                          0,
+                                          &DevInfoData))
+                {
+                    Ret = ShowDeviceProblemWizard(hWndParent,
+                                                  hDevInfo,
+                                                  &DevInfoData,
+                                                  hMachine);
+                }
+
+                CM_Disconnect_Machine(hMachine);
+            }
+
+            SetupDiDestroyDeviceInfoList(hDevInfo);
+        }
+
+        FreeLibrary(hComCtl32);
+    }
+
+    return Ret;
+}
+
+
+static const UINT ProblemStringId[NUM_CM_PROB] =
+{
+    IDS_DEV_NO_PROBLEM,
+    IDS_DEV_DEVLOADER_FAILED,
+    IDS_DEV_NOT_CONFIGURED,
+    IDS_DEV_OUT_OF_MEMORY,
+    IDS_DEV_ENTRY_IS_WRONG_TYPE,
+    IDS_DEV_LACKED_ARBITRATOR,
+    IDS_DEV_BOOT_CONFIG_CONFLICT,
+    IDS_DEV_FAILED_FILTER,
+    IDS_DEV_DEVLOADER_NOT_FOUND,
+    IDS_DEV_INVALID_DATA,
+    IDS_DEV_FAILED_START,
+    IDS_DEV_LIAR,
+    IDS_DEV_NORMAL_CONFLICT,
+    IDS_DEV_NOT_VERIFIED,
+    IDS_DEV_NEED_RESTART,
+    IDS_DEV_REENUMERATION,
+    IDS_DEV_PARTIAL_LOG_CONF,
+    IDS_DEV_UNKNOWN_RESOURCE,
+    IDS_DEV_REINSTALL,
+    IDS_DEV_REGISTRY,
+    IDS_UNKNOWN, /* CM_PROB_VXDLDR, not used on NT */
+    IDS_DEV_WILL_BE_REMOVED,
+    IDS_DEV_DISABLED,
+    IDS_DEV_DEVLOADER_NOT_READY,
+    IDS_DEV_DEVICE_NOT_THERE,
+    IDS_DEV_MOVED,
+    IDS_DEV_TOO_EARLY,
+    IDS_DEV_NO_VALID_LOG_CONF,
+    IDS_DEV_FAILED_INSTALL,
+    IDS_DEV_HARDWARE_DISABLED,
+    IDS_DEV_CANT_SHARE_IRQ,
+    IDS_DEV_FAILED_ADD,
+    IDS_DEV_DISABLED_SERVICE,
+    IDS_DEV_TRANSLATION_FAILED,
+    IDS_DEV_NO_SOFTCONFIG,
+    IDS_DEV_BIOS_TABLE,
+    IDS_DEV_IRQ_TRANSLATION_FAILED,
+    IDS_DEV_FAILED_DRIVER_ENTRY,
+    IDS_DEV_DRIVER_FAILED_PRIOR_UNLOAD,
+    IDS_DEV_DRIVER_FAILED_LOAD,
+    IDS_DEV_DRIVER_SERVICE_KEY_INVALID,
+    IDS_DEV_LEGACY_SERVICE_NO_DEVICES,
+    IDS_DEV_DUPLICATE_DEVICE,
+    IDS_DEV_FAILED_POST_START,
+    IDS_DEV_HALTED,
+    IDS_DEV_PHANTOM,
+    IDS_DEV_SYSTEM_SHUTDOWN,
+    IDS_DEV_HELD_FOR_EJECT,
+    IDS_DEV_DRIVER_BLOCKED,
+    IDS_DEV_REGISTRY_TOO_LARGE,
+    IDS_DEV_SETPROPERTIES_FAILED
+};
+
+
+/***************************************************************************
+ * NAME                                                         EXPORTED
+ *      DeviceProblemTextA
+ *
+ * DESCRIPTION
+ *   Gets the problem text from a problem number displayed in the properties dialog
+ *
+ * ARGUMENTS
+ *   hMachine:   Machine handle or NULL for the local machine
+ *   DevInst:    Device instance handle
+ *   uProblemId: Specifies the problem ID
+ *   lpString:   Pointer to a buffer where the string is to be copied to. If the buffer
+ *               is too small, the return value is the required string length in characters,
+ *               excluding the NULL-termination.
+ *   uMaxString: Size of the buffer in characters
+ *
+ * RETURN VALUE
+ *   The return value is the length of the string in characters.
+ *   It returns 0 if an error occured.
+ *
+ * @implemented
+ */
+UINT
+WINAPI
+DeviceProblemTextA(IN HMACHINE hMachine  OPTIONAL,
+                   IN DEVINST dnDevInst,
+                   IN ULONG uProblemId,
+                   OUT LPSTR lpString,
+                   IN UINT uMaxString)
+{
+    LPWSTR lpBuffer = NULL;
+    UINT Ret = 0;
+
+    if (uMaxString != 0)
+    {
+        lpBuffer = HeapAlloc(GetProcessHeap(),
+                             0,
+                             (uMaxString + 1) * sizeof(WCHAR));
+        if (lpBuffer == NULL)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            return 0;
+        }
+    }
+
+    Ret = DeviceProblemTextW(hMachine,
+                             dnDevInst,
+                             uProblemId,
+                             lpBuffer,
+                             uMaxString);
+
+    if (lpBuffer != NULL)
+    {
+        if (Ret)
+        {
+            WideCharToMultiByte(CP_ACP,
+                                0,
+                                lpBuffer,
+                                (int)Ret,
+                                lpString,
+                                (int)uMaxString,
+                                NULL,
+                                NULL);
+        }
+
+        HeapFree(GetProcessHeap(),
+                 0,
+                 lpBuffer);
+    }
+
+    return Ret;
+}
+
+
+/***************************************************************************
+ * NAME                                                         EXPORTED
+ *      DeviceProblemTextW
+ *
+ * DESCRIPTION
+ *   Gets the problem text from a problem number displayed in the properties dialog
+ *
+ * ARGUMENTS
+ *   hMachine:   Machine handle or NULL for the local machine
+ *   DevInst:    Device instance handle
+ *   uProblemId: Specifies the problem ID
+ *   lpString:   Pointer to a buffer where the string is to be copied to. If the buffer
+ *               is too small, the return value is the required string length in characters,
+ *               excluding the NULL-termination.
+ *   uMaxString: Size of the buffer in characters
+ *
+ * RETURN VALUE
+ *   The return value is the length of the string in characters.
+ *   It returns 0 if an error occured.
+ *
+ * @implemented
+ */
+UINT
+WINAPI
+DeviceProblemTextW(IN HMACHINE hMachine  OPTIONAL,
+                   IN DEVINST dnDevInst,
+                   IN ULONG uProblemId,
+                   OUT LPWSTR lpString,
+                   IN UINT uMaxString)
+{
+    UINT MessageId = IDS_UNKNOWN;
+    UINT Ret = 0;
+
+    if (uProblemId < sizeof(ProblemStringId) / sizeof(ProblemStringId[0]))
+        MessageId = ProblemStringId[uProblemId];
+
+    if (uProblemId == 0)
+    {
+        if (uMaxString != 0)
+        {
+            Ret = LoadString(hDllInstance,
+                             MessageId,
+                             lpString,
+                             (int)uMaxString);
+        }
+        else
+        {
+            Ret = (UINT)LengthOfStrResource(hDllInstance,
+                                            MessageId);
+        }
+    }
+    else
+    {
+        LPWSTR szProblem, szInfo = L"FIXME";
+        DWORD dwRet;
+        BOOL AdvFormat = FALSE;
+        UINT StringIDs[] =
+        {
+            MessageId,
+            IDS_DEVCODE,
+        };
+
+        switch (uProblemId)
+        {
+            case CM_PROB_DEVLOADER_FAILED:
+            {
+                /* FIXME - if not a root bus devloader then use IDS_DEV_DEVLOADER_FAILED2 */
+                /* FIXME - get the type string (ie. ISAPNP, PCI or BIOS for root bus devloaders,
+                           or FLOP, ESDI, SCSI, etc for others */
+                AdvFormat = TRUE;
+                break;
+            }
+
+            case CM_PROB_DEVLOADER_NOT_FOUND:
+            {
+                /* FIXME - 4 cases:
+                   1) if it's a missing system devloader:
+                      - get the system devloader name
+                   2) if it's not a system devloader but still missing:
+                      - get the devloader name (file name?)
+                   3) if it's not a system devloader but the file can be found:
+                      - use IDS_DEV_DEVLOADER_NOT_FOUND2
+                   4) if it's a missing or empty software key
+                      - use IDS_DEV_DEVLOADER_NOT_FOUND3
+                      - AdvFormat = FALSE!
+                 */
+                AdvFormat = TRUE;
+                break;
+            }
+
+            case CM_PROB_INVALID_DATA:
+                /* FIXME - if the device isn't enumerated by the BIOS/ACPI use IDS_DEV_INVALID_DATA2 */
+                AdvFormat = FALSE;
+                break;
+
+            case CM_PROB_NORMAL_CONFLICT:
+                /* FIXME - get resource type (IRQ, DMA, Memory or I/O) */
+                AdvFormat = TRUE;
+                break;
+
+            case CM_PROB_UNKNOWN_RESOURCE:
+                /* FIXME - get the .inf file name */
+                AdvFormat = TRUE;
+                break;
+
+            case CM_PROB_DISABLED:
+                /* FIXME - if the device was disabled by the system use IDS_DEV_DISABLED2 */
+                break;
+
+            case CM_PROB_FAILED_ADD:
+                /* FIXME - get the name of the sub-device with the error */
+                AdvFormat = TRUE;
+                break;
+        }
+
+        if (AdvFormat)
+        {
+            StringIDs[1] = IDS_DEVCODE2;
+            dwRet = LoadAndFormatStringsCat(hDllInstance,
+                                            StringIDs,
+                                            sizeof(StringIDs) / sizeof(StringIDs[0]),
+                                            &szProblem,
+                                            szInfo,
+                                            uProblemId);
+        }
+        else
+        {
+            dwRet = LoadAndFormatStringsCat(hDllInstance,
+                                            StringIDs,
+                                            sizeof(StringIDs) / sizeof(StringIDs[0]),
+                                            &szProblem,
+                                            uProblemId);
+        }
+
+        if (dwRet != 0)
+        {
+            if (uMaxString != 0 && uMaxString >= dwRet)
+            {
+                wcscpy(lpString,
+                       szProblem);
+            }
+
+            LocalFree((HLOCAL)szProblem);
+
+            Ret = dwRet;
+        }
+    }
+
+    return Ret;
+}
diff --git a/reactos/dll/win32/devmgr_new/hwpage.c b/reactos/dll/win32/devmgr_new/hwpage.c
new file mode 100644 (file)
index 0000000..2d7eae6
--- /dev/null
@@ -0,0 +1,1116 @@
+/*
+ * ReactOS Device Manager Applet
+ * Copyright (C) 2004 - 2005 ReactOS Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+/*
+ * PROJECT:         ReactOS devmgr.dll
+ * FILE:            lib/devmgr/hwpage.c
+ * PURPOSE:         ReactOS Device Manager
+ * PROGRAMMER:      Thomas Weidenmueller <w3seek@reactos.com>
+ * UPDATE HISTORY:
+ *      04-04-2004  Created
+ */
+
+#include "precomp.h"
+
+
+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;
+
+typedef struct _HARDWARE_PAGE_DATA
+{
+    HWND hWnd;
+    HWND hWndDevList;
+    HINSTANCE hComCtl32; /* only save this to keep track of the references */
+    INT DevListViewHeight;
+    SP_CLASSIMAGELIST_DATA ClassImageListData;
+    HWPAGE_DISPLAYMODE DisplayMode;
+
+    /* parent window subclass info */
+    WNDPROC ParentOldWndProc;
+    HWND hWndParent;
+
+    UINT NumberOfGuids;
+    HWCLASSDEVINFO ClassDevInfo[1];
+    /* struct may be dynamically expanded here! */
+} HARDWARE_PAGE_DATA, *PHARDWARE_PAGE_DATA;
+
+#define CX_TYPECOLUMN_WIDTH 80
+
+static VOID
+InitializeDevicesList(IN PHARDWARE_PAGE_DATA hpd)
+{
+    LVCOLUMN lvc;
+    RECT rcClient;
+    WCHAR szColName[255];
+    int iCol = 0;
+
+    /* set the list view style */
+    (void)ListView_SetExtendedListViewStyle(hpd->hWndDevList,
+                                            LVS_EX_FULLROWSELECT);
+
+    /* set the list view image list */
+    if (hpd->ClassImageListData.ImageList != NULL)
+    {
+        (void)ListView_SetImageList(hpd->hWndDevList,
+                                    hpd->ClassImageListData.ImageList,
+                                    LVSIL_SMALL);
+    }
+
+    GetClientRect(hpd->hWndDevList,
+                  &rcClient);
+
+    /* add the list view columns */
+    lvc.mask = LVCF_TEXT | LVCF_WIDTH;
+    lvc.fmt = LVCFMT_LEFT;
+    lvc.pszText = szColName;
+
+    if (LoadString(hDllInstance,
+                   IDS_NAME,
+                   szColName,
+                   sizeof(szColName) / sizeof(szColName[0])))
+    {
+        lvc.cx = rcClient.right - CX_TYPECOLUMN_WIDTH -
+                 GetSystemMetrics(SM_CXVSCROLL);
+        (void)ListView_InsertColumn(hpd->hWndDevList,
+                                    iCol++,
+                                    &lvc);
+    }
+    if (LoadString(hDllInstance,
+                   IDS_TYPE,
+                   szColName,
+                   sizeof(szColName) / sizeof(szColName[0])))
+    {
+        lvc.cx = CX_TYPECOLUMN_WIDTH;
+        (void)ListView_InsertColumn(hpd->hWndDevList,
+                                    iCol++,
+                                    &lvc);
+    }
+}
+
+
+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)
+    {
+        /* 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->ClassDevInfo->hDevInfo,
+                                    &HwDevInfo->DevInfoData,
+                                    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
+    {
+        /* 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
+BuildDevicesList(IN PHARDWARE_PAGE_DATA hpd)
+{
+    PHWCLASSDEVINFO ClassDevInfo, LastClassDevInfo;
+    SP_DEVINFO_DATA DevInfoData;
+
+    DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
+
+    ClassDevInfo = hpd->ClassDevInfo;
+    LastClassDevInfo = ClassDevInfo + hpd->NumberOfGuids;
+
+    while (ClassDevInfo != LastClassDevInfo)
+    {
+        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)
+        {
+            DWORD MemberIndex = 0;
+
+            SetupDiGetClassImageIndex(&hpd->ClassImageListData,
+                                      &ClassDevInfo->Guid,
+                                      &ClassDevInfo->ImageIndex);
+
+            /* enumerate all devices in the class */
+            while (SetupDiEnumDeviceInfo(ClassDevInfo->hDevInfo,
+                                         MemberIndex++,
+                                         &DevInfoData))
+            {
+                BOOL HideDevice = FALSE;
+
+                if (ClassDevInfo->HwDevInfo != NULL)
+                {
+                    PHWDEVINFO HwNewDevInfo = HeapReAlloc(GetProcessHeap(),
+                                                          0,
+                                                          ClassDevInfo->HwDevInfo,
+                                                          (ClassDevInfo->ItemCount + 1) *
+                                                              sizeof(HWDEVINFO));
+                    if (HwNewDevInfo != NULL)
+                    {
+                        ClassDevInfo->HwDevInfo = HwNewDevInfo;
+                    }
+                    else
+                    {
+                        ERR("Unable to allocate memory for %d SP_DEVINFO_DATA structures!\n",
+                            ClassDevInfo->ItemCount + 1);
+                        break;
+                    }
+                }
+                else
+                {
+                    ClassDevInfo->HwDevInfo = HeapAlloc(GetProcessHeap(),
+                                                        0,
+                                                        sizeof(HWDEVINFO));
+                    if (ClassDevInfo->HwDevInfo == NULL)
+                    {
+                        ERR("Unable to allocate memory for a SP_DEVINFO_DATA structures!\n");
+                        break;
+                    }
+                }
+
+                /* 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))
+                {
+                    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;
+                    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 = ClassDevInfo->ImageIndex;
+                    li.lParam = (LPARAM)HwDevInfo;
+
+                    iItem = ListView_InsertItem(hpd->hWndDevList,
+                                                &li);
+                    if (iItem != -1)
+                    {
+                        ItemCount++;
+
+                        /* 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;
+
+                            (void)ListView_SetItem(hpd->hWndDevList,
+                                                   &li);
+                        }
+                    }
+                }
+
+                HwDevInfo++;
+            }
+        }
+
+        ClassDevInfo++;
+    }
+
+    /* update the controls */
+    UpdateControlStates(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 */
+    (void)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,
+                 IN UINT uMsg,
+                 IN WPARAM wParam,
+                 IN LPARAM lParam)
+{
+    PHARDWARE_PAGE_DATA hpd;
+
+    hpd = (PHARDWARE_PAGE_DATA)GetProp(hwnd,
+                                       L"DevMgrSubClassInfo");
+    if (hpd != NULL)
+    {
+        if (uMsg == WM_SIZE)
+        {
+            /* resize the hardware page */
+            SetWindowPos(hpd->hWnd,
+                         NULL,
+                         0,
+                         0,
+                         LOWORD(lParam),
+                         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,
+                              hwnd,
+                              uMsg,
+                              wParam,
+                              lParam);
+    }
+    else
+    {
+        /* this is not a good idea if the subclassed window was an ansi
+           window, but we failed finding out the previous window proc
+           so we can't use CallWindowProc. This should rarely - if ever -
+           happen. */
+
+        return DefWindowProc(hwnd,
+                             uMsg,
+                             wParam,
+                             lParam);
+    }
+}
+
+
+static VOID
+HardwareDlgResize(IN PHARDWARE_PAGE_DATA hpd,
+                  IN INT cx,
+                  IN INT cy)
+{
+    HDWP dwp;
+    HWND hControl, hButton;
+    INT Width, x, y;
+    RECT rc, rcButton;
+    POINT pt = {0};
+    POINT ptMargin = {0};
+    POINT ptMarginGroup = {0};
+
+    /* use left margin of the IDC_DEVICES label as the right
+       margin of all controls outside the group box */
+    hControl = GetDlgItem(hpd->hWnd,
+                          IDC_DEVICES);
+    GetWindowRect(hControl,
+                  &rc);
+    MapWindowPoints(hControl,
+                    hpd->hWnd,
+                    &ptMargin,
+                    1);
+
+    Width = cx - (2 * ptMargin.x);
+
+    if ((dwp = BeginDeferWindowPos(8)))
+    {
+        /* rc already has the window rect of IDC_DEVICES! */
+        if (!(dwp = DeferWindowPos(dwp,
+                                   hControl,
+                                   NULL,
+                                   0,
+                                   0,
+                                   Width,
+                                   rc.bottom - rc.top,
+                                   SWP_NOMOVE | SWP_NOZORDER)))
+        {
+            return;
+        }
+
+        /* resize the devices list view control */
+        GetWindowRect(hpd->hWndDevList,
+                      &rc);
+        MapWindowPoints(hpd->hWndDevList,
+                        hpd->hWnd,
+                        &pt,
+                        1);
+        y = pt.y + hpd->DevListViewHeight + ptMargin.y;
+        if (!(dwp = DeferWindowPos(dwp,
+                                   hpd->hWndDevList,
+                                   NULL,
+                                   0,
+                                   0,
+                                   Width,
+                                   hpd->DevListViewHeight,
+                                   SWP_NOMOVE | SWP_NOZORDER)))
+        {
+            return;
+        }
+
+        /* resize the group box control */
+        hControl = GetDlgItem(hpd->hWnd,
+                              IDC_PROPERTIESGROUP);
+        GetWindowRect(hControl,
+                      &rc);
+        if (!(dwp = DeferWindowPos(dwp,
+                                   hControl,
+                                   NULL,
+                                   ptMargin.x,
+                                   y,
+                                   Width,
+                                   cy - y - ptMargin.y,
+                                   SWP_NOZORDER)))
+        {
+            return;
+        }
+
+        /* use left margin of the IDC_MANUFACTURER label as the right
+           margin of all controls inside the group box */
+        hControl = GetDlgItem(hpd->hWnd,
+                              IDC_MANUFACTURER);
+        GetWindowRect(hControl,
+                      &rc);
+        MapWindowPoints(hControl,
+                        hpd->hWnd,
+                        &ptMarginGroup,
+                        1);
+
+        ptMarginGroup.y = ptMargin.y * 2;
+        Width = cx - (2 * ptMarginGroup.x);
+        y += ptMarginGroup.y;
+        if (!(dwp = DeferWindowPos(dwp,
+                                   hControl,
+                                   NULL,
+                                   ptMarginGroup.x,
+                                   y,
+                                   Width,
+                                   rc.bottom - rc.top,
+                                   SWP_NOZORDER)))
+        {
+            return;
+        }
+        y += rc.bottom - rc.top + (ptMargin.y / 2);
+
+        /* resize the IDC_LOCATION label */
+        hControl = GetDlgItem(hpd->hWnd,
+                              IDC_LOCATION);
+        GetWindowRect(hControl,
+                      &rc);
+        if (!(dwp = DeferWindowPos(dwp,
+                                   hControl,
+                                   NULL,
+                                   ptMarginGroup.x,
+                                   y,
+                                   Width,
+                                   rc.bottom - rc.top,
+                                   SWP_NOZORDER)))
+        {
+            return;
+        }
+        y += rc.bottom - rc.top + (ptMargin.y / 2);
+
+        /* measure the size of the buttons */
+        hButton = GetDlgItem(hpd->hWnd,
+                             IDC_PROPERTIES);
+        GetWindowRect(hButton,
+                      &rcButton);
+
+        /* resize the IDC_STATUS label */
+        hControl = GetDlgItem(hpd->hWnd,
+                              IDC_STATUS);
+        GetWindowRect(hControl,
+                      &rc);
+        if (!(dwp = DeferWindowPos(dwp,
+                                   hControl,
+                                   NULL,
+                                   ptMarginGroup.x,
+                                   y,
+                                   Width,
+                                   cy - y - (3 * ptMargin.y) -
+                                       (rcButton.bottom - rcButton.top),
+                                   SWP_NOZORDER)))
+        {
+            return;
+        }
+
+        /* move the IDC_PROPERTIES button */
+        y = cy - (2 * ptMargin.y) - (rcButton.bottom - rcButton.top);
+        x = cx - ptMarginGroup.x - (rcButton.right - rcButton.left);
+        if (!(dwp = DeferWindowPos(dwp,
+                                   hButton,
+                                   NULL,
+                                   x,
+                                   y,
+                                   0,
+                                   0,
+                                   SWP_NOSIZE | SWP_NOZORDER)))
+        {
+            return;
+        }
+
+        /* move the IDC_TROUBLESHOOT button */
+        hButton = GetDlgItem(hpd->hWnd,
+                             IDC_TROUBLESHOOT);
+        GetWindowRect(hButton,
+                      &rcButton);
+        x -= (ptMargin.x / 2) + (rcButton.right - rcButton.left);
+        if (!(dwp = DeferWindowPos(dwp,
+                                   hButton,
+                                   NULL,
+                                   x,
+                                   y,
+                                   0,
+                                   0,
+                                   SWP_NOSIZE | SWP_NOZORDER)))
+        {
+            return;
+        }
+
+        EndDeferWindowPos(dwp);
+    }
+}
+
+
+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,
+                IN UINT uMsg,
+                IN WPARAM wParam,
+                IN LPARAM lParam)
+{
+    PHARDWARE_PAGE_DATA hpd;
+    INT_PTR Ret = FALSE;
+
+    hpd = (PHARDWARE_PAGE_DATA)GetWindowLongPtr(hwndDlg,
+                                                DWL_USER);
+
+    if (hpd != NULL || uMsg == WM_INITDIALOG)
+    {
+        switch (uMsg)
+        {
+            case WM_NOTIFY:
+            {
+                NMHDR *pnmh = (NMHDR*)lParam;
+                if (pnmh->hwndFrom == hpd->hWndDevList)
+                {
+                    switch (pnmh->code)
+                    {
+                        case LVN_ITEMCHANGED:
+                        {
+                            LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam;
+
+                            if ((pnmv->uChanged & LVIF_STATE) &&
+                                ((pnmv->uOldState & (LVIS_FOCUSED | LVIS_SELECTED)) ||
+                                 (pnmv->uNewState & (LVIS_FOCUSED | LVIS_SELECTED))))
+                            {
+                                UpdateControlStates(hpd);
+                            }
+                            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;
+            }
+
+            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_DEVICECHANGE:
+            {
+                /* FIXME - don't call UpdateDevicesListViewControl for all events */
+                UpdateDevicesListViewControl(hpd);
+                Ret = TRUE;
+                break;
+            }
+
+            case WM_INITDIALOG:
+            {
+                hpd = (PHARDWARE_PAGE_DATA)lParam;
+                if (hpd != NULL)
+                {
+                    HWND hWndParent;
+
+                    hpd->hWnd = hwndDlg;
+                    SetWindowLongPtr(hwndDlg,
+                                     DWL_USER,
+                                     (DWORD_PTR)hpd);
+
+                    hpd->ClassImageListData.cbSize = sizeof(SP_CLASSIMAGELIST_DATA);
+
+                    SetupDiGetClassImageList(&hpd->ClassImageListData);
+
+                    /* calculate the size of the devices list view control */
+                    hpd->hWndDevList = GetDlgItem(hwndDlg,
+                                                  IDC_LV_DEVICES);
+                    if (hpd->hWndDevList != NULL)
+                    {
+                        RECT rcClient;
+                        GetClientRect(hpd->hWndDevList,
+                                      &rcClient);
+                        hpd->DevListViewHeight = rcClient.bottom;
+
+                        if (hpd->DisplayMode == HWPD_LARGELIST)
+                        {
+                            hpd->DevListViewHeight = (hpd->DevListViewHeight * 3) / 2;
+                        }
+                    }
+
+                    /* subclass the parent window */
+                    hWndParent = GetAncestor(hwndDlg,
+                                             GA_PARENT);
+                    if (hWndParent != NULL)
+                    {
+                        RECT rcClient;
+
+                        if (GetClientRect(hWndParent,
+                                          &rcClient) &&
+