1c2c66affSColin Finck /* 2c2c66affSColin Finck * PROJECT: ReactOS Device Manager 3c2c66affSColin Finck * LICENSE: GPL - See COPYING in the top level directory 4c2c66affSColin Finck * FILE: dll/win32/devmgr/devmgmt/DeviceView.cpp 5c2c66affSColin Finck * PURPOSE: Implements the tree view which contains the devices 6c2c66affSColin Finck * COPYRIGHT: Copyright 2015 Ged Murphy <gedmurphy@reactos.org> 7c2c66affSColin Finck */ 8c2c66affSColin Finck 9c2c66affSColin Finck 10c2c66affSColin Finck 11c2c66affSColin Finck #include "precomp.h" 12c2c66affSColin Finck #include "devmgmt.h" 13c2c66affSColin Finck #include "DeviceView.h" 14c2c66affSColin Finck 15c2c66affSColin Finck 16c2c66affSColin Finck // DATA ********************************************/ 17c2c66affSColin Finck 18c2c66affSColin Finck #define CLASS_NAME_LEN 256 19c2c66affSColin Finck #define CLASS_DESC_LEN 256 20c2c66affSColin Finck #define ROOT_NAME_SIZE MAX_COMPUTERNAME_LENGTH + 1 21c2c66affSColin Finck 22c2c66affSColin Finck 23c2c66affSColin Finck typedef VOID(WINAPI *PADDHARDWAREWIZARD)(HWND hwnd, LPWSTR lpName); 24c2c66affSColin Finck 25c2c66affSColin Finck struct RefreshThreadData 26c2c66affSColin Finck { 27c2c66affSColin Finck CDeviceView *This; 28c2c66affSColin Finck BOOL ScanForChanges; 29c2c66affSColin Finck BOOL UpdateView; 30c2c66affSColin Finck }; 31c2c66affSColin Finck 32c2c66affSColin Finck 33c2c66affSColin Finck // PUBLIC METHODS ************************************/ 34c2c66affSColin Finck 35c2c66affSColin Finck CDeviceView::CDeviceView( 36c2c66affSColin Finck HWND hMainWnd 37c2c66affSColin Finck ) : 38c2c66affSColin Finck m_hMainWnd(hMainWnd), 39c2c66affSColin Finck m_hTreeView(NULL), 40c2c66affSColin Finck m_hPropertyDialog(NULL), 41c2c66affSColin Finck m_hMenu(NULL), 42c2c66affSColin Finck m_ViewType(DevicesByType), 43c2c66affSColin Finck m_ShowHidden(false), 44c2c66affSColin Finck m_RootNode(NULL) 45c2c66affSColin Finck { 46c2c66affSColin Finck ZeroMemory(&m_ImageListData, sizeof(SP_CLASSIMAGELIST_DATA)); 47c2c66affSColin Finck } 48c2c66affSColin Finck 49c2c66affSColin Finck CDeviceView::~CDeviceView(void) 50c2c66affSColin Finck { 51c2c66affSColin Finck } 52c2c66affSColin Finck 53c2c66affSColin Finck bool 54c2c66affSColin Finck CDeviceView::Initialize() 55c2c66affSColin Finck { 56c2c66affSColin Finck // Get the device image list 57c2c66affSColin Finck m_ImageListData.cbSize = sizeof(SP_CLASSIMAGELIST_DATA); 58c2c66affSColin Finck BOOL bSuccess = SetupDiGetClassImageList(&m_ImageListData); 59c2c66affSColin Finck if (bSuccess == FALSE) 60c2c66affSColin Finck return false; 61c2c66affSColin Finck 62c2c66affSColin Finck // Create the main treeview 63c2c66affSColin Finck m_hTreeView = CreateWindowExW(WS_EX_CLIENTEDGE, 64c2c66affSColin Finck WC_TREEVIEW, 65c2c66affSColin Finck NULL, 66c2c66affSColin Finck WS_CHILD | WS_VISIBLE | WS_BORDER | TVS_HASLINES | 67c2c66affSColin Finck TVS_HASBUTTONS | TVS_SHOWSELALWAYS | TVS_LINESATROOT, 68c2c66affSColin Finck 0, 0, 0, 0, 69c2c66affSColin Finck m_hMainWnd, 70c2c66affSColin Finck (HMENU)IDC_TREEVIEW, 71c2c66affSColin Finck g_hThisInstance, 72c2c66affSColin Finck NULL); 73c2c66affSColin Finck if (m_hTreeView) 74c2c66affSColin Finck { 75c2c66affSColin Finck // Set the image list against the treeview 76c2c66affSColin Finck (void)TreeView_SetImageList(m_hTreeView, 77c2c66affSColin Finck m_ImageListData.ImageList, 78c2c66affSColin Finck TVSIL_NORMAL); 79c2c66affSColin Finck 80c2c66affSColin Finck // Give the treeview arrows instead of +/- boxes (on Win7) 81c2c66affSColin Finck SetWindowTheme(m_hTreeView, L"explorer", NULL); 82c2c66affSColin Finck 83c2c66affSColin Finck // Create the root node 84c2c66affSColin Finck m_RootNode = new CRootNode(&m_ImageListData); 85c2c66affSColin Finck m_RootNode->SetupNode(); 86c2c66affSColin Finck } 87c2c66affSColin Finck 88c2c66affSColin Finck 89c2c66affSColin Finck 90c2c66affSColin Finck return !!(m_hTreeView); 91c2c66affSColin Finck } 92c2c66affSColin Finck 93c2c66affSColin Finck bool 94c2c66affSColin Finck CDeviceView::Uninitialize() 95c2c66affSColin Finck { 96c2c66affSColin Finck EmptyDeviceView(); 97c2c66affSColin Finck 98c2c66affSColin Finck if (m_ImageListData.ImageList != NULL) 99c2c66affSColin Finck { 100c2c66affSColin Finck SetupDiDestroyClassImageList(&m_ImageListData); 101c2c66affSColin Finck ZeroMemory(&m_ImageListData, sizeof(SP_CLASSIMAGELIST_DATA)); 102c2c66affSColin Finck } 103c2c66affSColin Finck 104c2c66affSColin Finck return true; 105c2c66affSColin Finck } 106c2c66affSColin Finck 107c2c66affSColin Finck LRESULT 108c2c66affSColin Finck CDeviceView::OnSize( 109c2c66affSColin Finck _In_ int x, 110c2c66affSColin Finck _In_ int y, 111c2c66affSColin Finck _In_ int cx, 112c2c66affSColin Finck _In_ int cy 113c2c66affSColin Finck ) 114c2c66affSColin Finck { 115c2c66affSColin Finck // Resize the treeview 116c2c66affSColin Finck SetWindowPos(m_hTreeView, 117c2c66affSColin Finck NULL, 118c2c66affSColin Finck x, 119c2c66affSColin Finck y, 120c2c66affSColin Finck cx, 121c2c66affSColin Finck cy, 122c2c66affSColin Finck SWP_NOZORDER); 123c2c66affSColin Finck 124c2c66affSColin Finck return 0; 125c2c66affSColin Finck } 126c2c66affSColin Finck 127c2c66affSColin Finck LRESULT 128c2c66affSColin Finck CDeviceView::OnRightClick( 129c2c66affSColin Finck _In_ LPNMHDR NmHdr 130c2c66affSColin Finck ) 131c2c66affSColin Finck { 132c2c66affSColin Finck TVHITTESTINFO hitInfo; 133c2c66affSColin Finck HTREEITEM hItem; 134c2c66affSColin Finck 135c2c66affSColin Finck GetCursorPos(&hitInfo.pt); 136c2c66affSColin Finck ScreenToClient(m_hTreeView, &hitInfo.pt); 137c2c66affSColin Finck 138c2c66affSColin Finck hItem = TreeView_HitTest(m_hTreeView, &hitInfo); 139c2c66affSColin Finck if (hItem != NULL && (hitInfo.flags & (TVHT_ONITEM | TVHT_ONITEMICON))) 140c2c66affSColin Finck { 141c2c66affSColin Finck TreeView_SelectItem(m_hTreeView, hItem); 142c2c66affSColin Finck } 143c2c66affSColin Finck 144c2c66affSColin Finck return 0; 145c2c66affSColin Finck } 146c2c66affSColin Finck 147c2c66affSColin Finck LRESULT 148c2c66affSColin Finck CDeviceView::OnContextMenu( 149c2c66affSColin Finck _In_ LPARAM lParam 150c2c66affSColin Finck ) 151c2c66affSColin Finck { 152c2c66affSColin Finck HTREEITEM hSelected = TreeView_GetSelection(m_hTreeView); 153c2c66affSColin Finck 154c2c66affSColin Finck RECT rc; 155c2c66affSColin Finck if (TreeView_GetItemRect(m_hTreeView, 156c2c66affSColin Finck hSelected, 157c2c66affSColin Finck &rc, 158c2c66affSColin Finck TRUE)) 159c2c66affSColin Finck { 160c2c66affSColin Finck POINT pt; 161c2c66affSColin Finck if (GetCursorPos(&pt) && 162c2c66affSColin Finck ScreenToClient(m_hTreeView, &pt) && 163c2c66affSColin Finck PtInRect(&rc, pt)) 164c2c66affSColin Finck { 165c2c66affSColin Finck CNode *Node = GetSelectedNode(); 166c2c66affSColin Finck if (Node) 167c2c66affSColin Finck { 168c2c66affSColin Finck // Create the context menu 169c2c66affSColin Finck HMENU hContextMenu = CreatePopupMenu(); 170c2c66affSColin Finck 171c2c66affSColin Finck // Add the actions for this node 172c2c66affSColin Finck BuildActionMenuForNode(hContextMenu, Node, false); 173c2c66affSColin Finck 174c2c66affSColin Finck INT xPos = GET_X_LPARAM(lParam); 175c2c66affSColin Finck INT yPos = GET_Y_LPARAM(lParam); 176c2c66affSColin Finck 177c2c66affSColin Finck // Display the menu 178c2c66affSColin Finck TrackPopupMenuEx(hContextMenu, 179c2c66affSColin Finck TPM_RIGHTBUTTON, 180c2c66affSColin Finck xPos, 181c2c66affSColin Finck yPos, 182c2c66affSColin Finck m_hMainWnd, 183c2c66affSColin Finck NULL); 184c2c66affSColin Finck 185c2c66affSColin Finck DestroyMenu(hContextMenu); 186c2c66affSColin Finck } 187c2c66affSColin Finck } 188c2c66affSColin Finck } 189c2c66affSColin Finck 190c2c66affSColin Finck return 0; 191c2c66affSColin Finck } 192c2c66affSColin Finck 193c2c66affSColin Finck 194c2c66affSColin Finck void 195c2c66affSColin Finck CDeviceView::Refresh( 196c2c66affSColin Finck _In_ ViewType Type, 197c2c66affSColin Finck _In_ bool ScanForChanges, 198c2c66affSColin Finck _In_ bool UpdateView 199c2c66affSColin Finck ) 200c2c66affSColin Finck { 201c2c66affSColin Finck // Enum devices on a separate thread to keep the gui responsive 202c2c66affSColin Finck 203c2c66affSColin Finck m_ViewType = Type; 204c2c66affSColin Finck 205c2c66affSColin Finck RefreshThreadData *ThreadData; 206c2c66affSColin Finck ThreadData = new RefreshThreadData; 207c2c66affSColin Finck ThreadData->This = this; 208c2c66affSColin Finck ThreadData->ScanForChanges = ScanForChanges; 209c2c66affSColin Finck ThreadData->UpdateView = UpdateView; 210c2c66affSColin Finck 211c2c66affSColin Finck HANDLE hThread; 212c2c66affSColin Finck hThread = (HANDLE)_beginthreadex(NULL, 213c2c66affSColin Finck 0, 214c2c66affSColin Finck RefreshThread, 215c2c66affSColin Finck ThreadData, 216c2c66affSColin Finck 0, 217c2c66affSColin Finck NULL); 218c2c66affSColin Finck if (hThread) CloseHandle(hThread); 219c2c66affSColin Finck } 220c2c66affSColin Finck 221c2c66affSColin Finck LRESULT 222c2c66affSColin Finck CDeviceView::OnAction( 223c2c66affSColin Finck _In_ UINT Action 224c2c66affSColin Finck ) 225c2c66affSColin Finck { 226c2c66affSColin Finck switch (Action) 227c2c66affSColin Finck { 228*61198994SEric Kohl case IDM_PROPERTIES: 229c2c66affSColin Finck { 230c2c66affSColin Finck DisplayPropertySheet(); 231c2c66affSColin Finck break; 232c2c66affSColin Finck } 233c2c66affSColin Finck 234*61198994SEric Kohl case IDM_SCAN_HARDWARE: 235c2c66affSColin Finck { 236c2c66affSColin Finck Refresh(GetCurrentView(), 237c2c66affSColin Finck true, 238c2c66affSColin Finck true); 239c2c66affSColin Finck break; 240c2c66affSColin Finck } 241c2c66affSColin Finck 242*61198994SEric Kohl case IDM_ENABLE_DRV: 243c2c66affSColin Finck { 244c2c66affSColin Finck bool NeedsReboot; 245c2c66affSColin Finck if (EnableSelectedDevice(true, NeedsReboot) && 246c2c66affSColin Finck NeedsReboot) 247c2c66affSColin Finck { 248c2c66affSColin Finck MessageBox(m_hMainWnd, L"Rebooting", L"Enable", MB_OK); 249c2c66affSColin Finck } 250c2c66affSColin Finck break; 251c2c66affSColin Finck } 252c2c66affSColin Finck 253*61198994SEric Kohl case IDM_DISABLE_DRV: 254c2c66affSColin Finck { 255c2c66affSColin Finck bool NeedsReboot; 256c2c66affSColin Finck EnableSelectedDevice(false, NeedsReboot); 257c2c66affSColin Finck break; 258c2c66affSColin Finck } 259c2c66affSColin Finck 260*61198994SEric Kohl case IDM_UPDATE_DRV: 261c2c66affSColin Finck { 262c2c66affSColin Finck bool NeedsReboot; 263c2c66affSColin Finck UpdateSelectedDevice(NeedsReboot); 264c2c66affSColin Finck break; 265c2c66affSColin Finck } 266c2c66affSColin Finck 267*61198994SEric Kohl case IDM_UNINSTALL_DRV: 268c2c66affSColin Finck { 269c2c66affSColin Finck UninstallSelectedDevice(); 270c2c66affSColin Finck break; 271c2c66affSColin Finck } 272c2c66affSColin Finck 273*61198994SEric Kohl case IDM_ADD_HARDWARE: 274c2c66affSColin Finck { 275c2c66affSColin Finck RunAddHardwareWizard(); 276c2c66affSColin Finck break; 277c2c66affSColin Finck } 278c2c66affSColin Finck } 279c2c66affSColin Finck 280c2c66affSColin Finck return 0; 281c2c66affSColin Finck } 282c2c66affSColin Finck 283c2c66affSColin Finck void 284c2c66affSColin Finck CDeviceView::DisplayPropertySheet() 285c2c66affSColin Finck { 286c2c66affSColin Finck CNode *Node = GetSelectedNode(); 287c2c66affSColin Finck if (Node && Node->HasProperties()) 288c2c66affSColin Finck { 289c2c66affSColin Finck DevicePropertiesExW(m_hTreeView, 290c2c66affSColin Finck NULL, 291c2c66affSColin Finck Node->GetDeviceId(), 292c2c66affSColin Finck 1,//DPF_EXTENDED, 293c2c66affSColin Finck FALSE); 294c2c66affSColin Finck } 295c2c66affSColin Finck } 296c2c66affSColin Finck 297c2c66affSColin Finck void 298c2c66affSColin Finck CDeviceView::SetFocus() 299c2c66affSColin Finck { 300c2c66affSColin Finck ::SetFocus(m_hTreeView); 301c2c66affSColin Finck } 302c2c66affSColin Finck 303c2c66affSColin Finck bool 304c2c66affSColin Finck CDeviceView::CreateActionMenu( 305c2c66affSColin Finck _In_ HMENU OwnerMenu, 306c2c66affSColin Finck _In_ bool MainMenu 307c2c66affSColin Finck ) 308c2c66affSColin Finck { 309c2c66affSColin Finck CNode *Node = GetSelectedNode(); 310c2c66affSColin Finck if (Node) 311c2c66affSColin Finck { 312c2c66affSColin Finck BuildActionMenuForNode(OwnerMenu, Node, MainMenu); 313c2c66affSColin Finck return true; 314c2c66affSColin Finck } 315c2c66affSColin Finck 316c2c66affSColin Finck return false; 317c2c66affSColin Finck } 318c2c66affSColin Finck 319c2c66affSColin Finck CNode* 320c2c66affSColin Finck CDeviceView::GetSelectedNode() 321c2c66affSColin Finck { 322c2c66affSColin Finck TV_ITEM TvItem; 323c2c66affSColin Finck TvItem.hItem = TreeView_GetSelection(m_hTreeView); 324c2c66affSColin Finck return GetNode(&TvItem); 325c2c66affSColin Finck } 326c2c66affSColin Finck 327c2c66affSColin Finck 328c2c66affSColin Finck 329c2c66affSColin Finck // PRIVATE METHODS *******************************************/ 330c2c66affSColin Finck 331c2c66affSColin Finck bool 332c2c66affSColin Finck CDeviceView::AddRootDevice() 333c2c66affSColin Finck { 334c2c66affSColin Finck m_hTreeRoot = InsertIntoTreeView(NULL, m_RootNode); 335c2c66affSColin Finck return (m_hTreeRoot != NULL); 336c2c66affSColin Finck } 337c2c66affSColin Finck 338c2c66affSColin Finck bool 339c2c66affSColin Finck CDeviceView::GetNextClass( 340c2c66affSColin Finck _In_ ULONG ClassIndex, 341c2c66affSColin Finck _Out_ LPGUID ClassGuid, 342c2c66affSColin Finck _Out_ HDEVINFO *hDevInfo 343c2c66affSColin Finck ) 344c2c66affSColin Finck { 345c2c66affSColin Finck CONFIGRET cr; 346c2c66affSColin Finck 347c2c66affSColin Finck // Get the next class in the list 348c2c66affSColin Finck cr = CM_Enumerate_Classes(ClassIndex, 349c2c66affSColin Finck ClassGuid, 350c2c66affSColin Finck 0); 351c2c66affSColin Finck if (cr != CR_SUCCESS) 352c2c66affSColin Finck return false; 353c2c66affSColin Finck 354c2c66affSColin Finck // Check if this is the unknown class 355c2c66affSColin Finck if (IsEqualGUID(*ClassGuid, GUID_DEVCLASS_UNKNOWN)) 356c2c66affSColin Finck { 357c2c66affSColin Finck // Get device info for all devices 358c2c66affSColin Finck *hDevInfo = SetupDiGetClassDevsW(NULL, 359c2c66affSColin Finck NULL, 360c2c66affSColin Finck NULL, 361c2c66affSColin Finck DIGCF_ALLCLASSES); 362c2c66affSColin Finck } 363c2c66affSColin Finck else 364c2c66affSColin Finck { 365c2c66affSColin Finck // We only want the devices for this class 366c2c66affSColin Finck *hDevInfo = SetupDiGetClassDevsW(ClassGuid, 367c2c66affSColin Finck NULL, 368c2c66affSColin Finck NULL, 369c2c66affSColin Finck DIGCF_PRESENT); 370c2c66affSColin Finck } 371c2c66affSColin Finck 372c2c66affSColin Finck return (hDevInfo != INVALID_HANDLE_VALUE); 373c2c66affSColin Finck } 374c2c66affSColin Finck 375c2c66affSColin Finck unsigned int __stdcall CDeviceView::RefreshThread(void *Param) 376c2c66affSColin Finck { 377c2c66affSColin Finck RefreshThreadData *ThreadData = (RefreshThreadData *)Param; 378c2c66affSColin Finck CDeviceView *This = ThreadData->This; 379c2c66affSColin Finck 380c2c66affSColin Finck // Get a copy of the currently selected node 381c2c66affSColin Finck CNode *LastSelectedNode = This->GetSelectedNode(); 382c2c66affSColin Finck if (LastSelectedNode == nullptr || (LastSelectedNode->GetNodeType() == RootNode)) 383c2c66affSColin Finck { 384c2c66affSColin Finck LastSelectedNode = new CRootNode(*This->m_RootNode); 385c2c66affSColin Finck } 386c2c66affSColin Finck else if (LastSelectedNode->GetNodeType() == ClassNode) 387c2c66affSColin Finck { 388c2c66affSColin Finck LastSelectedNode = new CClassNode(*dynamic_cast<CClassNode *>(LastSelectedNode)); 389c2c66affSColin Finck } 390c2c66affSColin Finck else if (LastSelectedNode->GetNodeType() == DeviceNode) 391c2c66affSColin Finck { 392c2c66affSColin Finck LastSelectedNode = new CDeviceNode(*dynamic_cast<CDeviceNode *>(LastSelectedNode)); 393c2c66affSColin Finck } 394c2c66affSColin Finck 395c2c66affSColin Finck // Empty the treeview 396c2c66affSColin Finck This->EmptyDeviceView(); 397c2c66affSColin Finck 398c2c66affSColin Finck // Re-add the root node to the tree 399c2c66affSColin Finck if (This->AddRootDevice() == false) 400c2c66affSColin Finck return 0; 401c2c66affSColin Finck 402c2c66affSColin Finck // Refresh the devices only if requested 403c2c66affSColin Finck if (ThreadData->ScanForChanges) 404c2c66affSColin Finck { 405c2c66affSColin Finck This->RefreshDeviceList(); 406c2c66affSColin Finck } 407c2c66affSColin Finck 408c2c66affSColin Finck // display the type of view the user wants 409c2c66affSColin Finck switch (This->m_ViewType) 410c2c66affSColin Finck { 411c2c66affSColin Finck case DevicesByType: 412c2c66affSColin Finck (void)This->ListDevicesByType(); 413c2c66affSColin Finck break; 414c2c66affSColin Finck 415c2c66affSColin Finck case DevicesByConnection: 416c2c66affSColin Finck (VOID)This->ListDevicesByConnection(); 417c2c66affSColin Finck break; 418c2c66affSColin Finck 419c2c66affSColin Finck case ResourcesByType: 420c2c66affSColin Finck break; 421c2c66affSColin Finck 422c2c66affSColin Finck case ResourcesByConnection: 423c2c66affSColin Finck break; 424c2c66affSColin Finck } 425c2c66affSColin Finck 426c2c66affSColin Finck This->SelectNode(LastSelectedNode); 427c2c66affSColin Finck 428c2c66affSColin Finck delete ThreadData; 429c2c66affSColin Finck 430c2c66affSColin Finck return 0; 431c2c66affSColin Finck } 432c2c66affSColin Finck 433c2c66affSColin Finck 434c2c66affSColin Finck bool 435c2c66affSColin Finck CDeviceView::ListDevicesByType() 436c2c66affSColin Finck { 437c2c66affSColin Finck CClassNode *ClassNode; 438c2c66affSColin Finck CDeviceNode *DeviceNode; 439c2c66affSColin Finck HDEVINFO hDevInfo; 440c2c66affSColin Finck HTREEITEM hTreeItem = NULL; 441c2c66affSColin Finck GUID ClassGuid; 442c2c66affSColin Finck INT ClassIndex; 443c2c66affSColin Finck BOOL bClassSuccess, bSuccess; 444c2c66affSColin Finck 445c2c66affSColin Finck ClassIndex = 0; 446c2c66affSColin Finck do 447c2c66affSColin Finck { 448c2c66affSColin Finck // Loop through all the device classes 449c2c66affSColin Finck bClassSuccess = GetNextClass(ClassIndex, &ClassGuid, &hDevInfo); 450c2c66affSColin Finck if (bClassSuccess) 451c2c66affSColin Finck { 452c2c66affSColin Finck bool bClassUnknown = false; 453c2c66affSColin Finck bool AddedParent = false; 454c2c66affSColin Finck INT DeviceIndex = 0; 455c2c66affSColin Finck bool MoreItems = false; 456c2c66affSColin Finck 457c2c66affSColin Finck // Get the cached class node 458c2c66affSColin Finck ClassNode = GetClassNode(&ClassGuid); 459c2c66affSColin Finck if (ClassNode == nullptr) 460c2c66affSColin Finck { 461c2c66affSColin Finck ATLASSERT(FALSE); 462c2c66affSColin Finck ClassIndex++; 463c2c66affSColin Finck continue; 464c2c66affSColin Finck } 465c2c66affSColin Finck 466c2c66affSColin Finck // Set a flag is this is the (special case) unknown class 467c2c66affSColin Finck if (IsEqualGUID(ClassGuid, GUID_DEVCLASS_UNKNOWN)) 468c2c66affSColin Finck bClassUnknown = true; 469c2c66affSColin Finck 470c2c66affSColin Finck // Check if this is a hidden class 471c2c66affSColin Finck if (IsEqualGUID(ClassGuid, GUID_DEVCLASS_LEGACYDRIVER) || 472c2c66affSColin Finck IsEqualGUID(ClassGuid, GUID_DEVCLASS_VOLUME)) 473c2c66affSColin Finck { 474c2c66affSColin Finck // Ignore this device if we aren't displaying hidden devices 475c2c66affSColin Finck if (m_ShowHidden == FALSE) 476c2c66affSColin Finck { 477c2c66affSColin Finck ClassIndex++; 478c2c66affSColin Finck continue; 479c2c66affSColin Finck } 480c2c66affSColin Finck } 481c2c66affSColin Finck 482c2c66affSColin Finck do 483c2c66affSColin Finck { 484c2c66affSColin Finck // Get a handle to all the devices in this class 485c2c66affSColin Finck SP_DEVINFO_DATA DeviceInfoData; 486c2c66affSColin Finck ZeroMemory(&DeviceInfoData, sizeof(SP_DEVINFO_DATA)); 487c2c66affSColin Finck DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); 488c2c66affSColin Finck bSuccess = SetupDiEnumDeviceInfo(hDevInfo, 489c2c66affSColin Finck DeviceIndex, 490c2c66affSColin Finck &DeviceInfoData); 491c2c66affSColin Finck if (bSuccess == FALSE && GetLastError() == ERROR_NO_MORE_ITEMS) 492c2c66affSColin Finck MoreItems = false; 493c2c66affSColin Finck 494c2c66affSColin Finck if (bSuccess) 495c2c66affSColin Finck { 496c2c66affSColin Finck MoreItems = true; 497c2c66affSColin Finck 498c2c66affSColin Finck // The unknown class handle contains all devices on the system, 499c2c66affSColin Finck // and we're just looking for the ones with a null GUID 500c2c66affSColin Finck if (bClassUnknown) 501c2c66affSColin Finck { 502c2c66affSColin Finck if (IsEqualGUID(DeviceInfoData.ClassGuid, GUID_NULL) == FALSE) 503c2c66affSColin Finck { 504c2c66affSColin Finck // This is a known device, we aren't interested in it 505c2c66affSColin Finck DeviceIndex++; 506c2c66affSColin Finck continue; 507c2c66affSColin Finck } 508c2c66affSColin Finck } 509c2c66affSColin Finck 510c2c66affSColin Finck // Get the cached device node 511c2c66affSColin Finck DeviceNode = GetDeviceNode(DeviceInfoData.DevInst); 512c2c66affSColin Finck if (DeviceNode == nullptr) 513c2c66affSColin Finck { 514c2c66affSColin Finck ATLASSERT(bClassUnknown == true); 515c2c66affSColin Finck DeviceIndex++; 516c2c66affSColin Finck continue; 517c2c66affSColin Finck } 518c2c66affSColin Finck 519c2c66affSColin Finck // Check if this is a hidden device 520c2c66affSColin Finck if (DeviceNode->IsHidden()) 521c2c66affSColin Finck { 522c2c66affSColin Finck // Ignore this device if we aren't displaying hidden devices 523c2c66affSColin Finck if (m_ShowHidden == FALSE) 524c2c66affSColin Finck { 525c2c66affSColin Finck DeviceIndex++; 526c2c66affSColin Finck continue; 527c2c66affSColin Finck } 528c2c66affSColin Finck } 529c2c66affSColin Finck 530c2c66affSColin Finck // We have a device, we need to add the parent if it hasn't yet been added 531c2c66affSColin Finck if (AddedParent == false) 532c2c66affSColin Finck { 533c2c66affSColin Finck // Insert the new class under the root item 534c2c66affSColin Finck hTreeItem = InsertIntoTreeView(m_hTreeRoot, 535c2c66affSColin Finck ClassNode); 536c2c66affSColin Finck AddedParent = true; 537c2c66affSColin Finck } 538c2c66affSColin Finck 539c2c66affSColin Finck // Add the device under the class item node 540c2c66affSColin Finck (void)InsertIntoTreeView(hTreeItem, DeviceNode); 541c2c66affSColin Finck 542c2c66affSColin Finck // Expand the class if it has a problem device 543c2c66affSColin Finck if (DeviceNode->HasProblem()) 544c2c66affSColin Finck { 545c2c66affSColin Finck (void)TreeView_Expand(m_hTreeView, 546c2c66affSColin Finck hTreeItem, 547c2c66affSColin Finck TVE_EXPAND); 548c2c66affSColin Finck } 549c2c66affSColin Finck } 550c2c66affSColin Finck 551c2c66affSColin Finck DeviceIndex++; 552c2c66affSColin Finck 553c2c66affSColin Finck } while (MoreItems); 554c2c66affSColin Finck 555c2c66affSColin Finck // If this class has devices, sort them alphabetically 556c2c66affSColin Finck if (AddedParent == true) 557c2c66affSColin Finck { 558c2c66affSColin Finck (void)TreeView_SortChildren(m_hTreeView, 559c2c66affSColin Finck hTreeItem, 560c2c66affSColin Finck 0); 561c2c66affSColin Finck } 562c2c66affSColin Finck } 563c2c66affSColin Finck 564c2c66affSColin Finck ClassIndex++; 565c2c66affSColin Finck 566c2c66affSColin Finck } while (bClassSuccess); 567c2c66affSColin Finck 568c2c66affSColin Finck // Sort the classes alphabetically 569c2c66affSColin Finck (void)TreeView_SortChildren(m_hTreeView, 570c2c66affSColin Finck m_hTreeRoot, 571c2c66affSColin Finck 0); 572c2c66affSColin Finck 573c2c66affSColin Finck // Expand the root item 574c2c66affSColin Finck (void)TreeView_Expand(m_hTreeView, 575c2c66affSColin Finck m_hTreeRoot, 576c2c66affSColin Finck TVE_EXPAND); 577c2c66affSColin Finck 578c2c66affSColin Finck // Pre-select the root item 579c2c66affSColin Finck (VOID)TreeView_SelectItem(m_hTreeView, 580c2c66affSColin Finck m_hTreeRoot); 581c2c66affSColin Finck 582c2c66affSColin Finck return 0; 583c2c66affSColin Finck } 584c2c66affSColin Finck 585c2c66affSColin Finck bool 586c2c66affSColin Finck CDeviceView::ListDevicesByConnection() 587c2c66affSColin Finck { 588c2c66affSColin Finck // Walk the device tree and add all the devices 589c2c66affSColin Finck (void)RecurseChildDevices(m_RootNode->GetDeviceInst(), m_hTreeRoot); 590c2c66affSColin Finck 591c2c66affSColin Finck // Expand the root item 592c2c66affSColin Finck (void)TreeView_Expand(m_hTreeView, 593c2c66affSColin Finck m_hTreeRoot, 594c2c66affSColin Finck TVE_EXPAND); 595c2c66affSColin Finck 596c2c66affSColin Finck return true; 597c2c66affSColin Finck } 598c2c66affSColin Finck 599c2c66affSColin Finck bool 600c2c66affSColin Finck CDeviceView::RecurseChildDevices( 601c2c66affSColin Finck _In_ DEVINST ParentDevice, 602c2c66affSColin Finck _In_ HTREEITEM hParentTreeItem 603c2c66affSColin Finck ) 604c2c66affSColin Finck { 605c2c66affSColin Finck HTREEITEM hDevItem = NULL; 606c2c66affSColin Finck DEVINST Device; 607c2c66affSColin Finck bool HasProblem = false; 608c2c66affSColin Finck bool bSuccess; 609c2c66affSColin Finck 610c2c66affSColin Finck // Check if the parent has any child devices 611c2c66affSColin Finck if (GetChildDevice(ParentDevice, &Device) == FALSE) 612c2c66affSColin Finck return true; 613c2c66affSColin Finck 614c2c66affSColin Finck // Get the cached device node 615c2c66affSColin Finck CDeviceNode *DeviceNode; 616c2c66affSColin Finck DeviceNode = dynamic_cast<CDeviceNode *>(GetDeviceNode(Device)); 617c2c66affSColin Finck if (DeviceNode == nullptr) 618c2c66affSColin Finck { 619c2c66affSColin Finck ATLASSERT(FALSE); 620c2c66affSColin Finck return false; 621c2c66affSColin Finck } 622c2c66affSColin Finck 623c2c66affSColin Finck // Don't show hidden devices if not requested 624c2c66affSColin Finck if ((m_ShowHidden == TRUE) || (!(DeviceNode->IsHidden()))) 625c2c66affSColin Finck { 626c2c66affSColin Finck // Add this device to the tree under its parent 627c2c66affSColin Finck hDevItem = InsertIntoTreeView(hParentTreeItem, 628c2c66affSColin Finck DeviceNode); 629c2c66affSColin Finck if (hDevItem) 630c2c66affSColin Finck { 631c2c66affSColin Finck // Check if this child has any children itself 632c2c66affSColin Finck if (!RecurseChildDevices(Device, hDevItem)) 633c2c66affSColin Finck HasProblem = true; 634c2c66affSColin Finck } 635c2c66affSColin Finck 636c2c66affSColin Finck if (DeviceNode->HasProblem()) 637c2c66affSColin Finck { 638c2c66affSColin Finck HasProblem = true; 639c2c66affSColin Finck } 640c2c66affSColin Finck } 641c2c66affSColin Finck 642c2c66affSColin Finck 643c2c66affSColin Finck // Check for siblings 644c2c66affSColin Finck for (;;) 645c2c66affSColin Finck { 646c2c66affSColin Finck // Check if the parent device has anything at the same level 647c2c66affSColin Finck bSuccess = GetSiblingDevice(Device, &Device); 648c2c66affSColin Finck if (bSuccess == FALSE) 649c2c66affSColin Finck break; 650c2c66affSColin Finck 651c2c66affSColin Finck DeviceNode = dynamic_cast<CDeviceNode *>(GetDeviceNode(Device)); 652c2c66affSColin Finck if (DeviceNode == nullptr) 653c2c66affSColin Finck { 654c2c66affSColin Finck ATLASSERT(FALSE); 655c2c66affSColin Finck } 656c2c66affSColin Finck 657c2c66affSColin Finck // Don't show hidden devices if not requested 658c2c66affSColin Finck if ((m_ShowHidden == TRUE) || (!(DeviceNode->IsHidden()))) 659c2c66affSColin Finck { 660c2c66affSColin Finck if (DeviceNode->HasProblem()) 661c2c66affSColin Finck { 662c2c66affSColin Finck HasProblem = true; 663c2c66affSColin Finck } 664c2c66affSColin Finck 665c2c66affSColin Finck // Add this device to the tree under its parent 666c2c66affSColin Finck hDevItem = InsertIntoTreeView(hParentTreeItem, 667c2c66affSColin Finck DeviceNode); 668c2c66affSColin Finck if (hDevItem) 669c2c66affSColin Finck { 670c2c66affSColin Finck // Check if this child has any children itself 671c2c66affSColin Finck if (!RecurseChildDevices(Device, hDevItem)) 672c2c66affSColin Finck HasProblem = true; 673c2c66affSColin Finck } 674c2c66affSColin Finck } 675c2c66affSColin Finck } 676c2c66affSColin Finck 677c2c66affSColin Finck (void)TreeView_SortChildren(m_hTreeView, 678c2c66affSColin Finck hParentTreeItem, 679c2c66affSColin Finck 0); 680c2c66affSColin Finck 681c2c66affSColin Finck // Expand the class if it has a problem device 682c2c66affSColin Finck if (HasProblem == true) 683c2c66affSColin Finck { 684c2c66affSColin Finck (void)TreeView_Expand(m_hTreeView, 685c2c66affSColin Finck hParentTreeItem, 686c2c66affSColin Finck TVE_EXPAND); 687c2c66affSColin Finck } 688c2c66affSColin Finck 689c2c66affSColin Finck // If there was a problem, expand the ancestors 690c2c66affSColin Finck if (HasProblem) 691c2c66affSColin Finck return false; 692c2c66affSColin Finck 693c2c66affSColin Finck return true; 694c2c66affSColin Finck } 695c2c66affSColin Finck 696c2c66affSColin Finck bool 697c2c66affSColin Finck CDeviceView::EnableSelectedDevice( 698c2c66affSColin Finck _In_ bool Enable, 699c2c66affSColin Finck _Out_ bool &NeedsReboot 700c2c66affSColin Finck ) 701c2c66affSColin Finck { 702c2c66affSColin Finck CDeviceNode *Node = dynamic_cast<CDeviceNode *>(GetSelectedNode()); 703c2c66affSColin Finck if (Node == nullptr) 704c2c66affSColin Finck return false; 705c2c66affSColin Finck 706c2c66affSColin Finck if (Enable == false) 707c2c66affSColin Finck { 708c2c66affSColin Finck CAtlStringW str; 709c2c66affSColin Finck if (str.LoadStringW(g_hThisInstance, IDS_CONFIRM_DISABLE)) 710c2c66affSColin Finck { 711c2c66affSColin Finck if (MessageBoxW(m_hMainWnd, 712c2c66affSColin Finck str, 713c2c66affSColin Finck Node->GetDisplayName(), 714c2c66affSColin Finck MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2) != IDYES) 715c2c66affSColin Finck { 716c2c66affSColin Finck return false; 717c2c66affSColin Finck } 718c2c66affSColin Finck } 719c2c66affSColin Finck } 720c2c66affSColin Finck 721c2c66affSColin Finck return Node->EnableDevice(Enable, NeedsReboot); 722c2c66affSColin Finck } 723c2c66affSColin Finck 724c2c66affSColin Finck bool 725c2c66affSColin Finck CDeviceView::UpdateSelectedDevice( 726c2c66affSColin Finck _Out_ bool &NeedsReboot 727c2c66affSColin Finck ) 728c2c66affSColin Finck { 729c2c66affSColin Finck CDeviceNode *Node = dynamic_cast<CDeviceNode *>(GetSelectedNode()); 730c2c66affSColin Finck if (Node == nullptr) 731c2c66affSColin Finck return false; 732c2c66affSColin Finck 733c2c66affSColin Finck DWORD dwReboot; 734c2c66affSColin Finck if (InstallDevInst(m_hMainWnd, Node->GetDeviceId(), TRUE, &dwReboot)) 735c2c66affSColin Finck { 736c2c66affSColin Finck NeedsReboot = false; 737c2c66affSColin Finck return true; 738c2c66affSColin Finck } 739c2c66affSColin Finck 740c2c66affSColin Finck return false; 741c2c66affSColin Finck } 742c2c66affSColin Finck 743c2c66affSColin Finck bool 744c2c66affSColin Finck CDeviceView::UninstallSelectedDevice( 745c2c66affSColin Finck ) 746c2c66affSColin Finck { 747c2c66affSColin Finck CDeviceNode *Node = dynamic_cast<CDeviceNode *>(GetSelectedNode()); 748c2c66affSColin Finck if (Node == nullptr) 749c2c66affSColin Finck return false; 750c2c66affSColin Finck 751c2c66affSColin Finck CAtlStringW str; 752c2c66affSColin Finck if (str.LoadStringW(g_hThisInstance, IDS_CONFIRM_UNINSTALL)) 753c2c66affSColin Finck { 754c2c66affSColin Finck if (MessageBoxW(m_hMainWnd, 755c2c66affSColin Finck str, 756c2c66affSColin Finck Node->GetDisplayName(), 757c2c66affSColin Finck MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2) != IDYES) 758c2c66affSColin Finck { 759c2c66affSColin Finck return false; 760c2c66affSColin Finck } 761c2c66affSColin Finck } 762c2c66affSColin Finck 763c2c66affSColin Finck return Node->UninstallDevice(); 764c2c66affSColin Finck } 765c2c66affSColin Finck 766c2c66affSColin Finck bool 767c2c66affSColin Finck CDeviceView::RunAddHardwareWizard() 768c2c66affSColin Finck { 769c2c66affSColin Finck PADDHARDWAREWIZARD pAddHardwareWizard; 770c2c66affSColin Finck HMODULE hModule; 771c2c66affSColin Finck 772c2c66affSColin Finck hModule = LoadLibraryW(L"hdwwiz.cpl"); 773c2c66affSColin Finck if (hModule == NULL) 774c2c66affSColin Finck return false; 775c2c66affSColin Finck 776c2c66affSColin Finck pAddHardwareWizard = (PADDHARDWAREWIZARD)GetProcAddress(hModule, 777c2c66affSColin Finck "AddHardwareWizard"); 778c2c66affSColin Finck if (pAddHardwareWizard == NULL) 779c2c66affSColin Finck { 780c2c66affSColin Finck FreeLibrary(hModule); 781c2c66affSColin Finck return false; 782c2c66affSColin Finck } 783c2c66affSColin Finck 784c2c66affSColin Finck pAddHardwareWizard(m_hMainWnd, NULL); 785c2c66affSColin Finck 786c2c66affSColin Finck FreeLibrary(hModule); 787c2c66affSColin Finck return true; 788c2c66affSColin Finck } 789c2c66affSColin Finck 790c2c66affSColin Finck bool 791c2c66affSColin Finck CDeviceView::GetChildDevice( 792c2c66affSColin Finck _In_ DEVINST ParentDevInst, 793c2c66affSColin Finck _Out_ PDEVINST DevInst 794c2c66affSColin Finck ) 795c2c66affSColin Finck { 796c2c66affSColin Finck CONFIGRET cr; 797c2c66affSColin Finck cr = CM_Get_Child(DevInst, 798c2c66affSColin Finck ParentDevInst, 799c2c66affSColin Finck 0); 800c2c66affSColin Finck return (cr == CR_SUCCESS); 801c2c66affSColin Finck } 802c2c66affSColin Finck 803c2c66affSColin Finck bool 804c2c66affSColin Finck CDeviceView::GetSiblingDevice( 805c2c66affSColin Finck _In_ DEVINST PrevDevice, 806c2c66affSColin Finck _Out_ PDEVINST DevInst 807c2c66affSColin Finck ) 808c2c66affSColin Finck { 809c2c66affSColin Finck CONFIGRET cr; 810c2c66affSColin Finck cr = CM_Get_Sibling(DevInst, 811c2c66affSColin Finck PrevDevice, 812c2c66affSColin Finck 0); 813c2c66affSColin Finck return (cr == CR_SUCCESS); 814c2c66affSColin Finck } 815c2c66affSColin Finck 816c2c66affSColin Finck HTREEITEM 817c2c66affSColin Finck CDeviceView::InsertIntoTreeView( 818c2c66affSColin Finck _In_opt_ HTREEITEM hParent, 819c2c66affSColin Finck _In_ CNode *Node 820c2c66affSColin Finck ) 821c2c66affSColin Finck { 822c2c66affSColin Finck LPWSTR lpLabel; 823c2c66affSColin Finck lpLabel = Node->GetDisplayName(); 824c2c66affSColin Finck 825c2c66affSColin Finck TV_ITEMW tvi; 826c2c66affSColin Finck TV_INSERTSTRUCT tvins; 827c2c66affSColin Finck ZeroMemory(&tvi, sizeof(tvi)); 828c2c66affSColin Finck ZeroMemory(&tvins, sizeof(tvins)); 829c2c66affSColin Finck 830c2c66affSColin Finck tvi.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE; 831c2c66affSColin Finck tvi.pszText = lpLabel; 832c2c66affSColin Finck tvi.cchTextMax = wcslen(lpLabel); 833c2c66affSColin Finck tvi.lParam = (LPARAM)Node; 834c2c66affSColin Finck tvi.iImage = Node->GetClassImage(); 835c2c66affSColin Finck tvi.iSelectedImage = Node->GetClassImage(); 836c2c66affSColin Finck 837c2c66affSColin Finck // try to cast it to a device node. This will only succeed if it's the correct type 838c2c66affSColin Finck CDeviceNode *DeviceNode = dynamic_cast<CDeviceNode *>(Node); 839c2c66affSColin Finck if (DeviceNode && DeviceNode->GetOverlayImage()) 840c2c66affSColin Finck { 841c2c66affSColin Finck tvi.mask |= TVIF_STATE; 842c2c66affSColin Finck tvi.stateMask = TVIS_OVERLAYMASK; 843c2c66affSColin Finck tvi.state = INDEXTOOVERLAYMASK(DeviceNode->GetOverlayImage()); 844c2c66affSColin Finck } 845c2c66affSColin Finck 846c2c66affSColin Finck tvins.item = tvi; 847c2c66affSColin Finck tvins.hParent = hParent; 848c2c66affSColin Finck 849c2c66affSColin Finck return TreeView_InsertItem(m_hTreeView, &tvins); 850c2c66affSColin Finck } 851c2c66affSColin Finck 852c2c66affSColin Finck void 853c2c66affSColin Finck CDeviceView::BuildActionMenuForNode( 854c2c66affSColin Finck _In_ HMENU OwnerMenu, 855c2c66affSColin Finck _In_ CNode *Node, 856c2c66affSColin Finck _In_ bool MainMenu 857c2c66affSColin Finck ) 858c2c66affSColin Finck { 859c2c66affSColin Finck // Create a separator structure 860c2c66affSColin Finck MENUITEMINFOW MenuSeparator = { 0 }; 861c2c66affSColin Finck MenuSeparator.cbSize = sizeof(MENUITEMINFOW); 862c2c66affSColin Finck MenuSeparator.fType = MFT_SEPARATOR; 863c2c66affSColin Finck 864c2c66affSColin Finck // Setup the 865c2c66affSColin Finck MENUITEMINFOW MenuItemInfo = { 0 }; 866c2c66affSColin Finck MenuItemInfo.cbSize = sizeof(MENUITEMINFOW); 867c2c66affSColin Finck MenuItemInfo.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA | MIIM_SUBMENU; 868c2c66affSColin Finck MenuItemInfo.fType = MFT_STRING; 869c2c66affSColin Finck 870c2c66affSColin Finck CAtlStringW String; 871c2c66affSColin Finck int i = 0; 872c2c66affSColin Finck 873c2c66affSColin Finck // Device nodes have extra data 874c2c66affSColin Finck if (Node->GetNodeType() == DeviceNode) 875c2c66affSColin Finck { 876c2c66affSColin Finck CDeviceNode *DeviceNode = dynamic_cast<CDeviceNode *>(Node); 877c2c66affSColin Finck 878c2c66affSColin Finck if (DeviceNode->CanUpdate()) 879c2c66affSColin Finck { 880c2c66affSColin Finck String.LoadStringW(g_hThisInstance, IDS_MENU_UPDATE); 881*61198994SEric Kohl MenuItemInfo.wID = IDM_UPDATE_DRV; 882c2c66affSColin Finck MenuItemInfo.dwTypeData = String.GetBuffer(); 883c2c66affSColin Finck InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo); 884c2c66affSColin Finck i++; 885c2c66affSColin Finck } 886c2c66affSColin Finck 887c2c66affSColin Finck if (DeviceNode->IsDisabled()) 888c2c66affSColin Finck { 889c2c66affSColin Finck String.LoadStringW(g_hThisInstance, IDS_MENU_ENABLE); 890*61198994SEric Kohl MenuItemInfo.wID = IDM_ENABLE_DRV; 891c2c66affSColin Finck MenuItemInfo.dwTypeData = String.GetBuffer(); 892c2c66affSColin Finck InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo); 893c2c66affSColin Finck i++; 894c2c66affSColin Finck } 895c2c66affSColin Finck 896c2c66affSColin Finck if (DeviceNode->CanDisable() && !DeviceNode->IsDisabled()) 897c2c66affSColin Finck { 898c2c66affSColin Finck String.LoadStringW(g_hThisInstance, IDS_MENU_DISABLE); 899*61198994SEric Kohl MenuItemInfo.wID = IDM_DISABLE_DRV; 900c2c66affSColin Finck MenuItemInfo.dwTypeData = String.GetBuffer(); 901c2c66affSColin Finck InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo); 902c2c66affSColin Finck i++; 903c2c66affSColin Finck } 904c2c66affSColin Finck 905c2c66affSColin Finck if (DeviceNode->CanUninstall()) 906c2c66affSColin Finck { 907c2c66affSColin Finck String.LoadStringW(g_hThisInstance, IDS_MENU_UNINSTALL); 908*61198994SEric Kohl MenuItemInfo.wID = IDM_UNINSTALL_DRV; 909c2c66affSColin Finck MenuItemInfo.dwTypeData = String.GetBuffer(); 910c2c66affSColin Finck InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo); 911c2c66affSColin Finck i++; 912c2c66affSColin Finck } 913c2c66affSColin Finck 914c2c66affSColin Finck InsertMenuItemW(OwnerMenu, i, TRUE, &MenuSeparator); 915c2c66affSColin Finck i++; 916c2c66affSColin Finck } 917c2c66affSColin Finck 918c2c66affSColin Finck // All nodes have the scan option 919c2c66affSColin Finck String.LoadStringW(g_hThisInstance, IDS_MENU_SCAN); 920*61198994SEric Kohl MenuItemInfo.wID = IDM_SCAN_HARDWARE; 921c2c66affSColin Finck MenuItemInfo.dwTypeData = String.GetBuffer(); 922c2c66affSColin Finck InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo); 923c2c66affSColin Finck i++; 924c2c66affSColin Finck 925c2c66affSColin Finck if ((Node->GetNodeType() == RootNode) || (MainMenu == true)) 926c2c66affSColin Finck { 927c2c66affSColin Finck String.LoadStringW(g_hThisInstance, IDS_MENU_ADD); 928*61198994SEric Kohl MenuItemInfo.wID = IDM_ADD_HARDWARE; 929c2c66affSColin Finck MenuItemInfo.dwTypeData = String.GetBuffer(); 930c2c66affSColin Finck InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo); 931c2c66affSColin Finck i++; 932c2c66affSColin Finck } 933c2c66affSColin Finck 934c2c66affSColin Finck if (Node->HasProperties()) 935c2c66affSColin Finck { 936c2c66affSColin Finck InsertMenuItemW(OwnerMenu, i, TRUE, &MenuSeparator); 937c2c66affSColin Finck i++; 938c2c66affSColin Finck 939c2c66affSColin Finck String.LoadStringW(g_hThisInstance, IDS_MENU_PROPERTIES); 940*61198994SEric Kohl MenuItemInfo.wID = IDM_PROPERTIES; 941c2c66affSColin Finck MenuItemInfo.dwTypeData = String.GetBuffer(); 942c2c66affSColin Finck InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo); 943c2c66affSColin Finck i++; 944c2c66affSColin Finck 945c2c66affSColin Finck SetMenuDefaultItem(OwnerMenu, IDC_PROPERTIES, FALSE); 946c2c66affSColin Finck } 947c2c66affSColin Finck } 948c2c66affSColin Finck 949c2c66affSColin Finck HTREEITEM 950c2c66affSColin Finck CDeviceView::RecurseFindDevice( 951c2c66affSColin Finck _In_ HTREEITEM hParentItem, 952c2c66affSColin Finck _In_ CNode *Node 953c2c66affSColin Finck ) 954c2c66affSColin Finck { 955c2c66affSColin Finck HTREEITEM FoundItem; 956c2c66affSColin Finck HTREEITEM hItem; 957c2c66affSColin Finck TVITEMW tvItem; 958c2c66affSColin Finck CNode *FoundNode; 959c2c66affSColin Finck 960c2c66affSColin Finck // Check if this node has any children 961c2c66affSColin Finck hItem = TreeView_GetChild(m_hTreeView, hParentItem); 962c2c66affSColin Finck if (hItem == NULL) 963c2c66affSColin Finck return NULL; 964c2c66affSColin Finck 965c2c66affSColin Finck // The lParam contains the node pointer data 966c2c66affSColin Finck tvItem.hItem = hItem; 967c2c66affSColin Finck tvItem.mask = TVIF_PARAM; 968c2c66affSColin Finck if (TreeView_GetItem(m_hTreeView, &tvItem) && 969c2c66affSColin Finck tvItem.lParam != NULL) 970c2c66affSColin Finck { 971c2c66affSColin Finck // check for a matching node 972c2c66affSColin Finck FoundNode = reinterpret_cast<CNode *>(tvItem.lParam); 973c2c66affSColin Finck if ((FoundNode->GetNodeType() == Node->GetNodeType()) && 974c2c66affSColin Finck (IsEqualGUID(*FoundNode->GetClassGuid(), *Node->GetClassGuid()))) 975c2c66affSColin Finck { 976c2c66affSColin Finck // check if this is a class node, or a device with matching ID's 977c2c66affSColin Finck if ((FoundNode->GetNodeType() == ClassNode) || 978c2c66affSColin Finck (wcscmp(FoundNode->GetDeviceId(), Node->GetDeviceId()) == 0)) 979c2c66affSColin Finck { 980c2c66affSColin Finck return hItem; 981c2c66affSColin Finck } 982c2c66affSColin Finck } 983c2c66affSColin Finck } 984c2c66affSColin Finck 985c2c66affSColin Finck // This node may have its own children 986c2c66affSColin Finck FoundItem = RecurseFindDevice(hItem, Node); 987c2c66affSColin Finck if (FoundItem) 988c2c66affSColin Finck return FoundItem; 989c2c66affSColin Finck 990c2c66affSColin Finck // Loop all the siblings 991c2c66affSColin Finck for (;;) 992c2c66affSColin Finck { 993c2c66affSColin Finck // Get the next item at this level 994c2c66affSColin Finck hItem = TreeView_GetNextSibling(m_hTreeView, hItem); 995c2c66affSColin Finck if (hItem == NULL) 996c2c66affSColin Finck break; 997c2c66affSColin Finck 998c2c66affSColin Finck // The lParam contains the node pointer data 999c2c66affSColin Finck tvItem.hItem = hItem; 1000c2c66affSColin Finck tvItem.mask = TVIF_PARAM; 1001c2c66affSColin Finck if (TreeView_GetItem(m_hTreeView, &tvItem)) 1002c2c66affSColin Finck { 1003c2c66affSColin Finck // check for a matching class 1004c2c66affSColin Finck FoundNode = reinterpret_cast<CNode *>(tvItem.lParam); 1005c2c66affSColin Finck if ((FoundNode->GetNodeType() == Node->GetNodeType()) && 1006c2c66affSColin Finck (IsEqualGUID(*FoundNode->GetClassGuid(), *Node->GetClassGuid()))) 1007c2c66affSColin Finck { 1008c2c66affSColin Finck // check if this is a class node, or a device with matching ID's 1009c2c66affSColin Finck if ((FoundNode->GetNodeType() == ClassNode) || 1010c2c66affSColin Finck (wcscmp(FoundNode->GetDeviceId(), Node->GetDeviceId()) == 0)) 1011c2c66affSColin Finck { 1012c2c66affSColin Finck return hItem; 1013c2c66affSColin Finck } 1014c2c66affSColin Finck } 1015c2c66affSColin Finck } 1016c2c66affSColin Finck 1017c2c66affSColin Finck // This node may have its own children 1018c2c66affSColin Finck FoundItem = RecurseFindDevice(hItem, Node); 1019c2c66affSColin Finck if (FoundItem) 1020c2c66affSColin Finck return FoundItem; 1021c2c66affSColin Finck } 1022c2c66affSColin Finck 1023c2c66affSColin Finck return hItem; 1024c2c66affSColin Finck } 1025c2c66affSColin Finck 1026c2c66affSColin Finck void 1027c2c66affSColin Finck CDeviceView::SelectNode( 1028c2c66affSColin Finck _In_ CNode *Node 1029c2c66affSColin Finck ) 1030c2c66affSColin Finck { 1031c2c66affSColin Finck HTREEITEM hRoot, hItem; 1032c2c66affSColin Finck 1033c2c66affSColin Finck // Check if there are any items in the tree 1034c2c66affSColin Finck hRoot = TreeView_GetRoot(m_hTreeView); 1035c2c66affSColin Finck if (hRoot == NULL) 1036c2c66affSColin Finck return; 1037c2c66affSColin Finck 1038c2c66affSColin Finck // If we don't want to set select a node, just select root 1039c2c66affSColin Finck if (Node == nullptr || Node->GetNodeType() == RootNode) 1040c2c66affSColin Finck { 1041c2c66affSColin Finck TreeView_SelectItem(m_hTreeView, hRoot); 1042c2c66affSColin Finck return; 1043c2c66affSColin Finck } 1044c2c66affSColin Finck 1045c2c66affSColin Finck // Scan the tree looking for the node we want 1046c2c66affSColin Finck hItem = RecurseFindDevice(hRoot, Node); 1047c2c66affSColin Finck if (hItem) 1048c2c66affSColin Finck { 1049c2c66affSColin Finck TreeView_SelectItem(m_hTreeView, hItem); 1050c2c66affSColin Finck } 1051c2c66affSColin Finck else 1052c2c66affSColin Finck { 1053c2c66affSColin Finck TreeView_SelectItem(m_hTreeView, hRoot); 1054c2c66affSColin Finck } 1055c2c66affSColin Finck } 1056c2c66affSColin Finck 1057c2c66affSColin Finck 1058c2c66affSColin Finck void 1059c2c66affSColin Finck CDeviceView::EmptyDeviceView() 1060c2c66affSColin Finck { 1061c2c66affSColin Finck (VOID)TreeView_DeleteAllItems(m_hTreeView); 1062c2c66affSColin Finck } 1063c2c66affSColin Finck 1064c2c66affSColin Finck 1065c2c66affSColin Finck CClassNode* 1066c2c66affSColin Finck CDeviceView::GetClassNode( 1067c2c66affSColin Finck _In_ LPGUID ClassGuid 1068c2c66affSColin Finck ) 1069c2c66affSColin Finck { 1070c2c66affSColin Finck POSITION Pos; 1071c2c66affSColin Finck CClassNode *Node = nullptr; 1072c2c66affSColin Finck 1073c2c66affSColin Finck Pos = m_ClassNodeList.GetHeadPosition(); 1074c2c66affSColin Finck if (Pos == NULL) 1075c2c66affSColin Finck return nullptr; 1076c2c66affSColin Finck 1077c2c66affSColin Finck do 1078c2c66affSColin Finck { 1079c2c66affSColin Finck Node = m_ClassNodeList.GetNext(Pos); 1080c2c66affSColin Finck if (IsEqualGUID(*Node->GetClassGuid(), *ClassGuid)) 1081c2c66affSColin Finck { 1082c2c66affSColin Finck ATLASSERT(Node->GetNodeType() == ClassNode); 1083c2c66affSColin Finck break; 1084c2c66affSColin Finck } 1085c2c66affSColin Finck 1086c2c66affSColin Finck Node = nullptr; 1087c2c66affSColin Finck 1088c2c66affSColin Finck } while (Pos != NULL); 1089c2c66affSColin Finck 1090c2c66affSColin Finck return Node; 1091c2c66affSColin Finck } 1092c2c66affSColin Finck 1093c2c66affSColin Finck CDeviceNode* 1094c2c66affSColin Finck CDeviceView::GetDeviceNode( 1095c2c66affSColin Finck _In_ DEVINST Device 1096c2c66affSColin Finck ) 1097c2c66affSColin Finck { 1098c2c66affSColin Finck POSITION Pos; 1099c2c66affSColin Finck CDeviceNode *Node = nullptr; 1100c2c66affSColin Finck 1101c2c66affSColin Finck Pos = m_DeviceNodeList.GetHeadPosition(); 1102c2c66affSColin Finck if (Pos == NULL) 1103c2c66affSColin Finck return nullptr; 1104c2c66affSColin Finck 1105c2c66affSColin Finck do 1106c2c66affSColin Finck { 1107c2c66affSColin Finck Node = m_DeviceNodeList.GetNext(Pos); 1108c2c66affSColin Finck if (Node->GetDeviceInst() == Device) 1109c2c66affSColin Finck { 1110c2c66affSColin Finck ATLASSERT(Node->GetNodeType() == DeviceNode); 1111c2c66affSColin Finck break; 1112c2c66affSColin Finck } 1113c2c66affSColin Finck 1114c2c66affSColin Finck Node = nullptr; 1115c2c66affSColin Finck 1116c2c66affSColin Finck } while (Pos != NULL); 1117c2c66affSColin Finck 1118c2c66affSColin Finck return Node; 1119c2c66affSColin Finck } 1120c2c66affSColin Finck 1121c2c66affSColin Finck CNode* CDeviceView::GetNode( 1122c2c66affSColin Finck _In_ LPTV_ITEMW TvItem 1123c2c66affSColin Finck ) 1124c2c66affSColin Finck { 1125c2c66affSColin Finck TvItem->mask = TVIF_PARAM; 1126c2c66affSColin Finck if (TreeView_GetItem(m_hTreeView, TvItem)) 1127c2c66affSColin Finck { 1128c2c66affSColin Finck return (CNode *)TvItem->lParam; 1129c2c66affSColin Finck } 1130c2c66affSColin Finck return nullptr; 1131c2c66affSColin Finck } 1132c2c66affSColin Finck 1133c2c66affSColin Finck void 1134c2c66affSColin Finck CDeviceView::EmptyLists() 1135c2c66affSColin Finck { 1136c2c66affSColin Finck CNode *Node; 1137c2c66affSColin Finck 1138c2c66affSColin Finck while (!m_ClassNodeList.IsEmpty()) 1139c2c66affSColin Finck { 1140c2c66affSColin Finck Node = m_ClassNodeList.RemoveTail(); 1141c2c66affSColin Finck delete Node; 1142c2c66affSColin Finck } 1143c2c66affSColin Finck 1144c2c66affSColin Finck while (!m_DeviceNodeList.IsEmpty()) 1145c2c66affSColin Finck { 1146c2c66affSColin Finck Node = m_DeviceNodeList.RemoveTail(); 1147c2c66affSColin Finck delete Node; 1148c2c66affSColin Finck } 1149c2c66affSColin Finck } 1150c2c66affSColin Finck 1151c2c66affSColin Finck bool 1152c2c66affSColin Finck CDeviceView::RefreshDeviceList() 1153c2c66affSColin Finck { 1154c2c66affSColin Finck GUID ClassGuid; 1155c2c66affSColin Finck CClassNode *ClassNode; 1156c2c66affSColin Finck CDeviceNode *DeviceNode; 1157c2c66affSColin Finck HDEVINFO hDevInfo; 1158c2c66affSColin Finck SP_DEVINFO_DATA DeviceInfoData; 1159c2c66affSColin Finck DWORD i; 1160c2c66affSColin Finck BOOL Success; 1161c2c66affSColin Finck 1162c2c66affSColin Finck ULONG ClassIndex = 0; 1163c2c66affSColin Finck 1164c2c66affSColin Finck EmptyLists(); 1165c2c66affSColin Finck 1166c2c66affSColin Finck if (m_RootNode) delete m_RootNode; 1167c2c66affSColin Finck m_RootNode = new CRootNode(&m_ImageListData); 1168c2c66affSColin Finck m_RootNode->SetupNode(); 1169c2c66affSColin Finck 1170c2c66affSColin Finck // Loop through all the classes 1171c2c66affSColin Finck do 1172c2c66affSColin Finck { 1173c2c66affSColin Finck Success = GetNextClass(ClassIndex, &ClassGuid, &hDevInfo); 1174c2c66affSColin Finck if (Success) 1175c2c66affSColin Finck { 1176c2c66affSColin Finck // Create a new class node and add it to the list 1177c2c66affSColin Finck ClassNode = new CClassNode(&ClassGuid, &m_ImageListData); 1178c2c66affSColin Finck if (ClassNode->SetupNode()) 1179c2c66affSColin Finck { 1180c2c66affSColin Finck m_ClassNodeList.AddTail(ClassNode); 1181c2c66affSColin Finck } 1182c2c66affSColin Finck 1183c2c66affSColin Finck SetupDiDestroyDeviceInfoList(hDevInfo); 1184c2c66affSColin Finck } 1185c2c66affSColin Finck ClassIndex++; 1186c2c66affSColin Finck } while (Success); 1187c2c66affSColin Finck 1188c2c66affSColin Finck // Get all the devices on the local machine 1189c2c66affSColin Finck hDevInfo = SetupDiGetClassDevsW(NULL, 1190c2c66affSColin Finck 0, 1191c2c66affSColin Finck 0, 1192c2c66affSColin Finck DIGCF_PRESENT | DIGCF_ALLCLASSES); 1193c2c66affSColin Finck if (hDevInfo == INVALID_HANDLE_VALUE) 1194c2c66affSColin Finck { 1195c2c66affSColin Finck return false; 1196c2c66affSColin Finck } 1197c2c66affSColin Finck 1198c2c66affSColin Finck // loop though all the devices 1199c2c66affSColin Finck DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); 1200c2c66affSColin Finck for (i = 0;; i++) 1201c2c66affSColin Finck { 1202c2c66affSColin Finck // Get the devinst for this device 1203c2c66affSColin Finck Success = SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); 1204c2c66affSColin Finck if (Success == FALSE) 1205c2c66affSColin Finck break; 1206c2c66affSColin Finck 1207c2c66affSColin Finck // create a new device node and add it to the list 1208c2c66affSColin Finck DeviceNode = new CDeviceNode(DeviceInfoData.DevInst, &m_ImageListData); 1209f9739601SEric Kohl /* FIXME: Start of Hack for CORE-5643 */ 1210f9739601SEric Kohl if (!DeviceNode->IsInstalled()) 1211f9739601SEric Kohl continue; 1212f9739601SEric Kohl /* FIXME: End of Hack for CORE-5643 */ 1213f9739601SEric Kohl 1214c2c66affSColin Finck if (DeviceNode->SetupNode()) 1215c2c66affSColin Finck { 1216c2c66affSColin Finck m_DeviceNodeList.AddTail(DeviceNode); 1217c2c66affSColin Finck } 1218c2c66affSColin Finck else 1219c2c66affSColin Finck { 1220c2c66affSColin Finck ATLASSERT(FALSE); 1221c2c66affSColin Finck } 1222c2c66affSColin Finck } 1223c2c66affSColin Finck 1224c2c66affSColin Finck SetupDiDestroyDeviceInfoList(hDevInfo); 1225c2c66affSColin Finck 1226c2c66affSColin Finck return TRUE; 1227c2c66affSColin Finck }