- 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
This commit is contained in:
Ged Murphy 2015-07-03 06:56:58 +00:00
parent 5c8a9ffd29
commit 27e12f2db6
7 changed files with 142 additions and 39 deletions

View file

@ -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));
}

View file

@ -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

View file

@ -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,

View file

@ -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<CDeviceNode *>(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<CNode *>(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<CNode *>(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
{

View file

@ -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

View file

@ -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)

View file

@ -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; }