From 27e12f2db67dabb3c1e8f29660d76aa8f18c303d Mon Sep 17 00:00:00 2001 From: Ged Murphy Date: Fri, 3 Jul 2015 06:56:58 +0000 Subject: [PATCH] [DEVMGR] - Implement dynamic context menu for device and class nodes - Fix CanUninstall to return correct results - Strings hardcoded for now, will fix soon svn path=/trunk/; revision=68334 --- .../dll/win32/devmgr/devmgmt/ClassNode.cpp | 2 +- .../dll/win32/devmgr/devmgmt/DeviceNode.cpp | 9 +- reactos/dll/win32/devmgr/devmgmt/DeviceNode.h | 3 +- .../dll/win32/devmgr/devmgmt/DeviceView.cpp | 146 ++++++++++++++---- reactos/dll/win32/devmgr/devmgmt/DeviceView.h | 7 +- reactos/dll/win32/devmgr/devmgmt/Node.cpp | 4 +- reactos/dll/win32/devmgr/devmgmt/Node.h | 10 ++ 7 files changed, 142 insertions(+), 39 deletions(-) diff --git a/reactos/dll/win32/devmgr/devmgmt/ClassNode.cpp b/reactos/dll/win32/devmgr/devmgmt/ClassNode.cpp index 55fa95d41aa..b2c1471bdb4 100644 --- a/reactos/dll/win32/devmgr/devmgmt/ClassNode.cpp +++ b/reactos/dll/win32/devmgr/devmgmt/ClassNode.cpp @@ -16,7 +16,7 @@ CClassNode::CClassNode( _In_ LPGUID ClassGuid, _In_ PSP_CLASSIMAGELIST_DATA ImageListData ) : - CNode(ImageListData) + CNode(ClassNode, ImageListData) { CopyMemory(&m_ClassGuid, ClassGuid, sizeof(GUID)); } diff --git a/reactos/dll/win32/devmgr/devmgmt/DeviceNode.cpp b/reactos/dll/win32/devmgr/devmgmt/DeviceNode.cpp index a4f46a8c49f..740e65378b7 100644 --- a/reactos/dll/win32/devmgr/devmgmt/DeviceNode.cpp +++ b/reactos/dll/win32/devmgr/devmgmt/DeviceNode.cpp @@ -16,7 +16,7 @@ CDeviceNode::CDeviceNode( _In_opt_ DEVINST Device, _In_ PSP_CLASSIMAGELIST_DATA ImageListData ) : - CNode(ImageListData), + CNode(DeviceNode, ImageListData), m_DevInst(Device), m_hDevInfo(NULL), m_Status(0), @@ -260,11 +260,12 @@ CDeviceNode::CanUninstall() NULL); if (cr == CR_SUCCESS) { - return ((m_Status & DN_DISABLEABLE) != 0 && - (m_Status & DN_ROOT_ENUMERATED) == 0); + if ((m_Status & DN_ROOT_ENUMERATED) != 0 && + (m_Status & DN_DISABLEABLE) == 0) + return false; } - return false; + return true; } bool diff --git a/reactos/dll/win32/devmgr/devmgmt/DeviceNode.h b/reactos/dll/win32/devmgr/devmgmt/DeviceNode.h index 190a4444439..42baef7abef 100644 --- a/reactos/dll/win32/devmgr/devmgmt/DeviceNode.h +++ b/reactos/dll/win32/devmgr/devmgmt/DeviceNode.h @@ -27,10 +27,11 @@ public: bool HasProblem(); bool IsHidden(); bool CanDisable(); - bool IsDisabled(); + virtual bool IsDisabled(); bool IsStarted(); bool IsInstalled(); bool CanUninstall(); + virtual bool CanUpdate() { return true; } // unimplemented bool EnableDevice( _In_ bool Enable, diff --git a/reactos/dll/win32/devmgr/devmgmt/DeviceView.cpp b/reactos/dll/win32/devmgr/devmgmt/DeviceView.cpp index 003fad434f5..dc4f4f256ab 100644 --- a/reactos/dll/win32/devmgr/devmgmt/DeviceView.cpp +++ b/reactos/dll/win32/devmgr/devmgmt/DeviceView.cpp @@ -49,7 +49,6 @@ CDeviceView::CDeviceView( m_hTreeView(NULL), m_hPropertyDialog(NULL), m_hMenu(NULL), - m_hContextMenu(NULL), m_ViewType(DevicesByType), m_ShowHidden(FALSE), m_RootClassImage(-1), @@ -92,9 +91,7 @@ CDeviceView::Initialize() SetWindowTheme(m_hTreeView, L"explorer", NULL); } - // Create the context menu and make properties the default item - m_hContextMenu = CreatePopupMenu(); - SetMenuDefaultItem(m_hContextMenu, IDC_PROPERTIES, FALSE); + return !!(m_hTreeView); } @@ -110,8 +107,6 @@ CDeviceView::Uninitialize() ZeroMemory(&m_ImageListData, sizeof(SP_CLASSIMAGELIST_DATA)); } - DestroyMenu(m_hContextMenu); - return true; } @@ -168,26 +163,14 @@ CDeviceView::OnContextMenu( PtInRect(&rc, pt)) { - CNode *Node = GetSelectedNode(); - if (Node && Node->HasProperties()) - { - - } - - - - - - INT xPos = GET_X_LPARAM(lParam); INT yPos = GET_Y_LPARAM(lParam); - TrackPopupMenuEx(m_hContextMenu, - TPM_RIGHTBUTTON, - xPos, - yPos, - m_hMainWnd, - NULL); + CNode *Node = GetSelectedNode(); + if (Node) + { + BuildContextMenuForNode(Node, xPos, yPos); + } } } @@ -807,6 +790,100 @@ CDeviceView::InsertIntoTreeView( return TreeView_InsertItem(m_hTreeView, &tvins); } +void +CDeviceView::BuildContextMenuForNode( + _In_ CNode *Node, + _In_ INT xPos, + _In_ INT yPos + ) +{ + // Create the context menu + HMENU hContextMenu = CreatePopupMenu(); + + // 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; + + int i = 0; + + // Device nodes have extra data + if (Node->GetNodeType() == DeviceNode) + { + CDeviceNode *DeviceNode = dynamic_cast(Node); + + if (DeviceNode->CanUpdate()) + { + MenuItemInfo.wID = IDC_UPDATE_DRV; + MenuItemInfo.dwTypeData = L"Update driver software..."; + InsertMenuItemW(hContextMenu, i, TRUE, &MenuItemInfo); + i++; + } + + if (DeviceNode->IsDisabled()) + { + MenuItemInfo.wID = IDC_ENABLE_DRV; + MenuItemInfo.dwTypeData = L"Enable"; + InsertMenuItemW(hContextMenu, i, TRUE, &MenuItemInfo); + i++; + } + + if (DeviceNode->CanDisable() && !DeviceNode->IsDisabled()) + { + MenuItemInfo.wID = IDC_DISABLE_DRV; + MenuItemInfo.dwTypeData = L"Disable"; + InsertMenuItemW(hContextMenu, i, TRUE, &MenuItemInfo); + i++; + } + + if (DeviceNode->CanUninstall()) + { + MenuItemInfo.wID = IDC_UNINSTALL_DRV; + MenuItemInfo.dwTypeData = L"Uninstall"; + InsertMenuItemW(hContextMenu, i, TRUE, &MenuItemInfo); + i++; + } + + InsertMenuItemW(hContextMenu, i, TRUE, &MenuSeperator); + i++; + } + + // All nodes have the scan option + MenuItemInfo.wID = IDC_SCAN_HARDWARE; + MenuItemInfo.dwTypeData = L"Scan for hardware changes"; + InsertMenuItemW(hContextMenu, i, TRUE, &MenuItemInfo); + i++; + + if (Node->HasProperties()) + { + InsertMenuItemW(hContextMenu, i, TRUE, &MenuSeperator); + i++; + + MenuItemInfo.wID = IDC_PROPERTIES; + MenuItemInfo.dwTypeData = L"Properties"; + InsertMenuItemW(hContextMenu, i, TRUE, &MenuItemInfo); + i++; + + SetMenuDefaultItem(hContextMenu, IDC_PROPERTIES, FALSE); + } + + // Display the menu + TrackPopupMenuEx(hContextMenu, + TPM_RIGHTBUTTON, + xPos, + yPos, + m_hMainWnd, + NULL); + + DestroyMenu(hContextMenu); +} + HTREEITEM CDeviceView::RecurseFindDevice( _In_ HTREEITEM hParentItem, @@ -828,6 +905,7 @@ CDeviceView::RecurseFindDevice( if (TreeView_GetItem(m_hTreeView, &tvItem) && tvItem.lParam != NULL) { + // check for a matching deviceid Node = reinterpret_cast(tvItem.lParam); if (Node->GetDeviceId() && (wcscmp(Node->GetDeviceId(), DeviceId) == 0)) @@ -840,7 +918,7 @@ CDeviceView::RecurseFindDevice( FoundItem = RecurseFindDevice(hItem, DeviceId); if (FoundItem) return FoundItem; - // Delete all the siblings + // Loop all the siblings for (;;) { // Get the next item at this level @@ -852,6 +930,7 @@ CDeviceView::RecurseFindDevice( tvItem.mask = TVIF_PARAM; if (TreeView_GetItem(m_hTreeView, &tvItem)) { + // check for a matching deviceid Node = reinterpret_cast(tvItem.lParam); if (Node->GetDeviceId() && wcscmp(Node->GetDeviceId(), DeviceId) == 0) @@ -879,14 +958,19 @@ CDeviceView::SelectNode( hRoot = TreeView_GetRoot(m_hTreeView); if (hRoot == NULL) return; - if (DeviceId) + // If we don't want to set select a node, just select root + if (DeviceId == NULL) { - hItem = RecurseFindDevice(hRoot, DeviceId); - if (hItem) - { - TreeView_SelectItem(m_hTreeView, hItem); - TreeView_Expand(m_hTreeView, hItem, TVM_EXPAND); - } + 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 { diff --git a/reactos/dll/win32/devmgr/devmgmt/DeviceView.h b/reactos/dll/win32/devmgr/devmgmt/DeviceView.h index fc5d29f646b..438d6571f73 100644 --- a/reactos/dll/win32/devmgr/devmgmt/DeviceView.h +++ b/reactos/dll/win32/devmgr/devmgmt/DeviceView.h @@ -20,7 +20,6 @@ class CDeviceView HWND m_hTreeView; HWND m_hPropertyDialog; HMENU m_hMenu; - HMENU m_hContextMenu; ViewType m_ViewType; HTREEITEM m_hTreeRoot; DEVINST m_RootDevInst; @@ -128,6 +127,12 @@ private: _In_ CNode *Node ); + void BuildContextMenuForNode( + _In_ CNode *Node, + _In_ INT xPos, + _In_ INT yPos + ); + HTREEITEM RecurseFindDevice( _In_ HTREEITEM hParentItem, _In_ LPWSTR DeviceId diff --git a/reactos/dll/win32/devmgr/devmgmt/Node.cpp b/reactos/dll/win32/devmgr/devmgmt/Node.cpp index e189aa416ee..1289582e543 100644 --- a/reactos/dll/win32/devmgr/devmgmt/Node.cpp +++ b/reactos/dll/win32/devmgr/devmgmt/Node.cpp @@ -14,7 +14,9 @@ /* PUBLIC METHODS *******************************************/ -CNode::CNode(_In_ PSP_CLASSIMAGELIST_DATA ImageListData) : +CNode::CNode(_In_ NodeType Type, + _In_ PSP_CLASSIMAGELIST_DATA ImageListData) : + m_NodeType(Type), m_ImageListData(ImageListData), m_DeviceId(NULL), m_ClassImage(0) diff --git a/reactos/dll/win32/devmgr/devmgmt/Node.h b/reactos/dll/win32/devmgr/devmgmt/Node.h index 5374863d23f..bea3840018d 100644 --- a/reactos/dll/win32/devmgr/devmgmt/Node.h +++ b/reactos/dll/win32/devmgr/devmgmt/Node.h @@ -2,6 +2,13 @@ #define DISPLAY_NAME_LEN 256 +enum NodeType +{ + RootNode, + ClassNode, + DeviceNode +}; + class CNode { protected: @@ -10,9 +17,11 @@ protected: 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 ); @@ -20,6 +29,7 @@ public: virtual bool SetupNode() = 0; + NodeType GetNodeType() { return m_NodeType; } LPGUID GetClassGuid() { return &m_ClassGuid; } LPWSTR GetDisplayName() { return m_DisplayName; } INT GetClassImage() { return m_ClassImage; }