- 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_ LPGUID ClassGuid,
_In_ PSP_CLASSIMAGELIST_DATA ImageListData _In_ PSP_CLASSIMAGELIST_DATA ImageListData
) : ) :
CNode(ImageListData) CNode(ClassNode, ImageListData)
{ {
CopyMemory(&m_ClassGuid, ClassGuid, sizeof(GUID)); CopyMemory(&m_ClassGuid, ClassGuid, sizeof(GUID));
} }

View file

@ -16,7 +16,7 @@ CDeviceNode::CDeviceNode(
_In_opt_ DEVINST Device, _In_opt_ DEVINST Device,
_In_ PSP_CLASSIMAGELIST_DATA ImageListData _In_ PSP_CLASSIMAGELIST_DATA ImageListData
) : ) :
CNode(ImageListData), CNode(DeviceNode, ImageListData),
m_DevInst(Device), m_DevInst(Device),
m_hDevInfo(NULL), m_hDevInfo(NULL),
m_Status(0), m_Status(0),
@ -260,11 +260,12 @@ CDeviceNode::CanUninstall()
NULL); NULL);
if (cr == CR_SUCCESS) if (cr == CR_SUCCESS)
{ {
return ((m_Status & DN_DISABLEABLE) != 0 && if ((m_Status & DN_ROOT_ENUMERATED) != 0 &&
(m_Status & DN_ROOT_ENUMERATED) == 0); (m_Status & DN_DISABLEABLE) == 0)
return false;
} }
return false; return true;
} }
bool bool

View file

