From 66bbc9e4c1f2d4b461020f393d7566d7e1804003 Mon Sep 17 00:00:00 2001 From: Ged Murphy Date: Wed, 17 Jun 2015 21:26:42 +0000 Subject: [PATCH] [DEVMGR] - 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 --- .../dll/win32/devmgr/devmgmt/ClassNode.cpp | 170 ++++++++ reactos/dll/win32/devmgr/devmgmt/ClassNode.h | 24 ++ .../dll/win32/devmgr/devmgmt/DeviceNode.cpp | 233 +++++++++++ reactos/dll/win32/devmgr/devmgmt/DeviceNode.h | 34 ++ .../dll/win32/devmgr/devmgmt/DeviceView.cpp | 103 +++-- reactos/dll/win32/devmgr/devmgmt/DeviceView.h | 11 +- .../dll/win32/devmgr/devmgmt/MainWindow.cpp | 7 + reactos/dll/win32/devmgr/devmgmt/Node.cpp | 392 +----------------- reactos/dll/win32/devmgr/devmgmt/Node.h | 52 +-- 9 files changed, 537 insertions(+), 489 deletions(-) create mode 100644 reactos/dll/win32/devmgr/devmgmt/ClassNode.cpp create mode 100644 reactos/dll/win32/devmgr/devmgmt/ClassNode.h create mode 100644 reactos/dll/win32/devmgr/devmgmt/DeviceNode.cpp create mode 100644 reactos/dll/win32/devmgr/devmgmt/DeviceNode.h diff --git a/reactos/dll/win32/devmgr/devmgmt/ClassNode.cpp b/reactos/dll/win32/devmgr/devmgmt/ClassNode.cpp new file mode 100644 index 00000000000..55fa95d41aa --- /dev/null +++ b/reactos/dll/win32/devmgr/devmgmt/ClassNode.cpp @@ -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 +* +*/ + +#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 index 00000000000..39db56b4d7f --- /dev/null +++ b/reactos/dll/win32/devmgr/devmgmt/ClassNode.h @@ -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 index 00000000000..000da6252cc --- /dev/null +++ b/reactos/dll/win32/devmgr/devmgmt/DeviceNode.cpp @@ -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 +* +*/ + +#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 index 00000000000..2b0ad42ba62 --- /dev/null +++ b/reactos/dll/win32/devmgr/devmgmt/DeviceNode.h @@ -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 +}; + diff --git a/reactos/dll/win32/devmgr/devmgmt/DeviceView.cpp b/reactos/dll/win32/devmgr/devmgmt/DeviceView.cpp index f0c3c2d07d0..03ef16191a0 100644 --- a/reactos/dll/win32/devmgr/devmgmt/DeviceView.cpp +++ b/reactos/dll/win32/devmgr/devmgmt/DeviceView.cpp @@ -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 -* -*/ + * 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 + */ + #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(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(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(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(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(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(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); diff --git a/reactos/dll/win32/devmgr/devmgmt/DeviceView.h b/reactos/dll/win32/devmgr/devmgmt/DeviceView.h index 9b41308798c..fd0159ca178 100644 --- a/reactos/dll/win32/devmgr/devmgmt/DeviceView.h +++ b/reactos/dll/win32/devmgr/devmgmt/DeviceView.h @@ -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 m_ClassNodeList; - CAtlList m_DeviceNodeList; + CAtlList m_ClassNodeList; + CAtlList 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(); }; diff --git a/reactos/dll/win32/devmgr/devmgmt/MainWindow.cpp b/reactos/dll/win32/devmgr/devmgmt/MainWindow.cpp index 8b3242aba4d..59e28be922f 100644 --- a/reactos/dll/win32/devmgr/devmgmt/MainWindow.cpp +++ b/reactos/dll/win32/devmgr/devmgmt/MainWindow.cpp @@ -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); diff --git a/reactos/dll/win32/devmgr/devmgmt/Node.cpp b/reactos/dll/win32/devmgr/devmgmt/Node.cpp index 94f7732f22e..be54a0b087a 100644 --- a/reactos/dll/win32/devmgr/devmgmt/Node.cpp +++ b/reactos/dll/win32/devmgr/devmgmt/Node.cpp @@ -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; -} diff --git a/reactos/dll/win32/devmgr/devmgmt/Node.h b/reactos/dll/win32/devmgr/devmgmt/Node.h index 2a858bbd409..5374863d23f 100644 --- a/reactos/dll/win32/devmgr/devmgmt/Node.h +++ b/reactos/dll/win32/devmgr/devmgmt/Node.h @@ -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 - ); };