Reactos
at master 1386 lines 37 kB view raw
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 "restypes.h" 13#include "devmgmt.h" 14#include "DeviceView.h" 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 23typedef VOID(WINAPI *PADDHARDWAREWIZARD)(HWND hwnd, LPWSTR lpName); 24 25struct RefreshThreadData 26{ 27 CDeviceView *This; 28 BOOL ScanForChanges; 29 BOOL UpdateView; 30}; 31 32 33// PUBLIC METHODS ************************************/ 34 35CDeviceView::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 49CDeviceView::~CDeviceView(void) 50{ 51} 52 53bool 54CDeviceView::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 93bool 94CDeviceView::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 107LRESULT 108CDeviceView::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 127LRESULT 128CDeviceView::OnDoubleClick( 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 // Check if we are trying to double-click an item 139 hItem = TreeView_HitTest(m_hTreeView, &hitInfo); 140 if (hItem != NULL && (hitInfo.flags & (TVHT_ONITEM | TVHT_ONITEMICON))) 141 { 142 DisplayPropertySheet(); 143 } 144 145 return 0; 146} 147 148LRESULT 149CDeviceView::OnRightClick( 150 _In_ LPNMHDR NmHdr 151 ) 152{ 153 TVHITTESTINFO hitInfo; 154 HTREEITEM hItem; 155 156 GetCursorPos(&hitInfo.pt); 157 ScreenToClient(m_hTreeView, &hitInfo.pt); 158 159 hItem = TreeView_HitTest(m_hTreeView, &hitInfo); 160 if (hItem != NULL && (hitInfo.flags & (TVHT_ONITEM | TVHT_ONITEMICON))) 161 { 162 TreeView_SelectItem(m_hTreeView, hItem); 163 } 164 165 return 0; 166} 167 168LRESULT 169CDeviceView::OnContextMenu( 170 _In_ LPARAM lParam 171 ) 172{ 173 HTREEITEM hSelected = TreeView_GetSelection(m_hTreeView); 174 175 RECT rc; 176 if (TreeView_GetItemRect(m_hTreeView, 177 hSelected, 178 &rc, 179 TRUE)) 180 { 181 POINT pt; 182 if (GetCursorPos(&pt) && 183 ScreenToClient(m_hTreeView, &pt) && 184 PtInRect(&rc, pt)) 185 { 186 CNode *Node = GetSelectedNode(); 187 if (Node) 188 { 189 // Create the context menu 190 HMENU hContextMenu = CreatePopupMenu(); 191 192 // Add the actions for this node 193 BuildActionMenuForNode(hContextMenu, Node, false); 194 195 INT xPos = GET_X_LPARAM(lParam); 196 INT yPos = GET_Y_LPARAM(lParam); 197 198 // Display the menu 199 TrackPopupMenuEx(hContextMenu, 200 TPM_RIGHTBUTTON, 201 xPos, 202 yPos, 203 m_hMainWnd, 204 NULL); 205 206 DestroyMenu(hContextMenu); 207 } 208 } 209 } 210 211 return 0; 212} 213 214 215void 216CDeviceView::Refresh( 217 _In_ ViewType Type, 218 _In_ bool ScanForChanges, 219 _In_ bool UpdateView 220 ) 221{ 222 // Enum devices on a separate thread to keep the gui responsive 223 224 m_ViewType = Type; 225 226 RefreshThreadData *ThreadData; 227 ThreadData = new RefreshThreadData; 228 ThreadData->This = this; 229 ThreadData->ScanForChanges = ScanForChanges; 230 ThreadData->UpdateView = UpdateView; 231 232 HANDLE hThread; 233 hThread = (HANDLE)_beginthreadex(NULL, 234 0, 235 RefreshThread, 236 ThreadData, 237 0, 238 NULL); 239 if (hThread) CloseHandle(hThread); 240} 241 242LRESULT 243CDeviceView::OnAction( 244 _In_ UINT Action 245) 246{ 247 switch (Action) 248 { 249 case IDM_PROPERTIES: 250 { 251 DisplayPropertySheet(); 252 break; 253 } 254 255 case IDM_SCAN_HARDWARE: 256 { 257 Refresh(GetCurrentView(), 258 true, 259 true); 260 break; 261 } 262 263 case IDM_ENABLE_DRV: 264 { 265 bool NeedsReboot; 266 if (EnableSelectedDevice(true, NeedsReboot) && 267 NeedsReboot) 268 { 269 MessageBox(m_hMainWnd, L"Rebooting", L"Enable", MB_OK); 270 } 271 break; 272 } 273 274 case IDM_DISABLE_DRV: 275 { 276 bool NeedsReboot; 277 EnableSelectedDevice(false, NeedsReboot); 278 break; 279 } 280 281 case IDM_UPDATE_DRV: 282 { 283 bool NeedsReboot; 284 UpdateSelectedDevice(NeedsReboot); 285 break; 286 } 287 288 case IDM_UNINSTALL_DRV: 289 { 290 UninstallSelectedDevice(); 291 break; 292 } 293 294 case IDM_ADD_HARDWARE: 295 { 296 RunAddHardwareWizard(); 297 break; 298 } 299 } 300 301 return 0; 302} 303 304void 305CDeviceView::DisplayPropertySheet() 306{ 307 CNode *Node = GetSelectedNode(); 308 if (Node && Node->HasProperties()) 309 { 310 DevicePropertiesExW(m_hTreeView, 311 NULL, 312 Node->GetDeviceId(), 313 1,//DPF_EXTENDED, 314 FALSE); 315 } 316} 317 318void 319CDeviceView::SetFocus() 320{ 321 ::SetFocus(m_hTreeView); 322} 323 324bool 325CDeviceView::CreateActionMenu( 326 _In_ HMENU OwnerMenu, 327 _In_ bool MainMenu 328 ) 329{ 330 CNode *Node = GetSelectedNode(); 331 if (Node) 332 { 333 BuildActionMenuForNode(OwnerMenu, Node, MainMenu); 334 return true; 335 } 336 337 return false; 338} 339 340CNode* 341CDeviceView::GetSelectedNode() 342{ 343 TV_ITEM TvItem; 344 TvItem.hItem = TreeView_GetSelection(m_hTreeView); 345 return GetNode(&TvItem); 346} 347 348 349 350// PRIVATE METHODS *******************************************/ 351 352bool 353CDeviceView::AddRootDevice() 354{ 355 m_hTreeRoot = InsertIntoTreeView(NULL, m_RootNode); 356 return (m_hTreeRoot != NULL); 357} 358 359bool 360CDeviceView::GetNextClass( 361 _In_ ULONG ClassIndex, 362 _Out_ LPGUID ClassGuid, 363 _Out_ HDEVINFO *hDevInfo 364 ) 365{ 366 CONFIGRET cr; 367 368 // Get the next class in the list 369 cr = CM_Enumerate_Classes(ClassIndex, 370 ClassGuid, 371 0); 372 if (cr != CR_SUCCESS) 373 return false; 374 375 // We only want the devices for this class 376 *hDevInfo = SetupDiGetClassDevsW(ClassGuid, 377 NULL, 378 NULL, 379 DIGCF_PRESENT); 380 381 return (hDevInfo != INVALID_HANDLE_VALUE); 382} 383 384unsigned int __stdcall CDeviceView::RefreshThread(void *Param) 385{ 386 RefreshThreadData *ThreadData = (RefreshThreadData *)Param; 387 CDeviceView *This = ThreadData->This; 388 389 // Get a copy of the currently selected node 390 CNode *LastSelectedNode = This->GetSelectedNode(); 391 if (LastSelectedNode == nullptr || (LastSelectedNode->GetNodeType() == RootNode)) 392 { 393 LastSelectedNode = new CRootNode(*This->m_RootNode); 394 } 395 else if (LastSelectedNode->GetNodeType() == ClassNode) 396 { 397 LastSelectedNode = new CClassNode(*dynamic_cast<CClassNode *>(LastSelectedNode)); 398 } 399 else if (LastSelectedNode->GetNodeType() == DeviceNode) 400 { 401 LastSelectedNode = new CDeviceNode(*dynamic_cast<CDeviceNode *>(LastSelectedNode)); 402 } 403 404 // Empty the treeview 405 This->EmptyDeviceView(); 406 407 // Re-add the root node to the tree 408 if (This->AddRootDevice() == false) 409 return 0; 410 411 // Refresh the devices only if requested 412 if (ThreadData->ScanForChanges) 413 { 414 This->RefreshDeviceList(); 415 } 416 417 // display the type of view the user wants 418 switch (This->m_ViewType) 419 { 420 case DevicesByType: 421 (void)This->ListDevicesByType(); 422 break; 423 424 case DevicesByConnection: 425 (VOID)This->ListDevicesByConnection(); 426 break; 427 428 case ResourcesByType: 429 (VOID)This->ListResourcesByType(); 430 break; 431 432 case ResourcesByConnection: 433 break; 434 } 435 436 This->SelectNode(LastSelectedNode); 437 438 delete ThreadData; 439 440 return 0; 441} 442 443 444bool 445CDeviceView::ListDevicesByType() 446{ 447 CClassNode *ClassNode; 448 CDeviceNode *DeviceNode; 449 HDEVINFO hDevInfo; 450 HTREEITEM hTreeItem = NULL; 451 GUID ClassGuid; 452 INT ClassIndex; 453 BOOL bClassSuccess, bSuccess; 454 455 ClassIndex = 0; 456 do 457 { 458 // Loop through all the device classes 459 bClassSuccess = GetNextClass(ClassIndex, &ClassGuid, &hDevInfo); 460 if (bClassSuccess) 461 { 462 bool AddedParent = false; 463 INT DeviceIndex = 0; 464 bool MoreItems = false; 465 466 // Get the cached class node 467 ClassNode = GetClassNode(&ClassGuid); 468 if (ClassNode == nullptr) 469 { 470 ClassIndex++; 471 continue; 472 } 473 474 // Check if this is a hidden class 475 if (IsEqualGUID(ClassGuid, GUID_DEVCLASS_LEGACYDRIVER) || 476 IsEqualGUID(ClassGuid, GUID_DEVCLASS_VOLUME)) 477 { 478 // Ignore this device if we aren't displaying hidden devices 479 if (m_ShowHidden == FALSE) 480 { 481 ClassIndex++; 482 continue; 483 } 484 } 485 486 do 487 { 488 // Get a handle to all the devices in this class 489 SP_DEVINFO_DATA DeviceInfoData; 490 ZeroMemory(&DeviceInfoData, sizeof(SP_DEVINFO_DATA)); 491 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); 492 bSuccess = SetupDiEnumDeviceInfo(hDevInfo, 493 DeviceIndex, 494 &DeviceInfoData); 495 if (bSuccess == FALSE && GetLastError() == ERROR_NO_MORE_ITEMS) 496 MoreItems = false; 497 498 if (bSuccess) 499 { 500 MoreItems = true; 501 502 // Get the cached device node 503 DeviceNode = GetDeviceNode(DeviceInfoData.DevInst); 504 if (DeviceNode == nullptr) 505 { 506 DeviceIndex++; 507 continue; 508 } 509 510 // Check if this is a hidden device 511 if (DeviceNode->IsHidden()) 512 { 513 // Ignore this device if we aren't displaying hidden devices 514 if (m_ShowHidden == FALSE) 515 { 516 DeviceIndex++; 517 continue; 518 } 519 } 520 521 // We have a device, we need to add the parent if it hasn't yet been added 522 if (AddedParent == false) 523 { 524 // Insert the new class under the root item 525 hTreeItem = InsertIntoTreeView(m_hTreeRoot, 526 ClassNode); 527 AddedParent = true; 528 } 529 530 // Add the device under the class item node 531 (void)InsertIntoTreeView(hTreeItem, DeviceNode); 532 533 // Expand the class if it has a problem device 534 if (DeviceNode->HasProblem()) 535 { 536 (void)TreeView_Expand(m_hTreeView, 537 hTreeItem, 538 TVE_EXPAND); 539 } 540 } 541 542 DeviceIndex++; 543 544 } while (MoreItems); 545 546 // If this class has devices, sort them alphabetically 547 if (AddedParent == true) 548 { 549 (void)TreeView_SortChildren(m_hTreeView, 550 hTreeItem, 551 0); 552 } 553 } 554 555 ClassIndex++; 556 557 } while (bClassSuccess); 558 559 // Sort the classes alphabetically 560 (void)TreeView_SortChildren(m_hTreeView, 561 m_hTreeRoot, 562 0); 563 564 // Expand the root item 565 (void)TreeView_Expand(m_hTreeView, 566 m_hTreeRoot, 567 TVE_EXPAND); 568 569 // Pre-select the root item 570 (VOID)TreeView_SelectItem(m_hTreeView, 571 m_hTreeRoot); 572 573 return 0; 574} 575 576bool 577CDeviceView::ListDevicesByConnection() 578{ 579 // Walk the device tree and add all the devices 580 (void)RecurseChildDevices(m_RootNode->GetDeviceInst(), m_hTreeRoot); 581 582 // Expand the root item 583 (void)TreeView_Expand(m_hTreeView, 584 m_hTreeRoot, 585 TVE_EXPAND); 586 587 return true; 588} 589 590bool 591CDeviceView::ListResourcesByType() 592{ 593 HTREEITEM hMemoryTreeItem = NULL; 594 HTREEITEM hPortTreeItem = NULL; 595 HTREEITEM hDmaTreeItem = NULL; 596 HTREEITEM hIrqTreeItem = NULL; 597 598 CResourceTypeNode *MemoryNode = new CResourceTypeNode(IDS_TYPE_MEMORY, &m_ImageListData); 599 hMemoryTreeItem = InsertIntoTreeView(m_hTreeRoot, 600 MemoryNode); 601 602 CResourceTypeNode *PortNode = new CResourceTypeNode(IDS_TYPE_PORT, &m_ImageListData); 603 hPortTreeItem = InsertIntoTreeView(m_hTreeRoot, 604 PortNode); 605 606 CResourceTypeNode *DmaNode = new CResourceTypeNode(IDS_TYPE_DMA, &m_ImageListData); 607 hDmaTreeItem = InsertIntoTreeView(m_hTreeRoot, 608 DmaNode); 609 610 CResourceTypeNode *IrqNode = new CResourceTypeNode(IDS_TYPE_IRQ, &m_ImageListData); 611 hIrqTreeItem = InsertIntoTreeView(m_hTreeRoot, 612 IrqNode); 613 614 // Walk the device tree and add all the resources 615 (void)RecurseResources(m_RootNode->GetDeviceInst(), 616 hMemoryTreeItem, 617 hPortTreeItem, 618 hDmaTreeItem, 619 hIrqTreeItem); 620 621 // Sort the resource types alphabetically 622 (void)TreeView_SortChildren(m_hTreeView, 623 m_hTreeRoot, 624 0); 625 626 // Expand the root item 627 (void)TreeView_Expand(m_hTreeView, 628 m_hTreeRoot, 629 TVE_EXPAND); 630 631 return true; 632} 633 634 635bool 636CDeviceView::RecurseResources( 637 _In_ DEVINST ParentDevice, 638 _In_ HTREEITEM hMemoryTreeItem, 639 _In_ HTREEITEM hPortTreeItem, 640 _In_ HTREEITEM hDmaTreeItem, 641 _In_ HTREEITEM hIrqTreeItem 642 ) 643{ 644 DEVINST Device; 645 bool bSuccess; 646 ULONG Index; 647 648 // Check if the parent has any child devices 649 if (GetChildDevice(ParentDevice, &Device) == FALSE) 650 return true; 651 652 // Get the cached device node 653 CDeviceNode *DeviceNode; 654 DeviceNode = dynamic_cast<CDeviceNode *>(GetDeviceNode(Device)); 655 if (DeviceNode == nullptr) 656 { 657 return false; 658 } 659 660 PCM_RESOURCE_LIST pResourceList = (PCM_RESOURCE_LIST)GetResourceList(DeviceNode->GetDeviceId()); 661 if (pResourceList) 662 { 663 664 for (Index = 0; Index < pResourceList->List[0].PartialResourceList.Count; Index++) 665 { 666 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor = &pResourceList->List[0].PartialResourceList.PartialDescriptors[Index]; 667 668 if (Descriptor->Type == CmResourceTypeInterrupt) 669 { 670 CResourceNode *resNode = new CResourceNode(DeviceNode, Descriptor, &m_ImageListData); 671 InsertIntoTreeView(hIrqTreeItem, resNode); 672 } 673 else if (Descriptor->Type == CmResourceTypePort) 674 { 675 CResourceNode *resNode = new CResourceNode(DeviceNode, Descriptor, &m_ImageListData); 676 InsertIntoTreeView(hPortTreeItem, resNode); 677 } 678 else if (Descriptor->Type == CmResourceTypeMemory) 679 { 680 CResourceNode *resNode = new CResourceNode(DeviceNode, Descriptor, &m_ImageListData); 681 InsertIntoTreeView(hMemoryTreeItem, resNode); 682 } 683 else if (Descriptor->Type == CmResourceTypeDma) 684 { 685 CResourceNode *resNode = new CResourceNode(DeviceNode, Descriptor, &m_ImageListData); 686 InsertIntoTreeView(hDmaTreeItem, resNode); 687 } 688 } 689 690 HeapFree(GetProcessHeap(), 0, pResourceList); 691 } 692 693 RecurseResources(Device, hMemoryTreeItem, hPortTreeItem, hDmaTreeItem, hIrqTreeItem); 694 695 // Check for siblings 696 for (;;) 697 { 698 // Check if the parent device has anything at the same level 699 bSuccess = GetSiblingDevice(Device, &Device); 700 if (bSuccess == FALSE) 701 break; 702 703 DeviceNode = dynamic_cast<CDeviceNode *>(GetDeviceNode(Device)); 704 if (DeviceNode == nullptr) 705 { 706 continue; 707 } 708 709 PCM_RESOURCE_LIST pResourceList = (PCM_RESOURCE_LIST)GetResourceList(DeviceNode->GetDeviceId()); 710 if (pResourceList) 711 { 712 for (Index = 0; Index < pResourceList->List[0].PartialResourceList.Count; Index++) 713 { 714 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor = &pResourceList->List[0].PartialResourceList.PartialDescriptors[Index]; 715 716 if (Descriptor->Type == CmResourceTypeInterrupt) 717 { 718 CResourceNode *resNode = new CResourceNode(DeviceNode, Descriptor, &m_ImageListData); 719 InsertIntoTreeView(hIrqTreeItem, resNode); 720 } 721 else if (Descriptor->Type == CmResourceTypePort) 722 { 723 CResourceNode *resNode = new CResourceNode(DeviceNode, Descriptor, &m_ImageListData); 724 InsertIntoTreeView(hPortTreeItem, resNode); 725 } 726 else if (Descriptor->Type == CmResourceTypeMemory) 727 { 728 CResourceNode *resNode = new CResourceNode(DeviceNode, Descriptor, &m_ImageListData); 729 InsertIntoTreeView(hMemoryTreeItem, resNode); 730 } 731 else if (Descriptor->Type == CmResourceTypeDma) 732 { 733 CResourceNode *resNode = new CResourceNode(DeviceNode, Descriptor, &m_ImageListData); 734 InsertIntoTreeView(hDmaTreeItem, resNode); 735 } 736 } 737 738 HeapFree(GetProcessHeap(), 0, pResourceList); 739 } 740 741 RecurseResources(Device, hMemoryTreeItem, hPortTreeItem, hDmaTreeItem, hIrqTreeItem); 742 } 743 744 (void)TreeView_SortChildren(m_hTreeView, 745 hMemoryTreeItem, 746 0); 747 748 (void)TreeView_SortChildren(m_hTreeView, 749 hPortTreeItem, 750 0); 751 752 (void)TreeView_SortChildren(m_hTreeView, 753 hIrqTreeItem, 754 0); 755 756 (void)TreeView_SortChildren(m_hTreeView, 757 hDmaTreeItem, 758 0); 759 760 return true; 761} 762 763 764bool 765CDeviceView::RecurseChildDevices( 766 _In_ DEVINST ParentDevice, 767 _In_ HTREEITEM hParentTreeItem 768 ) 769{ 770 HTREEITEM hDevItem = NULL; 771 DEVINST Device; 772 bool HasProblem = false; 773 bool bSuccess; 774 775 // Check if the parent has any child devices 776 if (GetChildDevice(ParentDevice, &Device) == FALSE) 777 return true; 778 779 // Get the cached device node 780 CDeviceNode *DeviceNode; 781 DeviceNode = dynamic_cast<CDeviceNode *>(GetDeviceNode(Device)); 782 if (DeviceNode == nullptr) 783 { 784 return false; 785 } 786 787 // Don't show hidden devices if not requested 788 if ((m_ShowHidden == TRUE) || (!(DeviceNode->IsHidden()))) 789 { 790 // Add this device to the tree under its parent 791 hDevItem = InsertIntoTreeView(hParentTreeItem, 792 DeviceNode); 793 if (hDevItem) 794 { 795 // Check if this child has any children itself 796 if (!RecurseChildDevices(Device, hDevItem)) 797 HasProblem = true; 798 } 799 800 if (DeviceNode->HasProblem()) 801 { 802 HasProblem = true; 803 } 804 } 805 806 807 // Check for siblings 808 for (;;) 809 { 810 // Check if the parent device has anything at the same level 811 bSuccess = GetSiblingDevice(Device, &Device); 812 if (bSuccess == FALSE) 813 break; 814 815 DeviceNode = dynamic_cast<CDeviceNode *>(GetDeviceNode(Device)); 816 if (DeviceNode == nullptr) 817 { 818 continue; 819 } 820 821 // Don't show hidden devices if not requested 822 if ((m_ShowHidden == TRUE) || (!(DeviceNode->IsHidden()))) 823 { 824 if (DeviceNode->HasProblem()) 825 { 826 HasProblem = true; 827 } 828 829 // Add this device to the tree under its parent 830 hDevItem = InsertIntoTreeView(hParentTreeItem, 831 DeviceNode); 832 if (hDevItem) 833 { 834 // Check if this child has any children itself 835 if (!RecurseChildDevices(Device, hDevItem)) 836 HasProblem = true; 837 } 838 } 839 } 840 841 (void)TreeView_SortChildren(m_hTreeView, 842 hParentTreeItem, 843 0); 844 845 // Expand the class if it has a problem device 846 if (HasProblem == true) 847 { 848 (void)TreeView_Expand(m_hTreeView, 849 hParentTreeItem, 850 TVE_EXPAND); 851 } 852 853 // If there was a problem, expand the ancestors 854 if (HasProblem) 855 return false; 856 857 return true; 858} 859 860bool 861CDeviceView::EnableSelectedDevice( 862 _In_ bool Enable, 863 _Out_ bool &NeedsReboot 864 ) 865{ 866 CDeviceNode *Node = dynamic_cast<CDeviceNode *>(GetSelectedNode()); 867 if (Node == nullptr) 868 return false; 869 870 if (Enable == false) 871 { 872 CAtlStringW str; 873 if (str.LoadStringW(g_hThisInstance, IDS_CONFIRM_DISABLE)) 874 { 875 if (MessageBoxW(m_hMainWnd, 876 str, 877 Node->GetDisplayName(), 878 MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2) != IDYES) 879 { 880 return false; 881 } 882 } 883 } 884 885 return Node->EnableDevice(Enable, NeedsReboot); 886} 887 888bool 889CDeviceView::UpdateSelectedDevice( 890 _Out_ bool &NeedsReboot 891 ) 892{ 893 CDeviceNode *Node = dynamic_cast<CDeviceNode *>(GetSelectedNode()); 894 if (Node == nullptr) 895 return false; 896 897 DWORD dwReboot; 898 if (InstallDevInst(m_hMainWnd, Node->GetDeviceId(), TRUE, &dwReboot)) 899 { 900 NeedsReboot = false; 901 return true; 902 } 903 904 return false; 905} 906 907bool 908CDeviceView::UninstallSelectedDevice( 909 ) 910{ 911 CDeviceNode *Node = dynamic_cast<CDeviceNode *>(GetSelectedNode()); 912 if (Node == nullptr) 913 return false; 914 915 CAtlStringW str; 916 if (str.LoadStringW(g_hThisInstance, IDS_CONFIRM_UNINSTALL)) 917 { 918 if (MessageBoxW(m_hMainWnd, 919 str, 920 Node->GetDisplayName(), 921 MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2) != IDYES) 922 { 923 return false; 924 } 925 } 926 927 return Node->UninstallDevice(); 928} 929 930bool 931CDeviceView::RunAddHardwareWizard() 932{ 933 PADDHARDWAREWIZARD pAddHardwareWizard; 934 HMODULE hModule; 935 936 hModule = LoadLibraryW(L"hdwwiz.cpl"); 937 if (hModule == NULL) 938 return false; 939 940 pAddHardwareWizard = (PADDHARDWAREWIZARD)GetProcAddress(hModule, 941 "AddHardwareWizard"); 942 if (pAddHardwareWizard == NULL) 943 { 944 FreeLibrary(hModule); 945 return false; 946 } 947 948 pAddHardwareWizard(m_hMainWnd, NULL); 949 950 FreeLibrary(hModule); 951 return true; 952} 953 954bool 955CDeviceView::GetChildDevice( 956 _In_ DEVINST ParentDevInst, 957 _Out_ PDEVINST DevInst 958) 959{ 960 CONFIGRET cr; 961 cr = CM_Get_Child(DevInst, 962 ParentDevInst, 963 0); 964 return (cr == CR_SUCCESS); 965} 966 967bool 968CDeviceView::GetSiblingDevice( 969 _In_ DEVINST PrevDevice, 970 _Out_ PDEVINST DevInst 971) 972{ 973 CONFIGRET cr; 974 cr = CM_Get_Sibling(DevInst, 975 PrevDevice, 976 0); 977 return (cr == CR_SUCCESS); 978} 979 980HTREEITEM 981CDeviceView::InsertIntoTreeView( 982 _In_opt_ HTREEITEM hParent, 983 _In_ CNode *Node 984 ) 985{ 986 LPWSTR lpLabel; 987 lpLabel = Node->GetDisplayName(); 988 989 TV_ITEMW tvi; 990 TV_INSERTSTRUCT tvins; 991 ZeroMemory(&tvi, sizeof(tvi)); 992 ZeroMemory(&tvins, sizeof(tvins)); 993 994 tvi.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE; 995 tvi.pszText = lpLabel; 996 tvi.cchTextMax = wcslen(lpLabel); 997 tvi.lParam = (LPARAM)Node; 998 tvi.iImage = Node->GetClassImage(); 999 tvi.iSelectedImage = Node->GetClassImage(); 1000 1001 // try to cast it to a device node. This will only succeed if it's the correct type 1002 CDeviceNode *DeviceNode = dynamic_cast<CDeviceNode *>(Node); 1003 if (DeviceNode && DeviceNode->GetOverlayImage()) 1004 { 1005 tvi.mask |= TVIF_STATE; 1006 tvi.stateMask = TVIS_OVERLAYMASK; 1007 tvi.state = INDEXTOOVERLAYMASK(DeviceNode->GetOverlayImage()); 1008 } 1009 1010 tvins.item = tvi; 1011 tvins.hParent = hParent; 1012 1013 return TreeView_InsertItem(m_hTreeView, &tvins); 1014} 1015 1016void 1017CDeviceView::BuildActionMenuForNode( 1018 _In_ HMENU OwnerMenu, 1019 _In_ CNode *Node, 1020 _In_ bool MainMenu 1021 ) 1022{ 1023 // Create a separator structure 1024 MENUITEMINFOW MenuSeparator = { 0 }; 1025 MenuSeparator.cbSize = sizeof(MENUITEMINFOW); 1026 MenuSeparator.fType = MFT_SEPARATOR; 1027 1028 // Setup the 1029 MENUITEMINFOW MenuItemInfo = { 0 }; 1030 MenuItemInfo.cbSize = sizeof(MENUITEMINFOW); 1031 MenuItemInfo.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA | MIIM_SUBMENU; 1032 MenuItemInfo.fType = MFT_STRING; 1033 1034 CAtlStringW String; 1035 int i = 0; 1036 1037 // Device nodes have extra data 1038 if (Node->GetNodeType() == DeviceNode) 1039 { 1040 CDeviceNode *DeviceNode = dynamic_cast<CDeviceNode *>(Node); 1041 1042 if (DeviceNode->CanUpdate()) 1043 { 1044 String.LoadStringW(g_hThisInstance, IDS_MENU_UPDATE); 1045 MenuItemInfo.wID = IDM_UPDATE_DRV; 1046 MenuItemInfo.dwTypeData = String.GetBuffer(); 1047 InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo); 1048 i++; 1049 } 1050 1051 if (DeviceNode->IsDisabled()) 1052 { 1053 String.LoadStringW(g_hThisInstance, IDS_MENU_ENABLE); 1054 MenuItemInfo.wID = IDM_ENABLE_DRV; 1055 MenuItemInfo.dwTypeData = String.GetBuffer(); 1056 InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo); 1057 i++; 1058 } 1059 1060 if (DeviceNode->CanDisable() && !DeviceNode->IsDisabled()) 1061 { 1062 String.LoadStringW(g_hThisInstance, IDS_MENU_DISABLE); 1063 MenuItemInfo.wID = IDM_DISABLE_DRV; 1064 MenuItemInfo.dwTypeData = String.GetBuffer(); 1065 InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo); 1066 i++; 1067 } 1068 1069 if (DeviceNode->CanUninstall()) 1070 { 1071 String.LoadStringW(g_hThisInstance, IDS_MENU_UNINSTALL); 1072 MenuItemInfo.wID = IDM_UNINSTALL_DRV; 1073 MenuItemInfo.dwTypeData = String.GetBuffer(); 1074 InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo); 1075 i++; 1076 } 1077 1078 InsertMenuItemW(OwnerMenu, i, TRUE, &MenuSeparator); 1079 i++; 1080 } 1081 1082 // All nodes have the scan option 1083 String.LoadStringW(g_hThisInstance, IDS_MENU_SCAN); 1084 MenuItemInfo.wID = IDM_SCAN_HARDWARE; 1085 MenuItemInfo.dwTypeData = String.GetBuffer(); 1086 InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo); 1087 i++; 1088 1089 if ((Node->GetNodeType() == RootNode) || (MainMenu == true)) 1090 { 1091 String.LoadStringW(g_hThisInstance, IDS_MENU_ADD); 1092 MenuItemInfo.wID = IDM_ADD_HARDWARE; 1093 MenuItemInfo.dwTypeData = String.GetBuffer(); 1094 InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo); 1095 i++; 1096 } 1097 1098 if (Node->HasProperties()) 1099 { 1100 InsertMenuItemW(OwnerMenu, i, TRUE, &MenuSeparator); 1101 i++; 1102 1103 String.LoadStringW(g_hThisInstance, IDS_MENU_PROPERTIES); 1104 MenuItemInfo.wID = IDM_PROPERTIES; 1105 MenuItemInfo.dwTypeData = String.GetBuffer(); 1106 InsertMenuItemW(OwnerMenu, i, TRUE, &MenuItemInfo); 1107 i++; 1108 1109 SetMenuDefaultItem(OwnerMenu, IDC_PROPERTIES, FALSE); 1110 } 1111} 1112 1113HTREEITEM 1114CDeviceView::RecurseFindDevice( 1115 _In_ HTREEITEM hParentItem, 1116 _In_ CNode *Node 1117 ) 1118{ 1119 HTREEITEM FoundItem; 1120 HTREEITEM hItem; 1121 TVITEMW tvItem; 1122 CNode *FoundNode; 1123 1124 // Check if this node has any children 1125 hItem = TreeView_GetChild(m_hTreeView, hParentItem); 1126 if (hItem == NULL) 1127 return NULL; 1128 1129 // The lParam contains the node pointer data 1130 tvItem.hItem = hItem; 1131 tvItem.mask = TVIF_PARAM; 1132 if (TreeView_GetItem(m_hTreeView, &tvItem) && 1133 tvItem.lParam != NULL) 1134 { 1135 // check for a matching node 1136 FoundNode = reinterpret_cast<CNode *>(tvItem.lParam); 1137 if ((FoundNode->GetNodeType() == Node->GetNodeType()) && 1138 (IsEqualGUID(*FoundNode->GetClassGuid(), *Node->GetClassGuid()))) 1139 { 1140 // check if this is a class node, or a device with matching ID's 1141 if ((FoundNode->GetNodeType() == ClassNode) || 1142 (wcscmp(FoundNode->GetDeviceId(), Node->GetDeviceId()) == 0)) 1143 { 1144 return hItem; 1145 } 1146 } 1147 } 1148 1149 // This node may have its own children 1150 FoundItem = RecurseFindDevice(hItem, Node); 1151 if (FoundItem) 1152 return FoundItem; 1153 1154 // Loop all the siblings 1155 for (;;) 1156 { 1157 // Get the next item at this level 1158 hItem = TreeView_GetNextSibling(m_hTreeView, hItem); 1159 if (hItem == NULL) 1160 break; 1161 1162 // The lParam contains the node pointer data 1163 tvItem.hItem = hItem; 1164 tvItem.mask = TVIF_PARAM; 1165 if (TreeView_GetItem(m_hTreeView, &tvItem)) 1166 { 1167 // check for a matching class 1168 FoundNode = reinterpret_cast<CNode *>(tvItem.lParam); 1169 if ((FoundNode->GetNodeType() == Node->GetNodeType()) && 1170 (IsEqualGUID(*FoundNode->GetClassGuid(), *Node->GetClassGuid()))) 1171 { 1172 // check if this is a class node, or a device with matching ID's 1173 if ((FoundNode->GetNodeType() == ClassNode) || 1174 (wcscmp(FoundNode->GetDeviceId(), Node->GetDeviceId()) == 0)) 1175 { 1176 return hItem; 1177 } 1178 } 1179 } 1180 1181 // This node may have its own children 1182 FoundItem = RecurseFindDevice(hItem, Node); 1183 if (FoundItem) 1184 return FoundItem; 1185 } 1186 1187 return hItem; 1188} 1189 1190void 1191CDeviceView::SelectNode( 1192 _In_ CNode *Node 1193 ) 1194{ 1195 HTREEITEM hRoot, hItem; 1196 1197 // Check if there are any items in the tree 1198 hRoot = TreeView_GetRoot(m_hTreeView); 1199 if (hRoot == NULL) 1200 return; 1201 1202 // If we don't want to set select a node, just select root 1203 if (Node == nullptr || Node->GetNodeType() == RootNode) 1204 { 1205 TreeView_SelectItem(m_hTreeView, hRoot); 1206 return; 1207 } 1208 1209 // Scan the tree looking for the node we want 1210 hItem = RecurseFindDevice(hRoot, Node); 1211 if (hItem) 1212 { 1213 TreeView_SelectItem(m_hTreeView, hItem); 1214 } 1215 else 1216 { 1217 TreeView_SelectItem(m_hTreeView, hRoot); 1218 } 1219} 1220 1221 1222void 1223CDeviceView::EmptyDeviceView() 1224{ 1225 (VOID)TreeView_DeleteAllItems(m_hTreeView); 1226} 1227 1228 1229CClassNode* 1230CDeviceView::GetClassNode( 1231 _In_ LPGUID ClassGuid 1232 ) 1233{ 1234 POSITION Pos; 1235 CClassNode *Node = nullptr; 1236 1237 Pos = m_ClassNodeList.GetHeadPosition(); 1238 if (Pos == NULL) 1239 return nullptr; 1240 1241 do 1242 { 1243 Node = m_ClassNodeList.GetNext(Pos); 1244 if (IsEqualGUID(*Node->GetClassGuid(), *ClassGuid)) 1245 { 1246 ATLASSERT(Node->GetNodeType() == ClassNode); 1247 break; 1248 } 1249 1250 Node = nullptr; 1251 1252 } while (Pos != NULL); 1253 1254 return Node; 1255} 1256 1257CDeviceNode* 1258CDeviceView::GetDeviceNode( 1259 _In_ DEVINST Device 1260 ) 1261{ 1262 POSITION Pos; 1263 CDeviceNode *Node = nullptr; 1264 1265 Pos = m_DeviceNodeList.GetHeadPosition(); 1266 if (Pos == NULL) 1267 return nullptr; 1268 1269 do 1270 { 1271 Node = m_DeviceNodeList.GetNext(Pos); 1272 if (Node->GetDeviceInst() == Device) 1273 { 1274 ATLASSERT(Node->GetNodeType() == DeviceNode); 1275 break; 1276 } 1277 1278 Node = nullptr; 1279 1280 } while (Pos != NULL); 1281 1282 return Node; 1283} 1284 1285CNode* CDeviceView::GetNode( 1286 _In_ LPTV_ITEMW TvItem 1287 ) 1288{ 1289 TvItem->mask = TVIF_PARAM; 1290 if (TreeView_GetItem(m_hTreeView, TvItem)) 1291 { 1292 return (CNode *)TvItem->lParam; 1293 } 1294 return nullptr; 1295} 1296 1297void 1298CDeviceView::EmptyLists() 1299{ 1300 CNode *Node; 1301 1302 while (!m_ClassNodeList.IsEmpty()) 1303 { 1304 Node = m_ClassNodeList.RemoveTail(); 1305 delete Node; 1306 } 1307 1308 while (!m_DeviceNodeList.IsEmpty()) 1309 { 1310 Node = m_DeviceNodeList.RemoveTail(); 1311 delete Node; 1312 } 1313} 1314 1315bool 1316CDeviceView::RefreshDeviceList() 1317{ 1318 GUID ClassGuid; 1319 CClassNode *ClassNode; 1320 CDeviceNode *DeviceNode; 1321 HDEVINFO hDevInfo; 1322 SP_DEVINFO_DATA DeviceInfoData; 1323 DWORD i; 1324 BOOL Success; 1325 1326 ULONG ClassIndex = 0; 1327 1328 EmptyLists(); 1329 1330 if (m_RootNode) delete m_RootNode; 1331 m_RootNode = new CRootNode(&m_ImageListData); 1332 m_RootNode->SetupNode(); 1333 1334 // Loop through all the classes 1335 do 1336 { 1337 Success = GetNextClass(ClassIndex, &ClassGuid, &hDevInfo); 1338 if (Success) 1339 { 1340 // Create a new class node and add it to the list 1341 ClassNode = new CClassNode(&ClassGuid, &m_ImageListData); 1342 if (ClassNode->SetupNode()) 1343 { 1344 m_ClassNodeList.AddTail(ClassNode); 1345 } 1346 1347 SetupDiDestroyDeviceInfoList(hDevInfo); 1348 } 1349 ClassIndex++; 1350 } while (Success); 1351 1352 // Get all the devices on the local machine 1353 hDevInfo = SetupDiGetClassDevsW(NULL, 1354 0, 1355 0, 1356 DIGCF_PRESENT | DIGCF_ALLCLASSES); 1357 if (hDevInfo == INVALID_HANDLE_VALUE) 1358 { 1359 return false; 1360 } 1361 1362 // loop though all the devices 1363 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); 1364 for (i = 0;; i++) 1365 { 1366 // Get the devinst for this device 1367 Success = SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); 1368 if (Success == FALSE) 1369 break; 1370 1371 // create a new device node and add it to the list 1372 DeviceNode = new CDeviceNode(DeviceInfoData.DevInst, &m_ImageListData); 1373 if (DeviceNode->SetupNode()) 1374 { 1375 m_DeviceNodeList.AddTail(DeviceNode); 1376 } 1377 else 1378 { 1379 ATLASSERT(FALSE); 1380 } 1381 } 1382 1383 SetupDiDestroyDeviceInfoList(hDevInfo); 1384 1385 return TRUE; 1386}