[DEVMGR]
authorGed Murphy <gedmurphy@reactos.org>
Wed, 17 Jun 2015 21:26:42 +0000 (21:26 +0000)
committerGed Murphy <gedmurphy@reactos.org>
Wed, 17 Jun 2015 21:26:42 +0000 (21:26 +0000)
- Make class and device nodes polymorphic and move the code into separate files
- Add an abstract base class which we attach to the listview nodes
- Add double clicking of nodes

svn path=/trunk/; revision=68180

reactos/dll/win32/devmgr/devmgmt/ClassNode.cpp [new file with mode: 0644]
reactos/dll/win32/devmgr/devmgmt/ClassNode.h [new file with mode: 0644]
reactos/dll/win32/devmgr/devmgmt/DeviceNode.cpp [new file with mode: 0644]
reactos/dll/win32/devmgr/devmgmt/DeviceNode.h [new file with mode: 0644]
reactos/dll/win32/devmgr/devmgmt/DeviceView.cpp
reactos/dll/win32/devmgr/devmgmt/DeviceView.h
reactos/dll/win32/devmgr/devmgmt/MainWindow.cpp
reactos/dll/win32/devmgr/devmgmt/Node.cpp
reactos/dll/win32/devmgr/devmgmt/Node.h

diff --git a/reactos/dll/win32/devmgr/devmgmt/ClassNode.cpp b/reactos/dll/win32/devmgr/devmgmt/ClassNode.cpp
new file mode 100644 (file)
index 0000000..55fa95d
--- /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(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
+        wcscpy_s(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))
+        {
+            wcscpy_s(ResourceDescriptor, ResourceDescriptorSize, ResString);
+            dwError = ERROR_SUCCESS;
+        }
+        else
+        {
+            dwError = GetLastError();
+        }
+
+        // Free the library
+        FreeLibrary(hModule);
+    }
+
+    return dwError;
+}
diff --git a/reactos/dll/win32/devmgr/devmgmt/ClassNode.h b/reactos/dll/win32/devmgr/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/devmgmt/DeviceNode.cpp b/reactos/dll/win32/devmgr/devmgmt/DeviceNode.cpp
new file mode 100644 (file)
index 0000000..000da62
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+* 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(ImageListData),
+    m_DevInst(Device),
+    m_Status(0),
+    m_ProblemNumber(0),
+    m_OverlayImage(0)
+{
+}
+
+CDeviceNode::~CDeviceNode()
+{
+}
+
+bool
+CDeviceNode::SetupNode()
+{
+    WCHAR ClassGuidString[MAX_GUID_STRING_LEN];
+    ULONG ulLength;
+    CONFIGRET cr;
+
+    //    ATLASSERT(m_DeviceId == NULL);
+
+    // 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 = (LPWSTR)HeapAlloc(GetProcessHeap(),
+                                       0,
+                                       (ulLength + 1) * sizeof(WCHAR));
+        if (m_DeviceId)
+        {
+            // Now get the actual device id
+            cr = CM_Get_Device_IDW(m_DevInst,
+                                   m_DeviceId,
+                                   ulLength + 1,
+                                   0);
+            if (cr != CR_SUCCESS)
+            {
+                HeapFree(GetProcessHeap(), 0, m_DeviceId);
+                m_DeviceId = NULL;
+            }
+        }
+    }
+
+    // Make sure we got the string
+    if (m_DeviceId == NULL)
+        return false;
+
+    // Get the current status of the device
+    cr = CM_Get_DevNode_Status_Ex(&m_Status,
+                                  &m_ProblemNumber,
+                                  m_DevInst,
+                                  0,
+                                  NULL);
+    if (cr != CR_SUCCESS)
+    {
+        HeapFree(GetProcessHeap(), 0, m_DeviceId);
+        m_DeviceId = NULL;
+        return false;
+    }
+
+    // Check if the device has a problem
+    if (m_Status & DN_HAS_PROBLEM)
+    {
+        m_OverlayImage = 1;
+    }
+
+    // The disabled overlay takes precidence over the problem overlay
+    if (m_ProblemNumber & (CM_PROB_DISABLED | CM_PROB_HARDWARE_DISABLED))
+    {
+        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)
+    {
+        HeapFree(GetProcessHeap(), 0, m_DeviceId);
+        m_DeviceId = NULL;
+    }
+
+    return (cr == CR_SUCCESS ? true : 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;
+}
\ No newline at end of file
diff --git a/reactos/dll/win32/devmgr/devmgmt/DeviceNode.h b/reactos/dll/win32/devmgr/devmgmt/DeviceNode.h
new file mode 100644 (file)
index 0000000..2b0ad42
--- /dev/null
@@ -0,0 +1,34 @@
+#pragma once
+#include "Node.h"
+
+class CDeviceNode : public CNode
+{
+private:
+    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() { return !!(m_ProblemNumber); }
+    bool IsHidden();
+    bool CanDisable();
+    bool IsDisabled();
+    bool IsStarted();
+    bool IsInstalled();
+    bool CanInstall() { return TRUE; } // unimplemented
+    bool CanUninstall() { return TRUE; } // unimplemented
+};
+
index f0c3c2d..03ef161 100644 (file)
@@ -1,11 +1,11 @@
 /*
-* 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>
-*
-*/
+ * 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 "DeviceView.h"
 
 
-/* DATA *********************************************/
+// DATA ********************************************/
 
 #define CLASS_NAME_LEN      256
 #define CLASS_DESC_LEN      256
