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 // Check if this is the unknown class 355 if (IsEqualGUID(*ClassGuid, GUID_DEVCLASS_UNKNOWN)) 356 { 357 // Get device info for all devices 358 *hDevInfo = SetupDiGetClassDevsW(NULL, 359 NULL, 360 NULL, 361 DIGCF_ALLCLASSES); 362 } 363 else 364 { 365 // We only want the devices for this class 366 *hDevInfo = SetupDiGetClassDevsW(ClassGuid, 367 NULL, 368 NULL, 369 DIGCF_PRESENT); 370 } 371 372 return (hDevInfo != INVALID_HANDLE_VALUE); 373 } 374 375 unsigned int __stdcall CDeviceView::RefreshThread(void *Param) 376 { 377 RefreshThreadData *ThreadData = (RefreshThreadData *)Param; 378 CDeviceView *This = ThreadData->This; 379 380 // Get a copy of the currently selected node 381 CNode *LastSelectedNode = This->GetSelectedNode(); 382 if (LastSelectedNode == nullptr || (LastSelectedNode->GetNodeType() == RootNode)) 383 { 384 LastSelectedNode = new CRootNode(*This->m_RootNode); 385 } 386 else if (LastSelectedNode->GetNodeType() == ClassNode) 387 { 388 LastSelectedNode = new CClassNode(*dynamic_cast<CClassNode *>(LastSelectedNode)); 389 } 390 else if (LastSelectedNode->GetNodeType() == DeviceNode) 391 { 392 LastSelectedNode = new CDeviceNode(*dynamic_cast<CDeviceNode *>(LastSelectedNode)); 393 } 394 395 // Empty the treeview 396 This->EmptyDeviceView(); 397 398 // Re-add the root node to the tree 399 if (This->AddRootDevice() == false) 400 return 0; 401 402 // Refresh the devices only if requested 403 if (ThreadData->ScanForChanges) 404 { 405 This->RefreshDeviceList(); 406 } 407 408 // display the type of view the user wants 409 switch (This->m_ViewType) 410 { 411 case DevicesByType: 412 (void)This->ListDevicesByType(); 413 break; 414 415 case DevicesByConnection: 416 (VOID)This->ListDevicesByConnection(); 417 break; 418 419 case ResourcesByType: 420 break; 421 422 case ResourcesByConnection: 423 break; 424 } 425 426 This->SelectNode(LastSelectedNode); 427 428 delete ThreadData; 429 430 return 0; 431 } 432 433 434 bool 435 CDeviceView::ListDevicesByType() 436 { 437 CClassNode *ClassNode; 438 CDeviceNode *DeviceNode; 439 HDEVINFO hDevInfo; 440 HTREEITEM hTreeItem = NULL; 441 GUID ClassGuid; 442 INT ClassIndex; 443 BOOL bClassSuccess, bSuccess; 444 445 ClassIndex = 0; 446 do 447 { 448 // Loop through all the device classes 449 bClassSuccess = GetNextClass(ClassIndex, &ClassGuid, &hDevInfo); 450 if (bClassSuccess) 451 { 452 bool bClassUnknown = false; 453 bool AddedParent = false; 454 INT DeviceIndex = 0; 455 bool MoreItems = false; 456 457 // Get the cached class node 458 ClassNode = GetClassNode(&ClassGuid); 459 if (ClassNode == nullptr) 460 { 461 ClassIndex++; 462 continue; 463 } 464 465 // Set a flag is this is the (special case) unknown class 466 if (IsEqualGUID(ClassGuid, GUID_DEVCLASS_UNKNOWN)) 467 bClassUnknown = true; 468 469 // Check if this is a hidden class 470 if (IsEqualGUID(ClassGuid, GUID_DEVCLASS_LEGACYDRIVER) || 471 IsEqualGUID(ClassGuid, GUID_DEVCLASS_VOLUME)) 472 { 473 // Ignore this device if we aren't displaying hidden devices 474 if (m_ShowHidden == FALSE) 475 { 476 ClassIndex++; 477 continue; 478 } 479 } 480 481 do 482 { 483 // Get a handle to all the devices in this class 484 SP_DEVINFO_DATA DeviceInfoData; 485 ZeroMemory(&DeviceInfoData, sizeof(SP_DEVINFO_DATA)); 486 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); 487 bSuccess = SetupDiEnumDeviceInfo(hDevInfo, 488 DeviceIndex, 489 &DeviceInfoData); 490 if (bSuccess == FALSE && GetLastError() == ERROR_NO_MORE_ITEMS) 491 MoreItems = false; 492 493 if (bSuccess) 494 { 495 MoreItems = true; 496 497 // The unknown class handle contains all devices on the system, 498 // and we're just looking for the ones with a null GUID 499 if (bClassUnknown) 500 { 501 if (IsEqualGUID(DeviceInfoData.ClassGuid, GUID_NULL) == FALSE) 502 { 503 // This is a known device, we aren't interested in it 504 DeviceIndex++; 505 continue; 506 } 507 } 508 509 // Get the cached device node 510 DeviceNode = GetDeviceNode(DeviceInfoData.DevInst); 511 if (DeviceNode == nullptr) 512 { 513 DeviceIndex++; 514 continue; 515 } 516 517 // Check if this is a hidden device 518 if (DeviceNode->IsHidden()) 519 { 520 // Ignore this device if we aren't displaying hidden devices 521 if (m_ShowHidden == FALSE) 522 { 523 DeviceIndex++; 524 continue; 525 } 526 } 527 528 // We have a device, we need to add the parent if it hasn't yet been added 529 if (AddedParent == false) 530 { 531 // Insert the new class under the root item 532 hTreeItem = InsertIntoTreeView(m_hTreeRoot, 533 ClassNode); 534 AddedParent = true; 535 } 536 537 // Add the device under the class item node 538 (void)InsertIntoTreeView(hTreeItem, DeviceNode); 539 540 // Expand the class if it has a problem device 541 if (DeviceNode->HasProblem()) 542 { 543 (void)TreeView_Expand(m_hTreeView, 544 hTreeItem, 545 TVE_EXPAND); 546 } 547 } 548 549 DeviceIndex++; 550 551 } while (MoreItems); 552 553 // If this class has devices, sort them alphabetically 554 if (AddedParent == true) 555 { 556 (void)TreeView_SortChildren(m_hTreeView, 557 hTreeItem, 558 0); 559 } 560 } 561 562 ClassIndex++; 563 564 } while (bClassSuccess); 565 566 // Sort the classes alphabetically 567 (void)TreeView_SortChildren(m_hTreeView, 568 m_hTreeRoot, 569 0); 570 571 // Expand the root item 572 (void)TreeView_Expand(m_hTreeView, 573 m_hTreeRoot, 574 TVE_EXPAND); 575 576 // Pre-select the root item 577 (VOID)TreeView_SelectItem(m_hTreeView, 578 m_hTreeRoot); 579 580 return 0; 581 } 582 583 bool 584 CDeviceView::ListDevicesByConnection() 585 { 586 // Walk the device tree and add all the devices 587 (void)RecurseChildDevices(m_RootNode->GetDeviceInst(), m_hTreeRoot); 588 589 // Expand the root item 590 (void)TreeView_Expand(m_hTreeView, 591 m_hTreeRoot, 592 TVE_EXPAND); 593 594 return true; 595 } 596 597 bool 598 CDeviceView::RecurseChildDevices( 599 _In_ DEVINST ParentDevice, 600 _In_ HTREEITEM hParentTreeItem 601 ) 602 { 603 HTREEITEM hDevItem = NULL; 604 DEVINST Device; 605 bool HasProblem = false; 606 bool bSuccess; 607 608 // Check if the parent has any child devices 609 if (GetChildDevice(ParentDevice, &Device) == FALSE) 610 return true; 611 612 // Get the cached device node 613 CDeviceNode *DeviceNode; 614 DeviceNode = dynamic_cast<CDeviceNode *>(GetDeviceNode(Device)); 615 if (DeviceNode == nullptr) 616 { 617 return false; 618 } 619 620 // Don't show hidden devices if not requested 621 if ((m_ShowHidden == TRUE) || (!(DeviceNode->IsHidden()))) 622 { 623 // Add this device to the tree under its parent 624 hDevItem = InsertIntoTreeView(hParentTreeItem, 625 DeviceNode); 626 if (hDevItem) 627 { 628 // Check if this child has any children itself 629 if (!RecurseChildDevices(Device, hDevItem)) 630 HasProblem = true; 631 } 632 633 if (DeviceNode->HasProblem()) 634 { 635 HasProblem = true; 636 } 637 } 638 639 640 // Check for siblings 641 for (;;) 642 { 643 // Check if the parent device has anything at the same level 644 bSuccess = GetSiblingDevice(Device, &Device); 645 if (bSuccess == FALSE) 646 break; 647 648 DeviceNode = dynamic_cast<CDeviceNode *>(GetDeviceNode(Device)); 649 if (DeviceNode == nullptr) 650 { 651 continue; 652 } 653 654 // Don't show hidden devices if not requested 655 if ((m_ShowHidden == TRUE) || (!(DeviceNode->IsHidden()))) 656 { 657 if (DeviceNode->HasProblem()) 658 { 659 HasProblem = true; 660 } 661 662 // Add this device to the tree under its parent 663 hDevItem = InsertIntoTreeView(hParentTreeItem, 664 DeviceNode); 665 if (hDevItem) 666 { 667 // Check if this child has any children itself 668 if (!RecurseChildDevices(Device, hDevItem)) 669 HasProblem = true; 670 } 671 } 672 } 673 674 (void)TreeView_SortChildren(m_hTreeView, 675 hParentTreeItem, 676 0); 677 678 // Expand the class if it has a problem device 679 if (HasProblem == true) 680 { 681 (void)TreeView_Expand(m_hTreeView, 682 hParentTreeItem, 683 TVE_EXPAND); 684 } 685 686 // If there was a problem, expand the ancestors 687 if (HasProblem) 688 return false; 689 690 return true; 691 } 692 693 bool 694 CDeviceView::EnableSelectedDevice( 695 _In_ bool Enable, 696 _Out_ bool &NeedsReboot 697 ) 698 { 699 CDeviceNode *Node = dynamic_cast<CDeviceNode *>(GetSelectedNode()); 700 if (Node == nullptr) 701 return false; 702 703 if (Enable == false) 704 { 705 CAtlStringW str; 706 if (str.LoadStringW(g_hThisInstance, IDS_CONFIRM_DISABLE)) 707 { 708 if (MessageBoxW(m_hMainWnd, 709 str, 710 Node->GetDisplayName(), 711 MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2) != IDYES) 712 { 713 return false; 714 } 715 } 716 } 717 718 return Node->EnableDevice(Enable, NeedsReboot); 719 } 720 721 bool 722 CDeviceView::UpdateSelectedDevice( 723 _Out_ bool &NeedsReboot 724 ) 725 { 726 CDeviceNode *Node = dynamic_cast<CDeviceNode *>(GetSelectedNode()); 727 if (Node == nullptr) 728 return false; 729 730 DWORD dwReboot; 731 if (InstallDevInst(m_hMainWnd, Node->GetDeviceId(), TRUE, &dwReboot)) 732 { 733 NeedsReboot = false; 734 return true; 735 } 736 737 return false; 738 } 739 740 bool 741 CDeviceView::UninstallSelectedDevice( 742 ) 743 { 744 CDeviceNode *Node = dynamic_cast<CDeviceNode *>(GetSelectedNode()); 745 if (Node == nullptr) 746 return false; 747 748 CAtlStringW str; 749 if (str.LoadStringW(g_hThisInstance, IDS_CONFIRM_UNINSTALL)) 750 { 751 if (MessageBoxW(m_hMainWnd, 752 str, 753 Node->GetDisplayName(), 754 MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2) != IDYES) 755 { 756 return false; 757 } 758 } 759 760 return Node->UninstallDevice(); 761 } 762 763 bool 764 CDeviceView::RunAddHardwareWizard() 765 { 766 PADDHARDWAREWIZARD pAddHardwareWizard; 767 HMODULE hModule; 768 769 hModule = LoadLibraryW(L"hdwwiz.cpl"); 770 if (hModule == NULL) 771 return false; 772 773 pAddHardwareWizard = (PADDHARDWAREWIZARD)GetProcAddress(hModule, 774 "AddHardwareWizard"); 775 if (pAddHardwareWizard == NULL) 776 { 777 FreeLibrary(hModule); 778 return false; 779 } 780 781 pAddHardwareWizard(m_hMainWnd, NULL); 782 783 FreeLibrary(hModule); 784 return true; 785 } 786 787 bool 788 CDeviceView::GetChildDevice( 789 _In_ DEVINST ParentDevInst, 790 _Out_ PDEVINST DevInst 791 ) 792 { 793 CONFIGRET cr; 794 cr = CM_Get_Child(DevInst, 795 ParentDevInst, 796 0); 797 return (cr == CR_SUCCESS); 798 } 799 800 bool 801 CDeviceView::GetSiblingDevice( 802 _In_ DEVINST PrevDevice, 803 _Out_ PDEVINST DevInst 804 ) 805 { 806 CONFIGRET cr; 807 cr = CM_Get_Sibling(DevInst, 808 PrevDevice, 809 0); 810 return (cr == CR_SUCCESS); 811 } 812 813 HTREEITEM 814 CDeviceView::InsertIntoTreeView( 815 _In_opt_ HTREEITEM hParent, 816 _In_ CNode *Node 817 ) 818 { 819 LPWSTR lpLabel; 820 lpLabel = Node->GetDisplayName(); 821 822 TV_ITEMW tvi; 823 TV_INSERTSTRUCT tvins; 824 ZeroMemory(&tvi, sizeof(tvi)); 825 ZeroMemory(&tvins, sizeof(tvins)); 826 827 tvi.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE; 828 tvi.pszText = lpLabel; 829 tvi.cchTextMax = wcslen(lpLabel); 830 tvi.lParam = (LPARAM)Node; 831 tvi.iImage = Node->GetClassImage(); 832 tvi.iSelectedImage = Node->GetClassImage(); 833 834 // try to cast it to a device node. This will only succeed if it's the correct type 835 CDeviceNode *DeviceNode = dynamic_cast<CDeviceNode *>(Node); 836 if (DeviceNode && DeviceNode->GetOverlayImage()) 837 { 838 tvi.mask |= TVIF_STATE; 839 tvi.stateMask = TVIS_OVERLAYMASK; 840 tvi.state = INDEXTOOVERLAYMASK(DeviceNode->GetOverlayImage()); 841 } 842 843 tvins.item = tvi; 844 tvins.hParent = hParent; 845 846 return TreeView_InsertItem(m_hTreeView, &tvins); 847 } 848 849 void 850 CDeviceView::BuildActionMenuForNode( 851 _In_ HMENU OwnerMenu, 852 _In_ CNode *Node, 853 _In_ bool MainMenu 854 ) 855 { 856 // Create a separator structure 857 MENUITEMINFOW MenuSeparator = { 0 }; 858 MenuSeparator.cbSize = sizeof(MENUITEMINFOW); 859 MenuSeparator.fType = MFT_SEPARATOR; 860 861 // Setup the 862 MENUITEMINFOW MenuItemInfo = { 0 }; 863 MenuItemInfo.cbSize = sizeof(MENUITEMINFOW); 864 MenuItemInfo.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA | MIIM_SUBMENU; 865 MenuItemInfo.fType = MFT_STRING; 866 867 CAtlStringW String; 868 int i = 0; 869 870 // Device nodes have extra data 871 if (Node->GetNodeType() == DeviceNode) 872 { 873 CDeviceNode *DeviceNode = dynamic_cast<CDeviceNode *>(Node); 874 875 if (DeviceNode->CanUpdate()) 876 { 877 String.LoadStringW(g_hThisInstance, IDS_MENU_UPDATE); 878 MenuItemInfo.wID = IDM_UPDATE_DRV; 879 MenuItemInfo.dwTypeData = String.GetBuffer(); 880 InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo); 881 i++; 882 } 883 884 if (DeviceNode->IsDisabled()) 885 { 886 String.LoadStringW(g_hThisInstance, IDS_MENU_ENABLE); 887 MenuItemInfo.wID = IDM_ENABLE_DRV; 888 MenuItemInfo.dwTypeData = String.GetBuffer(); 889 InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo); 890 i++; 891 } 892 893 if (DeviceNode->CanDisable() && !DeviceNode->IsDisabled()) 894 { 895 String.LoadStringW(g_hThisInstance, IDS_MENU_DISABLE); 896 MenuItemInfo.wID = IDM_DISABLE_DRV; 897 MenuItemInfo.dwTypeData = String.GetBuffer(); 898 InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo); 899 i++; 900 } 901 902 if (DeviceNode->CanUninstall()) 903 { 904 String.LoadStringW(g_hThisInstance, IDS_MENU_UNINSTALL); 905 MenuItemInfo.wID = IDM_UNINSTALL_DRV; 906 MenuItemInfo.dwTypeData = String.GetBuffer(); 907 InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo); 908 i++; 909 } 910 911 InsertMenuItemW(OwnerMenu, i, TRUE, &MenuSeparator); 912 i++; 913 } 914 915 // All nodes have the scan option 916 String.LoadStringW(g_hThisInstance, IDS_MENU_SCAN); 917 MenuItemInfo.wID = IDM_SCAN_HARDWARE; 918 MenuItemInfo.dwTypeData = String.GetBuffer(); 919 InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo); 920 i++; 921 922 if ((Node->GetNodeType() == RootNode) || (MainMenu == true)) 923 { 924 String.LoadStringW(g_hThisInstance, IDS_MENU_ADD); 925 MenuItemInfo.wID = IDM_ADD_HARDWARE; 926 MenuItemInfo.dwTypeData = String.GetBuffer(); 927 InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo); 928 i++; 929 } 930 931 if (Node->HasProperties()) 932 { 933 InsertMenuItemW(OwnerMenu, i, TRUE, &MenuSeparator); 934 i++; 935 936 String.LoadStringW(g_hThisInstance, IDS_MENU_PROPERTIES); 937 MenuItemInfo.wID = IDM_PROPERTIES; 938 MenuItemInfo.dwTypeData = String.GetBuffer(); 939 InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo); 940 i++; 941 942 SetMenuDefaultItem(OwnerMenu, IDC_PROPERTIES, FALSE); 943 } 944 } 945 946 HTREEITEM 947 CDeviceView::RecurseFindDevice( 948 _In_ HTREEITEM hParentItem, 949 _In_ CNode *Node 950 ) 951 { 952 HTREEITEM FoundItem; 953 HTREEITEM hItem; 954 TVITEMW tvItem; 955 CNode *FoundNode; 956 957 // Check if this node has any children 958 hItem = TreeView_GetChild(m_hTreeView, hParentItem); 959 if (hItem == NULL) 960 return NULL; 961 962 // The lParam contains the node pointer data 963 tvItem.hItem = hItem; 964 tvItem.mask = TVIF_PARAM; 965 if (TreeView_GetItem(m_hTreeView, &tvItem) && 966 tvItem.lParam != NULL) 967 { 968 // check for a matching node 969 FoundNode = reinterpret_cast<CNode *>(tvItem.lParam); 970 if ((FoundNode->GetNodeType() == Node->GetNodeType()) && 971 (IsEqualGUID(*FoundNode->GetClassGuid(), *Node->GetClassGuid()))) 972 { 973 // check if this is a class node, or a device with matching ID's 974 if ((FoundNode->GetNodeType() == ClassNode) || 975 (wcscmp(FoundNode->GetDeviceId(), Node->GetDeviceId()) == 0)) 976 { 977 return hItem; 978 } 979 } 980 } 981 982 // This node may have its own children 983 FoundItem = RecurseFindDevice(hItem, Node); 984 if (FoundItem) 985 return FoundItem; 986 987 // Loop all the siblings 988 for (;;) 989 { 990 // Get the next item at this level 991 hItem = TreeView_GetNextSibling(m_hTreeView, hItem); 992 if (hItem == NULL) 993 break; 994 995 // The lParam contains the node pointer data 996 tvItem.hItem = hItem; 997 tvItem.mask = TVIF_PARAM; 998 if (TreeView_GetItem(m_hTreeView, &tvItem)) 999 { 1000 // check for a matching class 1001 FoundNode = reinterpret_cast<CNode *>(tvItem.lParam); 1002 if ((FoundNode->GetNodeType() == Node->GetNodeType()) && 1003 (IsEqualGUID(*FoundNode->GetClassGuid(), *Node->GetClassGuid()))) 1004 { 1005 // check if this is a class node, or a device with matching ID's 1006 if ((FoundNode->GetNodeType() == ClassNode) || 1007 (wcscmp(FoundNode->GetDeviceId(), Node->GetDeviceId()) == 0)) 1008 { 1009 return hItem; 1010 } 1011 } 1012 } 1013 1014 // This node may have its own children 1015 FoundItem = RecurseFindDevice(hItem, Node); 1016 if (FoundItem) 1017 return FoundItem; 1018 } 1019 1020 return hItem; 1021 } 1022 1023 void 1024 CDeviceView::SelectNode( 1025 _In_ CNode *Node 1026 ) 1027 { 1028 HTREEITEM hRoot, hItem; 1029 1030 // Check if there are any items in the tree 1031 hRoot = TreeView_GetRoot(m_hTreeView); 1032 if (hRoot == NULL) 1033 return; 1034 1035 // If we don't want to set select a node, just select root 1036 if (Node == nullptr || Node->GetNodeType() == RootNode) 1037 { 1038 TreeView_SelectItem(m_hTreeView, hRoot); 1039 return; 1040 } 1041 1042 // Scan the tree looking for the node we want 1043 hItem = RecurseFindDevice(hRoot, Node); 1044 if (hItem) 1045 { 1046 TreeView_SelectItem(m_hTreeView, hItem); 1047 } 1048 else 1049 { 1050 TreeView_SelectItem(m_hTreeView, hRoot); 1051 } 1052 } 1053 1054 1055 void 1056 CDeviceView::EmptyDeviceView() 1057 { 1058 (VOID)TreeView_DeleteAllItems(m_hTreeView); 1059 } 1060 1061 1062 CClassNode* 1063 CDeviceView::GetClassNode( 1064 _In_ LPGUID ClassGuid 1065 ) 1066 { 1067 POSITION Pos; 1068 CClassNode *Node = nullptr; 1069 1070 Pos = m_ClassNodeList.GetHeadPosition(); 1071 if (Pos == NULL) 1072 return nullptr; 1073 1074 do 1075 { 1076 Node = m_ClassNodeList.GetNext(Pos); 1077 if (IsEqualGUID(*Node->GetClassGuid(), *ClassGuid)) 1078 { 1079 ATLASSERT(Node->GetNodeType() == ClassNode); 1080 break; 1081 } 1082 1083 Node = nullptr; 1084 1085 } while (Pos != NULL); 1086 1087 return Node; 1088 } 1089 1090 CDeviceNode* 1091 CDeviceView::GetDeviceNode( 1092 _In_ DEVINST Device 1093 ) 1094 { 1095 POSITION Pos; 1096 CDeviceNode *Node = nullptr; 1097 1098 Pos = m_DeviceNodeList.GetHeadPosition(); 1099 if (Pos == NULL) 1100 return nullptr; 1101 1102 do 1103 { 1104 Node = m_DeviceNodeList.GetNext(Pos); 1105 if (Node->GetDeviceInst() == Device) 1106 { 1107 ATLASSERT(Node->GetNodeType() == DeviceNode); 1108 break; 1109 } 1110 1111 Node = nullptr; 1112 1113 } while (Pos != NULL); 1114 1115 return Node; 1116 } 1117 1118 CNode* CDeviceView::GetNode( 1119 _In_ LPTV_ITEMW TvItem 1120 ) 1121 { 1122 TvItem->mask = TVIF_PARAM; 1123 if (TreeView_GetItem(m_hTreeView, TvItem)) 1124 { 1125 return (CNode *)TvItem->lParam; 1126 } 1127 return nullptr; 1128 } 1129 1130 void 1131 CDeviceView::EmptyLists() 1132 { 1133 CNode *Node; 1134 1135 while (!m_ClassNodeList.IsEmpty()) 1136 { 1137 Node = m_ClassNodeList.RemoveTail(); 1138 delete Node; 1139 } 1140 1141 while (!m_DeviceNodeList.IsEmpty()) 1142 { 1143 Node = m_DeviceNodeList.RemoveTail(); 1144 delete Node; 1145 } 1146 } 1147 1148 bool 1149 CDeviceView::RefreshDeviceList() 1150 { 1151 GUID ClassGuid; 1152 CClassNode *ClassNode; 1153 CDeviceNode *DeviceNode; 1154 HDEVINFO hDevInfo; 1155 SP_DEVINFO_DATA DeviceInfoData; 1156 DWORD i; 1157 BOOL Success; 1158 1159 ULONG ClassIndex = 0; 1160 1161 EmptyLists(); 1162 1163 if (m_RootNode) delete m_RootNode; 1164 m_RootNode = new CRootNode(&m_ImageListData); 1165 m_RootNode->SetupNode(); 1166 1167 // Loop through all the classes 1168 do 1169 { 1170 Success = GetNextClass(ClassIndex, &ClassGuid, &hDevInfo); 1171 if (Success) 1172 { 1173 // Create a new class node and add it to the list 1174 ClassNode = new CClassNode(&ClassGuid, &m_ImageListData); 1175 if (ClassNode->SetupNode()) 1176 { 1177 m_ClassNodeList.AddTail(ClassNode); 1178 } 1179 1180 SetupDiDestroyDeviceInfoList(hDevInfo); 1181 } 1182 ClassIndex++; 1183 } while (Success); 1184 1185 // Get all the devices on the local machine 1186 hDevInfo = SetupDiGetClassDevsW(NULL, 1187 0, 1188 0, 1189 DIGCF_PRESENT | DIGCF_ALLCLASSES); 1190 if (hDevInfo == INVALID_HANDLE_VALUE) 1191 { 1192 return false; 1193 } 1194 1195 // loop though all the devices 1196 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); 1197 for (i = 0;; i++) 1198 { 1199 // Get the devinst for this device 1200 Success = SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); 1201 if (Success == FALSE) 1202 break; 1203 1204 // create a new device node and add it to the list 1205 DeviceNode = new CDeviceNode(DeviceInfoData.DevInst, &m_ImageListData); 1206 /* FIXME: Start of Hack for CORE-5643 */ 1207 if (!DeviceNode->IsInstalled()) 1208 continue; 1209 /* FIXME: End of Hack for CORE-5643 */ 1210 1211 if (DeviceNode->SetupNode()) 1212 { 1213 m_DeviceNodeList.AddTail(DeviceNode); 1214 } 1215 else 1216 { 1217 ATLASSERT(FALSE); 1218 } 1219 } 1220 1221 SetupDiDestroyDeviceInfoList(hDevInfo); 1222 1223 return TRUE; 1224 }