- 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
This commit is contained in:
Ged Murphy 2015-06-17 21:26:42 +00:00
parent a29eac1548
commit 66bbc9e4c1
9 changed files with 537 additions and 489 deletions

View file

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

View file

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

View file

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

View file

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

View 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"
@ -13,10 +13,11 @@
#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);

View 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();
};

View 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);

View file

@ -14,34 +14,12 @@
/* 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;
}

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