+#define ROOT_NAME_SIZE      MAX_COMPUTERNAME_LENGTH + 1
 
 INT_PTR
 WINAPI
@@ -38,7 +39,7 @@ struct RefreshThreadData
 };
 
 
-/* PUBLIC METHODS *************************************/
+// PUBLIC METHODS ************************************/
 
 CDeviceView::CDeviceView(
     HWND hMainWnd
@@ -269,7 +270,7 @@ CDeviceView::IsDisabled(
     _In_ LPTV_ITEMW TvItem
     )
 {
-    CNode *Node = GetNode(TvItem);
+    CDeviceNode *Node = dynamic_cast<CDeviceNode *>(GetNode(TvItem));
     if (Node)
     {
         return Node->IsDisabled();
@@ -282,16 +283,16 @@ CDeviceView::CanDisable(
     _In_ LPTV_ITEMW TvItem
     )
 {
-    CNode *Node = GetNode(TvItem);
+    CDeviceNode *Node = dynamic_cast<CDeviceNode *>(GetNode(TvItem));
     if (Node)
     {
-        return Node->CanDisable();
+        Node->CanDisable();
     }
     return false;
 }
 
 
-/* PRIVATE METHODS ********************************************/
+// PRIVATE METHODS *******************************************/
 
 bool
 CDeviceView::AddRootDevice()
@@ -312,7 +313,7 @@ CDeviceView::AddRootDevice()
         DeleteObject(hRootImage);
     }
 
-    /* Get the root instance */
+    // Get the root instance 
     CONFIGRET cr;
     cr = CM_Locate_DevNodeW(&m_RootDevInst,
                             NULL,
@@ -322,7 +323,7 @@ CDeviceView::AddRootDevice()
         return false;
     }
 
-    /* The root name is the computer name */
+    // The root name is the computer name 
     WCHAR RootDeviceName[ROOT_NAME_SIZE];
     DWORD Size = ROOT_NAME_SIZE;
     if (GetComputerNameW(RootDeviceName, &Size))
@@ -425,7 +426,8 @@ unsigned int __stdcall CDeviceView::RefreshThread(void *Param)
 bool
 CDeviceView::ListDevicesByType()
 {
-    CNode *ClassNode, *DeviceNode;
+    CClassNode *ClassNode;
+    CDeviceNode *DeviceNode;
     HDEVINFO hDevInfo;
     HTREEITEM hTreeItem = NULL;
     GUID ClassGuid;
@@ -574,10 +576,10 @@ CDeviceView::ListDevicesByConnection()
     bSuccess = AddRootDevice();
     if (bSuccess == false) return false;
 
-    /* Walk the device tree and add all the devices */
+    // Walk the device tree and add all the devices 
     RecurseChildDevices(m_RootDevInst, m_hTreeRoot);
 
-    /* Expand the root item */
+    // Expand the root item 
     (VOID)TreeView_Expand(m_hTreeView,
                           m_hTreeRoot,
                           TVE_EXPAND);
@@ -596,13 +598,13 @@ CDeviceView::RecurseChildDevices(
     DEVINST Device;
     BOOL bSuccess;
 
-    /* Check if the parent has any child devices */
+    // Check if the parent has any child devices 
     if (GetChildDevice(ParentDevice, &Device) == FALSE)
         return;
 
     // Get the cached device node
-    CNode *DeviceNode;
-    DeviceNode = GetDeviceNode(Device);
+    CDeviceNode *DeviceNode;
+    DeviceNode = dynamic_cast<CDeviceNode *>(GetDeviceNode(Device));
     if (DeviceNode == NULL)
     {
         ATLASSERT(FALSE);
@@ -610,17 +612,17 @@ CDeviceView::RecurseChildDevices(
     }
 
 
-    /* Check if this is a hidden device */
+    // Check if this is a hidden device 
     if ((m_ShowHidden == TRUE) || (!(DeviceNode->IsHidden())))
     {
-        /* Add this device to the tree under its parent */
+        // Add this device to the tree under its parent 
         hDevItem = InsertIntoTreeView(hParentTreeItem,
                                       DeviceNode);
 
 
         if (hDevItem)
         {
-            /* Check if this child has any children itself */
+            // Check if this child has any children itself 
             RecurseChildDevices(Device, hDevItem);
         }
     }
@@ -628,29 +630,29 @@ CDeviceView::RecurseChildDevices(
 
     for (;;)
     {
-        /* Check if the parent device has anything at the same level */
+        // Check if the parent device has anything at the same level 
         bSuccess = GetSiblingDevice(Device, &Device);
         if (bSuccess == FALSE) break;
 
-        DeviceNode = GetDeviceNode(Device);
+        DeviceNode = dynamic_cast<CDeviceNode *>(GetDeviceNode(Device));
         if (DeviceNode == NULL)
         {
             ATLASSERT(FALSE);
         }
 
-        /* Check if this is a hidden device */
+        // Check if this is a hidden device 
         if (DeviceNode->IsHidden())
         {
             if (m_ShowHidden == FALSE)
                 continue;
         }
 
-        /* Add this device to the tree under its parent */
+        // Add this device to the tree under its parent 
         hDevItem = InsertIntoTreeView(hParentTreeItem,
                                       DeviceNode);
         if (hDevItem)
         {
-            /* Check if this child has any children itself */
+            // Check if this child has any children itself 
             RecurseChildDevices(Device, hDevItem);
         }
     }
@@ -709,11 +711,13 @@ CDeviceView::InsertIntoTreeView(
     tvi.iImage = Node->GetClassImage();
     tvi.iSelectedImage = Node->GetClassImage();
 
-    if (Node->GetOverlayImage())
+    // 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(Node->GetOverlayImage());
+        tvi.state = INDEXTOOVERLAYMASK(DeviceNode->GetOverlayImage());
     }
 
     tvins.item = tvi;
@@ -763,7 +767,7 @@ CDeviceView::RecurseDeviceView(
             //    delete reinterpret_cast<CNode *>(tvItem.lParam);
         }
 
-        /* This node may have its own children */
+        // This node may have its own children 
         RecurseDeviceView(hItem);
     }
 }
@@ -788,11 +792,11 @@ CDeviceView::EmptyDeviceView()
 
 
 
-CNode*
+CClassNode*
 CDeviceView::GetClassNode(_In_ LPGUID ClassGuid)
 {
     POSITION Pos;
-    CNode *Node;
+    CClassNode *Node;
 
     Pos = m_ClassNodeList.GetHeadPosition();
 
@@ -812,11 +816,11 @@ CDeviceView::GetClassNode(_In_ LPGUID ClassGuid)
     return Node;
 }
 
-CNode*
+CDeviceNode*
 CDeviceView::GetDeviceNode(_In_ DEVINST Device)
 {
     POSITION Pos;
-    CNode *Node;
+    CDeviceNode *Node;
 
     Pos = m_DeviceNodeList.GetHeadPosition();
 
@@ -843,6 +847,7 @@ CNode* CDeviceView::GetNode(LPTV_ITEMW TvItem)
     {
         return (CNode *)TvItem->lParam;
     }
+    return NULL;
 }
 
 CNode* CDeviceView::GetSelectedNode()
@@ -885,7 +890,8 @@ bool
 CDeviceView::RefreshDeviceList()
 {
     GUID ClassGuid;
-    CNode *Node;
+    CClassNode *ClassNode;
+    CDeviceNode *DeviceNode;
     HDEVINFO hDevInfo;
     SP_DEVINFO_DATA DeviceInfoData;
     DWORD i;
@@ -895,22 +901,24 @@ CDeviceView::RefreshDeviceList()
 
     EmptyLists();
 
+    // Loop through all the classes
     do
     {
         Success = GetNextClass(ClassIndex, &ClassGuid, &hDevInfo);
         if (Success)
         {
-            /* Create a new class node */
-            Node = new CNode(&ClassGuid, &m_ImageListData);
-            if (Node->Setup())
+            // Create a new class node and add it to the list
+            ClassNode = new CClassNode(&ClassGuid, &m_ImageListData);
+            if (ClassNode->SetupNode())
             {
-                m_ClassNodeList.AddTail(Node);
+                m_ClassNodeList.AddTail(ClassNode);
             }
         }
         ClassIndex++;
     } while (Success);
 
 
+    // Get all the devices on the local machine
     hDevInfo = SetupDiGetClassDevsW(NULL,
                                     0,
                                     0,
@@ -920,17 +928,20 @@ CDeviceView::RefreshDeviceList()
         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;
 
-
-        Node = new CNode(DeviceInfoData.DevInst, &m_ImageListData);
-        Node->Setup();
-        m_DeviceNodeList.AddTail(Node);
+        // 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);
index 9b41308..fd0159c 100644 (file)
@@ -1,5 +1,6 @@
 #pragma once
-#include "Node.h"
+#include "DeviceNode.h"
+#include "ClassNode.h"
 
 enum ViewType
 {
@@ -12,8 +13,8 @@ enum ViewType
 
 class CDeviceView
 {
-    CAtlList<CNode *> m_ClassNodeList;
-    CAtlList<CNode *> m_DeviceNodeList;
+    CAtlList<CClassNode *> m_ClassNodeList;
+    CAtlList<CDeviceNode *> m_DeviceNodeList;
 
     SP_CLASSIMAGELIST_DATA m_ImageListData;
 
@@ -128,8 +129,8 @@ private:
     CNode* GetNode(_In_ LPTV_ITEMW TvItem);
     CNode* GetSelectedNode();
 
-    CNode* GetClassNode(_In_ LPGUID ClassGuid);
-    CNode* GetDeviceNode(_In_ DEVINST Device);
+    CClassNode* GetClassNode(_In_ LPGUID ClassGuid);
+    CDeviceNode* GetDeviceNode(_In_ DEVINST Device);
     void EmptyLists();
 };
 
index 8b3242a..59e28be 100644 (file)
@@ -456,6 +456,13 @@ CMainWindow::OnNotify(LPARAM lParam)
             break;
         }
 
+        case NM_DBLCLK:
+        {
+            LPNMTREEVIEW NmTreeView = (LPNMTREEVIEW)lParam;
+            m_DeviceView->DisplayPropertySheet();
+            break;
+        }
+
         case NM_RCLICK:
         {
             Ret = m_DeviceView->OnRightClick(NmHdr);
index 94f7732..be54a0b 100644 (file)
 
 /* PUBLIC METHODS *******************************************/
 
-CNode::CNode(_In_ LPGUID ClassGuid,
-             _In_ PSP_CLASSIMAGELIST_DATA ImageListData) :
+CNode::CNode(_In_ PSP_CLASSIMAGELIST_DATA ImageListData) :
     m_ImageListData(ImageListData),
-    m_NodeType(NodeClass),
-    m_DevInst(0),
     m_DeviceId(NULL),
-    m_ClassImage(0),
-    m_Status(0),
-    m_ProblemNumber(0),
-    m_OverlayImage(0)
+    m_ClassImage(0)
 {
     m_DisplayName[0] = UNICODE_NULL;
-    CopyMemory(&m_ClassGuid, ClassGuid, sizeof(GUID));
-}
-
-CNode::CNode(_In_opt_ DEVINST Device,
-             _In_ PSP_CLASSIMAGELIST_DATA ImageListData) :
-    m_ImageListData(ImageListData),
-    m_NodeType(NodeDevice),
-    m_DevInst(Device),
-    m_DeviceId(NULL),
-    m_ClassImage(0),
-    m_Status(0),
-    m_ProblemNumber(0),
-    m_OverlayImage(0)
-{
-    m_DisplayName[0] = UNICODE_NULL;
-    CopyMemory(&m_ClassGuid, &GUID_NULL, sizeof(GUID));
 }
 
 CNode::~CNode()
@@ -49,306 +27,9 @@ CNode::~CNode()
     Cleanup();
 }
 
-bool
-CNode::Setup()
-{
-    // TODO: Make this polymorphic
-
-    if (m_NodeType == NodeClass)
-    {
-        return SetupClassNode();
-    }
-    else if (m_NodeType == NodeDevice)
-    {
-        return SetupDeviceNode();
-    }
-
-    return FALSE;
-}
-
-bool
-CNode::HasProperties()
-{
-    return (m_DeviceId != NULL);
-}
-
-bool
-CNode::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
-CNode::CanDisable()
-{
-    CONFIGRET cr;
-    cr = CM_Get_DevNode_Status_Ex(&m_Status,
-                                  &m_ProblemNumber,
-                                  m_DevInst,
-                                  0,
-                                  NULL);
-    if (cr == CR_SUCCESS)
-    {
-        return (m_NodeType == NodeDevice && ((m_Status & DN_DISABLEABLE) != 0));
-    }
-
-    return false;
-}
-
-bool
-CNode::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
-CNode::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
-CNode::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;
-}
-
 
 /* PRIVATE METHODS ******************************************/
 
-bool
-CNode::SetupClassNode()
-{
-    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;
-}
-
-bool
-CNode::SetupDeviceNode()
-{
-    WCHAR ClassGuidString[MAX_GUID_STRING_LEN];
-    ULONG ulLength;
-    CONFIGRET cr;
-
-//    ATLASSERT(m_DeviceId == NULL);
-
-    // 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 = (LPWSTR)HeapAlloc(GetProcessHeap(),
-                                      0,
-                                      (ulLength + 1) * sizeof(WCHAR));
-        if (m_DeviceId)
-        {
-            // Now get the actual device id
-            cr = CM_Get_Device_IDW(m_DevInst,
-                                   m_DeviceId,
-                                   ulLength + 1,
-                                   0);
-            if (cr != CR_SUCCESS)
-            {
-                HeapFree(GetProcessHeap(), 0, m_DeviceId);
-                m_DeviceId = NULL;
-            }
-        }
-    }
-
-    // Make sure we got the string
-    if (m_DeviceId == NULL)
-        return false;
-
-    // Get the current status of the device
-    cr = CM_Get_DevNode_Status_Ex(&m_Status,
-                                  &m_ProblemNumber,
-                                  m_DevInst,
-                                  0,
-                                  NULL);
-    if (cr != CR_SUCCESS)
-    {
-        HeapFree(GetProcessHeap(), 0, m_DeviceId);
-        m_DeviceId = NULL;
-        return false;
-    }
-
-    // Check if the device has a problem
-    if (m_Status & DN_HAS_PROBLEM)
-    {
-        m_OverlayImage = 1;
-    }
-
-    // The disabled overlay takes precidence over the problem overlay
-    if (m_ProblemNumber & (CM_PROB_DISABLED | CM_PROB_HARDWARE_DISABLED))
-    {
-        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)
-    {
-        HeapFree(GetProcessHeap(), 0, m_DeviceId);
-        m_DeviceId = NULL;
-    }
-
-    return (cr == CR_SUCCESS ? true : false);
-}
 
 void
 CNode::Cleanup()
@@ -359,72 +40,3 @@ CNode::Cleanup()
         m_DeviceId = NULL;
     }
 }
-
-DWORD
-CNode::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
-        wcscpy_s(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))
-        {
-            wcscpy_s(ResourceDescriptor, ResourceDescriptorSize, ResString);
-            dwError = ERROR_SUCCESS;
-        }
-        else
-        {
-            dwError = GetLastError();
-        }
-
-        // Free the library
-        FreeLibrary(hModule);
-    }
-
-    return dwError;
-}
index 2a858bb..5374863 100644 (file)
@@ -1,78 +1,34 @@
 #pragma once
 
 #define DISPLAY_NAME_LEN    256
