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