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>
13 #include "DeviceView.h"
16 // DATA ********************************************/
18 #define CLASS_NAME_LEN 256
19 #define CLASS_DESC_LEN 256
20 #define ROOT_NAME_SIZE MAX_COMPUTERNAME_LENGTH + 1
26 IN HWND hWndParent OPTIONAL
,
27 IN LPCWSTR lpMachineName OPTIONAL
,
28 IN LPCWSTR lpDeviceID OPTIONAL
,
29 IN DWORD dwFlags OPTIONAL
,
33 typedef INT_PTR(WINAPI
*pDevicePropertiesExW
)(HWND
,LPCWSTR
,LPCWSTR
,DWORD
,BOOL
);
35 struct RefreshThreadData
44 // PUBLIC METHODS ************************************/
46 CDeviceView::CDeviceView(
51 m_hPropertyDialog(NULL
),
53 m_ViewType(DevicesByType
),
57 ZeroMemory(&m_ImageListData
, sizeof(SP_CLASSIMAGELIST_DATA
));
60 CDeviceView::~CDeviceView(void)
65 CDeviceView::Initialize()
67 // Get the device image list
68 m_ImageListData
.cbSize
= sizeof(SP_CLASSIMAGELIST_DATA
);
69 BOOL bSuccess
= SetupDiGetClassImageList(&m_ImageListData
);
70 if (bSuccess
== FALSE
) return false;
72 // Create the main treeview
73 m_hTreeView
= CreateWindowExW(WS_EX_CLIENTEDGE
,
76 WS_CHILD
| WS_VISIBLE
| WS_BORDER
| TVS_HASLINES
|
77 TVS_HASBUTTONS
| TVS_SHOWSELALWAYS
| TVS_LINESATROOT
,
85 // Set the image list against the treeview
86 (void)TreeView_SetImageList(m_hTreeView
,
87 m_ImageListData
.ImageList
,
90 // Give the treeview arrows instead of +/- boxes (on Win7)
91 SetWindowTheme(m_hTreeView
, L
"explorer", NULL
);
96 return !!(m_hTreeView
);
100 CDeviceView::Uninitialize()
104 if (m_ImageListData
.ImageList
!= NULL
)
106 SetupDiDestroyClassImageList(&m_ImageListData
);
107 ZeroMemory(&m_ImageListData
, sizeof(SP_CLASSIMAGELIST_DATA
));
121 // Resize the treeview
122 SetWindowPos(m_hTreeView
,
134 CDeviceView::OnRightClick(
138 HTREEITEM hItem
= TreeView_GetNextItem(NmHdr
->hwndFrom
, 0, TVGN_DROPHILITE
);
141 TreeView_SelectItem(NmHdr
->hwndFrom
, hItem
);
148 CDeviceView::OnContextMenu(
152 HTREEITEM hSelected
= TreeView_GetSelection(m_hTreeView
);
155 if (TreeView_GetItemRect(m_hTreeView
,
161 if (GetCursorPos(&pt
) &&
162 ScreenToClient(m_hTreeView
, &pt
) &&
165 CNode
*Node
= GetSelectedNode();
168 // Create the context menu
169 HMENU hContextMenu
= CreatePopupMenu();
171 // Add the actions for this node
172 BuildActionMenuForNode(hContextMenu
, Node
, false);
174 INT xPos
= GET_X_LPARAM(lParam
);
175 INT yPos
= GET_Y_LPARAM(lParam
);
178 TrackPopupMenuEx(hContextMenu
,
185 DestroyMenu(hContextMenu
);
195 CDeviceView::Refresh(
197 _In_
bool ScanForChanges
,
198 _In_
bool UpdateView
,
199 _In_opt_ LPWSTR DeviceId
202 // Enum devices on a seperate thread to keep the gui responsive
206 RefreshThreadData
*ThreadData
;
207 ThreadData
= new RefreshThreadData
;
208 ThreadData
->This
= this;
209 ThreadData
->ScanForChanges
= ScanForChanges
;
210 ThreadData
->UpdateView
= UpdateView
;
211 ThreadData
->DeviceId
= NULL
;
215 // Node gets deleted on refresh so we copy it to another block
216 size_t Length
= wcslen(DeviceId
) + 1;
217 ThreadData
->DeviceId
= new WCHAR
[Length
];
218 StringCbCopyW(ThreadData
->DeviceId
, Length
, DeviceId
);
223 hThread
= (HANDLE
)_beginthreadex(NULL
,
229 if (hThread
) CloseHandle(hThread
);
233 CDeviceView::OnAction(
241 DisplayPropertySheet();
245 case IDC_SCAN_HARDWARE
:
247 Refresh(GetCurrentView(),
257 if (EnableSelectedDevice(true, NeedsReboot
) &&
260 MessageBox(m_hMainWnd
, L
"Rebooting", L
"Enable", MB_OK
);
265 case IDC_DISABLE_DRV
:
268 EnableSelectedDevice(false, NeedsReboot
);
274 MessageBox(m_hMainWnd
, L
"Not yet implemented", L
"Update Driver", MB_OK
);
278 case IDC_UNINSTALL_DRV
:
280 UninstallSelectedDevice();
284 case IDC_ADD_HARDWARE
:
286 MessageBox(m_hMainWnd
, L
"Not yet implemented", L
"Add Hardware", MB_OK
);
295 CDeviceView::DisplayPropertySheet()
298 // In ReactOS we can link to DevicePropertiesEx but
299 // not in windows as it's not part of the SDK
302 HMODULE hModule
= LoadLibraryW(L
"devmgr.dll");
303 if (hModule
== NULL
) return;
305 pDevicePropertiesExW DevicePropertiesExW
;
306 DevicePropertiesExW
= (pDevicePropertiesExW
)GetProcAddress(hModule
,
307 "DevicePropertiesExW");
308 if (DevicePropertiesExW
== NULL
)
310 FreeLibrary(hModule
);
315 CNode
*Node
= GetSelectedNode();
316 if (Node
&& Node
->HasProperties())
318 DevicePropertiesExW(m_hTreeView
,
326 FreeLibrary(hModule
);
331 CDeviceView::SetFocus()
336 CDeviceView::CreateActionMenu(
337 _In_ HMENU OwnerMenu
,
341 CNode
*Node
= GetSelectedNode();
344 BuildActionMenuForNode(OwnerMenu
, Node
, MainMenu
);
352 CDeviceView::GetSelectedNode()
355 TvItem
.hItem
= TreeView_GetSelection(m_hTreeView
);
356 return GetNode(&TvItem
);
361 // PRIVATE METHODS *******************************************/
364 CDeviceView::AddRootDevice()
366 m_hTreeRoot
= InsertIntoTreeView(NULL
, m_RootNode
);
367 return (m_hTreeRoot
!= NULL
);
371 CDeviceView::GetNextClass(
372 _In_ ULONG ClassIndex
,
373 _Out_ LPGUID ClassGuid
,
374 _Out_ HDEVINFO
*hDevInfo
379 // Get the next class in the list
380 cr
= CM_Enumerate_Classes(ClassIndex
,
383 if (cr
!= CR_SUCCESS
) return false;
385 // Check if this is the unknown class
386 if (IsEqualGUID(*ClassGuid
, GUID_DEVCLASS_UNKNOWN
))
388 // Get device info for all devices
389 *hDevInfo
= SetupDiGetClassDevsW(NULL
,
396 // We only want the devices for this class
397 *hDevInfo
= SetupDiGetClassDevsW(ClassGuid
,
403 return (hDevInfo
!= INVALID_HANDLE_VALUE
);
406 unsigned int __stdcall
CDeviceView::RefreshThread(void *Param
)
408 RefreshThreadData
*ThreadData
= (RefreshThreadData
*)Param
;
409 CDeviceView
*This
= ThreadData
->This
;
412 // Empty the treeview
413 This
->EmptyDeviceView();
414 This
->m_hTreeRoot
= NULL
;
416 // Refresh the devices only if requested. This means
417 // switching views uses the cache and remains fast
418 if (ThreadData
->ScanForChanges
)
420 This
->RefreshDeviceList();
423 // display the type of view the user wants
424 switch (This
->m_ViewType
)
427 (void)This
->ListDevicesByType();
430 case DevicesByConnection
:
431 (VOID
)This
->ListDevicesByConnection();
434 case ResourcesByType
:
437 case ResourcesByConnection
:
442 This
->SelectNode(ThreadData
->DeviceId
);
444 if (ThreadData
->DeviceId
)
445 delete[] ThreadData
->DeviceId
;
453 CDeviceView::ListDevicesByType()
455 CClassNode
*ClassNode
;
456 CDeviceNode
*DeviceNode
;
458 HTREEITEM hTreeItem
= NULL
;
461 BOOL bClassSuccess
, bSuccess
;
463 // Start by adding the root node to the tree
464 bSuccess
= AddRootDevice();
465 if (bSuccess
== false) return false;
470 // Loop through all the device classes
471 bClassSuccess
= GetNextClass(ClassIndex
, &ClassGuid
, &hDevInfo
);
474 bool bClassUnknown
= false;
475 bool AddedParent
= false;
477 bool MoreItems
= false;
479 // Get the cached class node
480 ClassNode
= GetClassNode(&ClassGuid
);
481 if (ClassNode
== nullptr)
488 // Set a flag is this is the (special case) unknown class
489 if (IsEqualGUID(ClassGuid
, GUID_DEVCLASS_UNKNOWN
))
490 bClassUnknown
= true;
494 // Get a handle to all the devices in this class
495 SP_DEVINFO_DATA DeviceInfoData
;
496 ZeroMemory(&DeviceInfoData
, sizeof(SP_DEVINFO_DATA
));
497 DeviceInfoData
.cbSize
= sizeof(SP_DEVINFO_DATA
);
498 bSuccess
= SetupDiEnumDeviceInfo(hDevInfo
,
501 if (bSuccess
== FALSE
&& GetLastError() == ERROR_NO_MORE_ITEMS
)
508 // The unknown class handle contains all devices on the system,
509 // and we're just looking for the ones with a null GUID
512 if (IsEqualGUID(DeviceInfoData
.ClassGuid
, GUID_NULL
) == FALSE
)
514 // This is a known device, we aren't interested in it
520 // Get the cached device node
521 DeviceNode
= GetDeviceNode(DeviceInfoData
.DevInst
);
522 if (DeviceNode
== nullptr)
524 ATLASSERT(bClassUnknown
== true);
529 // Check if this is a hidden device
530 if (DeviceNode
->IsHidden())
532 // Ignore this device if we aren't displaying hidden devices
533 if (m_ShowHidden
== FALSE
)
540 // We have a device, we need to add the parent if it hasn't yet been added
541 if (AddedParent
== false)
543 // Insert the new class under the root item
544 hTreeItem
= InsertIntoTreeView(m_hTreeRoot
,
549 // Add the device under the class item node
550 (void)InsertIntoTreeView(hTreeItem
, DeviceNode
);
552 // Expand the class if it has a problem device
553 if (DeviceNode
->HasProblem())
555 (void)TreeView_Expand(m_hTreeView
,
565 // If this class has devices, sort them alphabetically
566 if (AddedParent
== true)
568 (void)TreeView_SortChildren(m_hTreeView
,
576 } while (bClassSuccess
);
578 // Sort the classes alphabetically
579 (void)TreeView_SortChildren(m_hTreeView
,
583 // Expand the root item
584 (void)TreeView_Expand(m_hTreeView
,
588 // Pre-select the root item
589 (VOID
)TreeView_SelectItem(m_hTreeView
,
596 CDeviceView::ListDevicesByConnection()
600 // Start by adding the root node to the tree
601 bSuccess
= AddRootDevice();
602 if (bSuccess
== false) return false;
604 // Walk the device tree and add all the devices
605 (void)RecurseChildDevices(m_RootNode
->GetDeviceInst(), m_hTreeRoot
);
607 // Expand the root item
608 (void)TreeView_Expand(m_hTreeView
,
616 CDeviceView::RecurseChildDevices(
617 _In_ DEVINST ParentDevice
,
618 _In_ HTREEITEM hParentTreeItem
621 HTREEITEM hDevItem
= NULL
;
623 bool HasProblem
= false;
626 // Check if the parent has any child devices
627 if (GetChildDevice(ParentDevice
, &Device
) == FALSE
)
630 // Get the cached device node
631 CDeviceNode
*DeviceNode
;
632 DeviceNode
= dynamic_cast<CDeviceNode
*>(GetDeviceNode(Device
));
633 if (DeviceNode
== nullptr)
639 // Don't show hidden devices if not requested
640 if ((m_ShowHidden
== TRUE
) || (!(DeviceNode
->IsHidden())))
642 // Add this device to the tree under its parent
643 hDevItem
= InsertIntoTreeView(hParentTreeItem
,
647 // Check if this child has any children itself
648 if (!RecurseChildDevices(Device
, hDevItem
))
652 if (DeviceNode
->HasProblem())
659 // Check for siblings
662 // Check if the parent device has anything at the same level
663 bSuccess
= GetSiblingDevice(Device
, &Device
);
664 if (bSuccess
== FALSE
) break;
666 DeviceNode
= dynamic_cast<CDeviceNode
*>(GetDeviceNode(Device
));
667 if (DeviceNode
== nullptr)
672 // Don't show hidden devices if not requested
673 if ((m_ShowHidden
== TRUE
) || (!(DeviceNode
->IsHidden())))
675 if (DeviceNode
->HasProblem())
680 // Add this device to the tree under its parent
681 hDevItem
= InsertIntoTreeView(hParentTreeItem
,
685 // Check if this child has any children itself
686 if (!RecurseChildDevices(Device
, hDevItem
))
692 (void)TreeView_SortChildren(m_hTreeView
,
696 // Expand the class if it has a problem device
697 if (HasProblem
== true)
699 (void)TreeView_Expand(m_hTreeView
,
704 // If there was a problem, expand the ancestors
705 if (HasProblem
) return false;
711 CDeviceView::EnableSelectedDevice(
713 _Out_
bool &NeedsReboot
716 CDeviceNode
*Node
= dynamic_cast<CDeviceNode
*>(GetSelectedNode());
717 if (Node
== nullptr) return false;
722 if (str
.LoadStringW(g_hThisInstance
, IDS_CONFIRM_DISABLE
))
724 if (MessageBoxW(m_hMainWnd
,
726 Node
->GetDisplayName(),
727 MB_YESNO
| MB_ICONWARNING
| MB_DEFBUTTON2
) != IDYES
)
734 if (Node
->EnableDevice(Enable
, NeedsReboot
))
736 Refresh(m_ViewType
, true, true, Node
->GetDeviceId());
744 CDeviceView::UninstallSelectedDevice(
747 CDeviceNode
*Node
= dynamic_cast<CDeviceNode
*>(GetSelectedNode());
748 if (Node
== nullptr) return false;
750 return Node
->UninstallDevice();
754 CDeviceView::GetChildDevice(
755 _In_ DEVINST ParentDevInst
,
756 _Out_ PDEVINST DevInst
760 cr
= CM_Get_Child(DevInst
,
763 return (cr
== CR_SUCCESS
);
767 CDeviceView::GetSiblingDevice(
768 _In_ DEVINST PrevDevice
,
769 _Out_ PDEVINST DevInst
773 cr
= CM_Get_Sibling(DevInst
,
776 return (cr
== CR_SUCCESS
);
780 CDeviceView::InsertIntoTreeView(
781 _In_opt_ HTREEITEM hParent
,
786 lpLabel
= Node
->GetDisplayName();
789 TV_INSERTSTRUCT tvins
;
790 ZeroMemory(&tvi
, sizeof(tvi
));
791 ZeroMemory(&tvins
, sizeof(tvins
));
793 tvi
.mask
= TVIF_TEXT
| TVIF_PARAM
| TVIF_IMAGE
| TVIF_SELECTEDIMAGE
;
794 tvi
.pszText
= lpLabel
;
795 tvi
.cchTextMax
= wcslen(lpLabel
);
796 tvi
.lParam
= (LPARAM
)Node
;
797 tvi
.iImage
= Node
->GetClassImage();
798 tvi
.iSelectedImage
= Node
->GetClassImage();
800 // try to cast it to a device node. This will only suceed if it's the correct type
801 CDeviceNode
*DeviceNode
= dynamic_cast<CDeviceNode
*>(Node
);
802 if (DeviceNode
&& DeviceNode
->GetOverlayImage())
804 tvi
.mask
|= TVIF_STATE
;
805 tvi
.stateMask
= TVIS_OVERLAYMASK
;
806 tvi
.state
= INDEXTOOVERLAYMASK(DeviceNode
->GetOverlayImage());
810 tvins
.hParent
= hParent
;
812 return TreeView_InsertItem(m_hTreeView
, &tvins
);
816 CDeviceView::BuildActionMenuForNode(
817 _In_ HMENU OwnerMenu
,
822 // Create a seperator structure
823 MENUITEMINFOW MenuSeperator
= { 0 };
824 MenuSeperator
.cbSize
= sizeof(MENUITEMINFOW
);
825 MenuSeperator
.fType
= MFT_SEPARATOR
;
828 MENUITEMINFOW MenuItemInfo
= { 0 };
829 MenuItemInfo
.cbSize
= sizeof(MENUITEMINFOW
);
830 MenuItemInfo
.fMask
= MIIM_ID
| MIIM_STRING
| MIIM_DATA
| MIIM_SUBMENU
;
831 MenuItemInfo
.fType
= MFT_STRING
;
836 // Device nodes have extra data
837 if (Node
->GetNodeType() == DeviceNode
)
839 CDeviceNode
*DeviceNode
= dynamic_cast<CDeviceNode
*>(Node
);
841 if (DeviceNode
->CanUpdate())
843 String
.LoadStringW(g_hThisInstance
, IDS_MENU_UPDATE
);
844 MenuItemInfo
.wID
= IDC_UPDATE_DRV
;
845 MenuItemInfo
.dwTypeData
= String
.GetBuffer();
846 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuItemInfo
);
850 if (DeviceNode
->IsDisabled())
852 String
.LoadStringW(g_hThisInstance
, IDS_MENU_ENABLE
);
853 MenuItemInfo
.wID
= IDC_ENABLE_DRV
;
854 MenuItemInfo
.dwTypeData
= String
.GetBuffer();
855 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuItemInfo
);
859 if (DeviceNode
->CanDisable() && !DeviceNode
->IsDisabled())
861 String
.LoadStringW(g_hThisInstance
, IDS_MENU_DISABLE
);
862 MenuItemInfo
.wID
= IDC_DISABLE_DRV
;
863 MenuItemInfo
.dwTypeData
= String
.GetBuffer();
864 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuItemInfo
);
868 if (DeviceNode
->CanUninstall())
870 String
.LoadStringW(g_hThisInstance
, IDS_MENU_UNINSTALL
);
871 MenuItemInfo
.wID
= IDC_UNINSTALL_DRV
;
872 MenuItemInfo
.dwTypeData
= String
.GetBuffer();
873 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuItemInfo
);
877 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuSeperator
);
881 // All nodes have the scan option
882 String
.LoadStringW(g_hThisInstance
, IDS_MENU_SCAN
);
883 MenuItemInfo
.wID
= IDC_SCAN_HARDWARE
;
884 MenuItemInfo
.dwTypeData
= String
.GetBuffer();
885 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuItemInfo
);
888 if ((Node
->GetNodeType() == RootNode
) || (MainMenu
== true))
890 String
.LoadStringW(g_hThisInstance
, IDS_MENU_ADD
);
891 MenuItemInfo
.wID
= IDC_ADD_HARDWARE
;
892 MenuItemInfo
.dwTypeData
= String
.GetBuffer();
893 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuItemInfo
);
897 if (Node
->HasProperties())
899 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuSeperator
);
902 String
.LoadStringW(g_hThisInstance
, IDS_MENU_PROPERTIES
);
903 MenuItemInfo
.wID
= IDC_PROPERTIES
;
904 MenuItemInfo
.dwTypeData
= String
.GetBuffer();
905 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuItemInfo
);
908 SetMenuDefaultItem(OwnerMenu
, IDC_PROPERTIES
, FALSE
);
913 CDeviceView::RecurseFindDevice(
914 _In_ HTREEITEM hParentItem
,
923 // Check if this node has any children
924 hItem
= TreeView_GetChild(m_hTreeView
, hParentItem
);
925 if (hItem
== NULL
) return NULL
;
927 // The lParam contains the node pointer data
928 tvItem
.hItem
= hItem
;
929 tvItem
.mask
= TVIF_PARAM
;
930 if (TreeView_GetItem(m_hTreeView
, &tvItem
) &&
931 tvItem
.lParam
!= NULL
)
933 // check for a matching deviceid
934 Node
= reinterpret_cast<CNode
*>(tvItem
.lParam
);
935 if (Node
->GetDeviceId() &&
936 (wcscmp(Node
->GetDeviceId(), DeviceId
) == 0))
942 // This node may have its own children
943 FoundItem
= RecurseFindDevice(hItem
, DeviceId
);
944 if (FoundItem
) return FoundItem
;
946 // Loop all the siblings
949 // Get the next item at this level
950 hItem
= TreeView_GetNextSibling(m_hTreeView
, hItem
);
951 if (hItem
== NULL
) break;
953 // The lParam contains the node pointer data
954 tvItem
.hItem
= hItem
;
955 tvItem
.mask
= TVIF_PARAM
;
956 if (TreeView_GetItem(m_hTreeView
, &tvItem
))
958 // check for a matching deviceid
959 Node
= reinterpret_cast<CNode
*>(tvItem
.lParam
);
960 if (Node
->GetDeviceId() &&
961 wcscmp(Node
->GetDeviceId(), DeviceId
) == 0)
967 // This node may have its own children
968 FoundItem
= RecurseFindDevice(hItem
, DeviceId
);
969 if (FoundItem
) return FoundItem
;
976 CDeviceView::SelectNode(
980 HTREEITEM hRoot
, hItem
;
982 // Check if there are any items in the tree
983 hRoot
= TreeView_GetRoot(m_hTreeView
);
984 if (hRoot
== NULL
) return;
986 // If we don't want to set select a node, just select root
987 if (DeviceId
== NULL
)
989 TreeView_SelectItem(m_hTreeView
, hRoot
);
993 // Scan the tree looking for the node we want
994 hItem
= RecurseFindDevice(hRoot
, DeviceId
);
997 TreeView_SelectItem(m_hTreeView
, hItem
);
998 TreeView_Expand(m_hTreeView
, hItem
, TVM_EXPAND
);
1002 TreeView_SelectItem(m_hTreeView
, hRoot
);
1008 CDeviceView::EmptyDeviceView()
1010 (VOID
)TreeView_DeleteAllItems(m_hTreeView
);
1015 CDeviceView::GetClassNode(
1016 _In_ LPGUID ClassGuid
1022 Pos
= m_ClassNodeList
.GetHeadPosition();
1023 if (Pos
== NULL
) return nullptr;
1027 Node
= m_ClassNodeList
.GetNext(Pos
);
1028 if (IsEqualGUID(*Node
->GetClassGuid(), *ClassGuid
))
1030 ATLASSERT(Node
->GetNodeType() == ClassNode
);
1036 } while (Pos
!= NULL
);
1042 CDeviceView::GetDeviceNode(
1049 Pos
= m_DeviceNodeList
.GetHeadPosition();
1050 if (Pos
== NULL
) return nullptr;
1054 Node
= m_DeviceNodeList
.GetNext(Pos
);
1055 if (Node
->GetDeviceInst() == Device
)
1057 ATLASSERT(Node
->GetNodeType() == DeviceNode
);
1063 } while (Pos
!= NULL
);
1068 CNode
* CDeviceView::GetNode(
1069 _In_ LPTV_ITEMW TvItem
1072 TvItem
->mask
= TVIF_PARAM
;
1073 if (TreeView_GetItem(m_hTreeView
, TvItem
))
1075 return (CNode
*)TvItem
->lParam
;
1081 CDeviceView::EmptyLists()
1085 while (!m_ClassNodeList
.IsEmpty())
1087 Node
= m_ClassNodeList
.RemoveTail();
1091 while (!m_DeviceNodeList
.IsEmpty())
1093 Node
= m_DeviceNodeList
.RemoveTail();
1099 CDeviceView::RefreshDeviceList()
1102 CClassNode
*ClassNode
;
1103 CDeviceNode
*DeviceNode
;
1105 SP_DEVINFO_DATA DeviceInfoData
;
1109 ULONG ClassIndex
= 0;
1113 if (m_RootNode
) delete m_RootNode
;
1114 m_RootNode
= new CRootNode(&m_ImageListData
);
1115 m_RootNode
->SetupNode();
1117 // Loop through all the classes
1120 Success
= GetNextClass(ClassIndex
, &ClassGuid
, &hDevInfo
);
1123 // Create a new class node and add it to the list
1124 ClassNode
= new CClassNode(&ClassGuid
, &m_ImageListData
);
1125 if (ClassNode
->SetupNode())
1127 m_ClassNodeList
.AddTail(ClassNode
);
1130 SetupDiDestroyDeviceInfoList(hDevInfo
);
1136 // Get all the devices on the local machine
1137 hDevInfo
= SetupDiGetClassDevsW(NULL
,
1140 DIGCF_PRESENT
| DIGCF_ALLCLASSES
);
1141 if (hDevInfo
== INVALID_HANDLE_VALUE
)
1146 // loop though all the devices
1147 DeviceInfoData
.cbSize
= sizeof(SP_DEVINFO_DATA
);
1150 // Get the devinst for this device
1151 Success
= SetupDiEnumDeviceInfo(hDevInfo
, i
, &DeviceInfoData
);
1152 if (Success
== FALSE
) break;
1154 // create a new device node and add it to the list
1155 DeviceNode
= new CDeviceNode(DeviceInfoData
.DevInst
, &m_ImageListData
);
1156 if (DeviceNode
->SetupNode())
1158 m_DeviceNodeList
.AddTail(DeviceNode
);
1167 SetupDiDestroyDeviceInfoList(hDevInfo
);