-#define ROOT_NAME_SIZE      MAX_COMPUTERNAME_LENGTH + 1
-
-enum NodeType
-{
-    NodeClass,
-    NodeDevice
-};
-
-typedef ULONG Actions;
-#define Update      0x01
-#define Enable      0x02
-#define Disable     0x04
-#define Uninstall   0x08
-
 
 class CNode
 {
-private:
+protected:
     PSP_CLASSIMAGELIST_DATA m_ImageListData;
-    NodeType m_NodeType;
-    DEVINST m_DevInst;
-    Actions m_Actions;
     LPWSTR m_DeviceId;
     WCHAR m_DisplayName[DISPLAY_NAME_LEN];
     GUID  m_ClassGuid;
     INT m_ClassImage;
-    ULONG m_Status;
-    ULONG m_ProblemNumber;
-    INT m_OverlayImage;
 
 public:
     CNode(
-        _In_ LPGUID ClassGuid,
-        _In_ PSP_CLASSIMAGELIST_DATA ImageListData
-        );
-
-    CNode(
-        _In_ DEVINST Device,
         _In_ PSP_CLASSIMAGELIST_DATA ImageListData
         );
 
     ~CNode();
 
-    bool Setup();
-
-    LPGUID GetClassGuid() { return &m_ClassGuid;  }
-    DEVINST GetDeviceInst() { return m_DevInst; }
+    virtual bool SetupNode() = 0;
 
+    LPGUID GetClassGuid() { return &m_ClassGuid; }
     LPWSTR GetDisplayName() { return m_DisplayName; }
     INT GetClassImage() { return m_ClassImage; }
-    INT GetOverlayImage() { return m_OverlayImage; }
     LPWSTR GetDeviceId() { return m_DeviceId; }
-    Actions GetActions() { return m_Actions; }
 
-    bool HasProblem() { return !!(m_ProblemNumber); }
-    bool HasProperties();
-    bool IsHidden();
-    bool CanDisable();
-    bool IsDisabled();
-    bool IsStarted();
-    bool IsInstalled();
-    bool CanInstall() { return TRUE; } // unimplemented
-    bool CanUninstall() { return TRUE; } // unimplemented
+    bool HasProperties() { return (m_DeviceId != NULL); }
 
 private:
-    bool SetupClassNode();
-    bool SetupDeviceNode();
     void Cleanup();
 
-    DWORD ConvertResourceDescriptorToString(
-        _Inout_z_ LPWSTR ResourceDescriptor,
-        _In_ DWORD ResourceDescriptorSize
-        );
 };