@ -27,10 +27,11 @@ public:
bool HasProblem(); bool HasProblem();
bool IsHidden(); bool IsHidden();
bool CanDisable(); bool CanDisable();
bool IsDisabled(); virtual bool IsDisabled();
bool IsStarted(); bool IsStarted();
bool IsInstalled(); bool IsInstalled();
bool CanUninstall(); bool CanUninstall();
virtual bool CanUpdate() { return true; } // unimplemented
bool EnableDevice( bool EnableDevice(
_In_ bool Enable, _In_ bool Enable,

View file

@ -49,7 +49,6 @@ CDeviceView::CDeviceView(
m_hTreeView(NULL), m_hTreeView(NULL),
m_hPropertyDialog(NULL), m_hPropertyDialog(NULL),
m_hMenu(NULL), m_hMenu(NULL),
m_hContextMenu(NULL),
m_ViewType(DevicesByType), m_ViewType(DevicesByType),
m_ShowHidden(FALSE), m_ShowHidden(FALSE),
m_RootClassImage(-1), m_RootClassImage(-1),
@ -92,9 +91,7 @@ CDeviceView::Initialize()
SetWindowTheme(m_hTreeView, L"explorer", NULL); 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); return !!(m_hTreeView);
} }
@ -110,8 +107,6 @@ CDeviceView::Uninitialize()
ZeroMemory(&m_ImageListData, sizeof(SP_CLASSIMAGELIST_DATA)); ZeroMemory(&m_ImageListData, sizeof(SP_CLASSIMAGELIST_DATA));
} }
DestroyMenu(m_hContextMenu);
return true; return true;
} }
@ -168,26 +163,14 @@ CDeviceView::OnContextMenu(
PtInRect(&rc, pt)) PtInRect(&rc, pt))
{ {
CNode *Node = GetSelectedNode();
if (Node && Node->HasProperties())
{
}
INT xPos = GET_X_LPARAM(lParam); INT xPos = GET_X_LPARAM(lParam);
INT yPos = GET_Y_LPARAM(lParam); INT yPos = GET_Y_LPARAM(lParam);
TrackPopupMenuEx(m_hContextMenu, CNode *Node = GetSelectedNode();
TPM_RIGHTBUTTON, if (Node)
xPos, {
yPos, BuildContextMenuForNode(Node, xPos, yPos);
m_hMainWnd, }
NULL);
} }
} }
@ -807,6 +790,100 @@ CDeviceView::InsertIntoTreeView(
return TreeView_InsertItem(m_hTreeView, &tvins); 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 HTREEITEM
CDeviceView::RecurseFindDevice( CDeviceView::RecurseFindDevice(
_In_ HTREEITEM hParentItem, _In_ HTREEITEM hParentItem,
@ -828,6 +905,7 @@ CDeviceView::RecurseFindDevice(
if (TreeView_GetItem(m_hTreeView, &tvItem) && if (TreeView_GetItem(m_hTreeView, &tvItem) &&
tvItem.lParam != NULL) tvItem.lParam != NULL)
{ {
// check for a matching deviceid
Node = reinterpret_cast<CNode *>(tvItem.lParam); Node = reinterpret_cast<CNode *>(tvItem.lParam);
if (Node->GetDeviceId() && if (Node->GetDeviceId() &&
(wcscmp(Node->GetDeviceId(), DeviceId) == 0)) (wcscmp(Node->GetDeviceId(), DeviceId) == 0))
@ -840,7 +918,7 @@ CDeviceView::RecurseFindDevice(
FoundItem = RecurseFindDevice(hItem, DeviceId); FoundItem = RecurseFindDevice(hItem, DeviceId);
if (FoundItem) return FoundItem; if (FoundItem) return FoundItem;
// Delete all the siblings // Loop all the siblings
for (;;) for (;;)
{ {
// Get the next item at this level // Get the next item at this level
@ -852,6 +930,7 @@ CDeviceView::RecurseFindDevice(
tvItem.mask = TVIF_PARAM; tvItem.mask = TVIF_PARAM;
if (TreeView_GetItem(m_hTreeView, &tvItem)) if (TreeView_GetItem(m_hTreeView, &tvItem))
{ {
// check for a matching deviceid
Node = reinterpret_cast<CNode *>(tvItem.lParam); Node = reinterpret_cast<CNode *>(tvItem.lParam);
if (Node->GetDeviceId() && if (Node->GetDeviceId() &&
wcscmp(Node->GetDeviceId(), DeviceId) == 0) wcscmp(Node->GetDeviceId(), DeviceId) == 0)
@ -879,14 +958,19 @@ CDeviceView::SelectNode(
hRoot = TreeView_GetRoot(m_hTreeView); hRoot = TreeView_GetRoot(m_hTreeView);
if (hRoot == NULL) return; 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); TreeView_SelectItem(m_hTreeView, hRoot);
if (hItem) return;
{ }
TreeView_SelectItem(m_hTreeView, hItem);
TreeView_Expand(m_hTreeView, hItem, TVM_EXPAND); // 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 else
{ {

View file

@ -20,7 +20,6 @@ class CDeviceView
HWND m_hTreeView; HWND m_hTreeView;
HWND m_hPropertyDialog; HWND m_hPropertyDialog;
HMENU m_hMenu; HMENU m_hMenu;
HMENU m_hContextMenu;
ViewType m_ViewType; ViewType m_ViewType;
HTREEITEM m_hTreeRoot; HTREEITEM m_hTreeRoot;
DEVINST m_RootDevInst; DEVINST m_RootDevInst;
@ -128,6 +127,12 @@ private:
_In_ CNode *Node _In_ CNode *Node
); );
void BuildContextMenuForNode(
_In_ CNode *Node,
_In_ INT xPos,
_In_ INT yPos
);
HTREEITEM RecurseFindDevice( HTREEITEM RecurseFindDevice(
_In_ HTREEITEM hParentItem, _In_ HTREEITEM hParentItem,
_In_ LPWSTR DeviceId _In_ LPWSTR DeviceId

View file

@ -14,7 +14,9 @@
/* PUBLIC METHODS *******************************************/ /* 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_ImageListData(ImageListData),
m_DeviceId(NULL), m_DeviceId(NULL),
m_ClassImage(0) m_ClassImage(0)

View file

@ -2,6 +2,13 @@
#define DISPLAY_NAME_LEN 256 #define DISPLAY_NAME_LEN 256
enum NodeType
{
RootNode,
ClassNode,
DeviceNode
};
class CNode class CNode
{ {
protected: protected:
@ -10,9 +17,11 @@ protected:
WCHAR m_DisplayName[DISPLAY_NAME_LEN]; WCHAR m_DisplayName[DISPLAY_NAME_LEN];
GUID m_ClassGuid; GUID m_ClassGuid;
INT m_ClassImage; INT m_ClassImage;
NodeType m_NodeType;
public: public:
CNode( CNode(
_In_ NodeType Type,
_In_ PSP_CLASSIMAGELIST_DATA ImageListData _In_ PSP_CLASSIMAGELIST_DATA ImageListData
); );
@ -20,6 +29,7 @@ public:
virtual bool SetupNode() = 0; virtual bool SetupNode() = 0;
NodeType GetNodeType() { return m_NodeType; }
LPGUID GetClassGuid() { return &m_ClassGuid; } LPGUID GetClassGuid() { return &m_ClassGuid; }
LPWSTR GetDisplayName() { return m_DisplayName; } LPWSTR GetDisplayName() { return m_DisplayName; }
INT GetClassImage() { return m_ClassImage; } INT GetClassImage() { return m_ClassImage; }