2 * PROJECT: ReactOS Device Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/devmgr/devmgr/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
25 IN HWND hWndParent OPTIONAL
,
26 IN LPCWSTR lpMachineName OPTIONAL
,
27 IN LPCWSTR lpDeviceID OPTIONAL
,
28 IN DWORD dwFlags OPTIONAL
,
32 typedef INT_PTR(WINAPI
*pDevicePropertiesExW
)(HWND
,LPCWSTR
,LPCWSTR
,DWORD
,BOOL
);
34 struct RefreshThreadData
43 // PUBLIC METHODS ************************************/
45 CDeviceView::CDeviceView(
50 m_hPropertyDialog(NULL
),
52 m_ViewType(DevicesByType
),
56 ZeroMemory(&m_ImageListData
, sizeof(SP_CLASSIMAGELIST_DATA
));
59 CDeviceView::~CDeviceView(void)
64 CDeviceView::Initialize()
66 // Get the device image list
67 m_ImageListData
.cbSize
= sizeof(SP_CLASSIMAGELIST_DATA
);
68 BOOL bSuccess
= SetupDiGetClassImageList(&m_ImageListData
);
69 if (bSuccess
== FALSE
) return false;
71 // Create the main treeview
72 m_hTreeView
= CreateWindowExW(WS_EX_CLIENTEDGE
,
75 WS_CHILD
| WS_VISIBLE
| WS_BORDER
| TVS_HASLINES
|
76 TVS_HASBUTTONS
| TVS_SHOWSELALWAYS
| TVS_LINESATROOT
,
84 // Set the image list against the treeview
85 (void)TreeView_SetImageList(m_hTreeView
,
86 m_ImageListData
.ImageList
,
89 // Give the treeview arrows instead of +/- boxes (on Win7)
90 SetWindowTheme(m_hTreeView
, L
"explorer", NULL
);
95 return !!(m_hTreeView
);
99 CDeviceView::Uninitialize()
103 if (m_ImageListData
.ImageList
!= NULL
)
105 SetupDiDestroyClassImageList(&m_ImageListData
);
106 ZeroMemory(&m_ImageListData
, sizeof(SP_CLASSIMAGELIST_DATA
));
120 // Resize the treeview
121 SetWindowPos(m_hTreeView
,
133 CDeviceView::OnRightClick(
137 HTREEITEM hItem
= TreeView_GetNextItem(NmHdr
->hwndFrom
, 0, TVGN_DROPHILITE
);
140 TreeView_SelectItem(NmHdr
->hwndFrom
, hItem
);
147 CDeviceView::OnContextMenu(
151 HTREEITEM hSelected
= TreeView_GetSelection(m_hTreeView
);
154 if (TreeView_GetItemRect(m_hTreeView
,
160 if (GetCursorPos(&pt
) &&
161 ScreenToClient(m_hTreeView
, &pt
) &&
164 CNode
*Node
= GetSelectedNode();
167 // Create the context menu
168 HMENU hContextMenu
= CreatePopupMenu();
170 // Add the actions for this node
171 BuildActionMenuForNode(hContextMenu
, Node
, false);
173 INT xPos
= GET_X_LPARAM(lParam
);
174 INT yPos
= GET_Y_LPARAM(lParam
);
177 TrackPopupMenuEx(hContextMenu
,
184 DestroyMenu(hContextMenu
);
194 CDeviceView::Refresh(
196 _In_
bool ScanForChanges
,
197 _In_
bool UpdateView
,
198 _In_opt_ LPWSTR DeviceId
201 // Enum devices on a seperate thread to keep the gui responsive
205 RefreshThreadData
*ThreadData
;
206 ThreadData
= new RefreshThreadData();
207 ThreadData
->This
= this;
208 ThreadData
->ScanForChanges
= ScanForChanges
;
209 ThreadData
->UpdateView
= UpdateView
;
210 ThreadData
->DeviceId
= NULL
;
214 // Node gets deleted on refresh so we copy it to another block
215 size_t Length
= wcslen(DeviceId
) + 1;
216 ThreadData
->DeviceId
= new WCHAR
[Length
];
217 wcscpy_s(ThreadData
->DeviceId
, Length
, DeviceId
);
222 hThread
= (HANDLE
)_beginthreadex(NULL
,
229 if (hThread
) CloseHandle(hThread
);
233 CDeviceView::DisplayPropertySheet()
236 // In ReactOS we can link to DevicePropertiesEx but
237 // not in windows as it's not part of the SDK
240 HMODULE hModule
= LoadLibraryW(L
"devmgr.dll");
241 if (hModule
== NULL
) return;
243 pDevicePropertiesExW DevicePropertiesExW
;
244 DevicePropertiesExW
= (pDevicePropertiesExW
)GetProcAddress(hModule
,
245 "DevicePropertiesExW");
246 if (DevicePropertiesExW
== NULL
)
248 FreeLibrary(hModule
);
253 CNode
*Node
= GetSelectedNode();
254 if (Node
&& Node
->HasProperties())
256 DevicePropertiesExW(m_hTreeView
,
264 FreeLibrary(hModule
);
269 CDeviceView::SetFocus()
274 CDeviceView::CreateActionMenu(
275 _In_ HMENU OwnerMenu
,
279 CNode
*Node
= GetSelectedNode();
282 BuildActionMenuForNode(OwnerMenu
, Node
, MainMenu
);
290 CDeviceView::HasProperties(
291 _In_ LPTV_ITEMW TvItem
294 CNode
*Node
= GetNode(TvItem
);
297 return Node
->HasProperties();
303 CDeviceView::IsDisabled(
304 _In_ LPTV_ITEMW TvItem
307 CDeviceNode
*Node
= dynamic_cast<CDeviceNode
*>(GetNode(TvItem
));
310 return Node
->IsDisabled();
316 CDeviceView::CanDisable(
317 _In_ LPTV_ITEMW TvItem
320 CDeviceNode
*Node
= dynamic_cast<CDeviceNode
*>(GetNode(TvItem
));
323 return Node
->CanDisable();
329 CDeviceView::EnableSelectedDevice(
331 _Out_
bool &NeedsReboot
334 CDeviceNode
*Node
= dynamic_cast<CDeviceNode
*>(GetSelectedNode());
335 if (Node
== nullptr) return false;
340 if (str
.LoadStringW(g_hInstance
, IDS_CONFIRM_DISABLE
))
342 if (MessageBoxW(m_hMainWnd
,
344 Node
->GetDisplayName(),
345 MB_YESNO
| MB_ICONWARNING
| MB_DEFBUTTON2
) != IDYES
)
352 if (Node
->EnableDevice(Enable
, NeedsReboot
))
354 Refresh(m_ViewType
, true, true, Node
->GetDeviceId());
362 // PRIVATE METHODS *******************************************/
365 CDeviceView::AddRootDevice()
367 m_hTreeRoot
= InsertIntoTreeView(NULL
, m_RootNode
);
368 return (m_hTreeRoot
!= NULL
);
372 CDeviceView::GetNextClass(
373 _In_ ULONG ClassIndex
,
374 _Out_ LPGUID ClassGuid
,
375 _Out_ HDEVINFO
*hDevInfo
380 // Get the next class in the list
381 cr
= CM_Enumerate_Classes(ClassIndex
,
384 if (cr
!= CR_SUCCESS
) return false;
386 // Check if this is the unknown class
387 if (IsEqualGUID(*ClassGuid
, GUID_DEVCLASS_UNKNOWN
))
389 // Get device info for all devices
390 *hDevInfo
= SetupDiGetClassDevsW(NULL
,
397 // We only want the devices for this class
398 *hDevInfo
= SetupDiGetClassDevsW(ClassGuid
,
404 return (hDevInfo
!= INVALID_HANDLE_VALUE
);
407 unsigned int __stdcall
CDeviceView::RefreshThread(void *Param
)
409 RefreshThreadData
*ThreadData
= (RefreshThreadData
*)Param
;
410 CDeviceView
*This
= ThreadData
->This
;
413 // Empty the treeview
414 This
->EmptyDeviceView();
415 This
->m_hTreeRoot
= NULL
;
417 // Refresh the devices only if requested. This means
418 // switching views uses the cache and remains fast
419 if (ThreadData
->ScanForChanges
)
421 This
->RefreshDeviceList();
424 // display the type of view the user wants
425 switch (This
->m_ViewType
)
428 (void)This
->ListDevicesByType();
431 case DevicesByConnection
:
432 (VOID
)This
->ListDevicesByConnection();
435 case ResourcesByType
:
438 case ResourcesByConnection
:
443 This
->SelectNode(ThreadData
->DeviceId
);
445 if (ThreadData
->DeviceId
)
446 delete[] ThreadData
->DeviceId
;
454 CDeviceView::ListDevicesByType()
456 CClassNode
*ClassNode
;
457 CDeviceNode
*DeviceNode
;
459 HTREEITEM hTreeItem
= NULL
;
462 LPTSTR DeviceId
= NULL
;
463 BOOL bClassSuccess
, bSuccess
;
465 // Start by adding the root node to the tree
466 bSuccess
= AddRootDevice();
467 if (bSuccess
== false) return false;
472 // Loop through all the device classes
473 bClassSuccess
= GetNextClass(ClassIndex
, &ClassGuid
, &hDevInfo
);
476 bool bClassUnknown
= false;
477 bool AddedParent
= false;
481 // Get the cached class node
482 ClassNode
= GetClassNode(&ClassGuid
);
483 if (ClassNode
== NULL
)
490 // Set a flag is this is the (special case) unknown class
491 if (IsEqualGUID(ClassGuid
, GUID_DEVCLASS_UNKNOWN
))
492 bClassUnknown
= true;
496 // Get a handle to all the devices in this class
497 SP_DEVINFO_DATA DeviceInfoData
;
498 ZeroMemory(&DeviceInfoData
, sizeof(SP_DEVINFO_DATA
));
499 DeviceInfoData
.cbSize
= sizeof(SP_DEVINFO_DATA
);
500 bSuccess
= SetupDiEnumDeviceInfo(hDevInfo
,
503 if (bSuccess
== FALSE
&& GetLastError() == ERROR_NO_MORE_ITEMS
)
510 // The unknown class handle contains all devices on the system,
511 // and we're just looking for the ones with a null GUID
514 if (IsEqualGUID(DeviceInfoData
.ClassGuid
, GUID_NULL
) == FALSE
)
516 // This is a known device, we aren't interested in it
522 // Get the cached device node
523 DeviceNode
= GetDeviceNode(DeviceInfoData
.DevInst
);
524 if (DeviceNode
== NULL
)
526 ATLASSERT(bClassUnknown
== true);
531 // Check if this is a hidden device
532 if (DeviceNode
->IsHidden())
534 // Ignore this device if we aren't displaying hidden devices
535 if (m_ShowHidden
== FALSE
)
542 // We have a device, we need to add the parent if it hasn't yet been added
543 if (AddedParent
== false)
545 // Insert the new class under the root item
546 hTreeItem
= InsertIntoTreeView(m_hTreeRoot
,
551 // Add the device under the class item node
552 (void)InsertIntoTreeView(hTreeItem
, DeviceNode
);
554 // Expand the class if it has a problem device
555 if (DeviceNode
->HasProblem())
557 (void)TreeView_Expand(m_hTreeView
,
567 // If this class has devices, sort them alphabetically
568 if (AddedParent
== true)
570 (void)TreeView_SortChildren(m_hTreeView
,
578 } while (bClassSuccess
);
580 // Sort the classes alphabetically
581 (void)TreeView_SortChildren(m_hTreeView
,
585 // Expand the root item
586 (void)TreeView_Expand(m_hTreeView
,
590 // Pre-select the root item
591 (VOID
)TreeView_SelectItem(m_hTreeView
,
598 CDeviceView::ListDevicesByConnection()
602 // Start by adding the root node to the tree
603 bSuccess
= AddRootDevice();
604 if (bSuccess
== false) return false;
606 // Walk the device tree and add all the devices
607 (void)RecurseChildDevices(m_RootNode
->GetDeviceInst(), m_hTreeRoot
);
609 // Expand the root item
610 (void)TreeView_Expand(m_hTreeView
,
618 CDeviceView::RecurseChildDevices(
619 _In_ DEVINST ParentDevice
,
620 _In_ HTREEITEM hParentTreeItem
623 HTREEITEM hDevItem
= NULL
;
625 bool HasProblem
= false;
628 // Check if the parent has any child devices
629 if (GetChildDevice(ParentDevice
, &Device
) == FALSE
)
632 // Get the cached device node
633 CDeviceNode
*DeviceNode
;
634 DeviceNode
= dynamic_cast<CDeviceNode
*>(GetDeviceNode(Device
));
635 if (DeviceNode
== nullptr)
641 // Don't show hidden devices if not requested
642 if ((m_ShowHidden
== TRUE
) || (!(DeviceNode
->IsHidden())))
644 // Add this device to the tree under its parent
645 hDevItem
= InsertIntoTreeView(hParentTreeItem
,
649 // Check if this child has any children itself
650 if (!RecurseChildDevices(Device
, hDevItem
))
654 if (DeviceNode
->HasProblem())
661 // Check for siblings
664 // Check if the parent device has anything at the same level
665 bSuccess
= GetSiblingDevice(Device
, &Device
);
666 if (bSuccess
== FALSE
) break;
668 DeviceNode
= dynamic_cast<CDeviceNode
*>(GetDeviceNode(Device
));
669 if (DeviceNode
== nullptr)
674 // Don't show hidden devices if not requested
675 if ((m_ShowHidden
== TRUE
) || (!(DeviceNode
->IsHidden())))
677 if (DeviceNode
->HasProblem())
682 // Add this device to the tree under its parent
683 hDevItem
= InsertIntoTreeView(hParentTreeItem
,
687 // Check if this child has any children itself
688 if (!RecurseChildDevices(Device
, hDevItem
))
694 (void)TreeView_SortChildren(m_hTreeView
,
698 // Expand the class if it has a problem device
699 if (HasProblem
== true)
701 (void)TreeView_Expand(m_hTreeView
,
706 // If there was a problem, expand the ancestors
707 if (HasProblem
) return false;
713 CDeviceView::GetChildDevice(
714 _In_ DEVINST ParentDevInst
,
715 _Out_ PDEVINST DevInst
719 cr
= CM_Get_Child(DevInst
,
722 return (cr
== CR_SUCCESS
);
726 CDeviceView::GetSiblingDevice(
727 _In_ DEVINST PrevDevice
,
728 _Out_ PDEVINST DevInst
732 cr
= CM_Get_Sibling(DevInst
,
735 return (cr
== CR_SUCCESS
);
739 CDeviceView::InsertIntoTreeView(
740 _In_opt_ HTREEITEM hParent
,
745 lpLabel
= Node
->GetDisplayName();
748 TV_INSERTSTRUCT tvins
;
749 ZeroMemory(&tvi
, sizeof(tvi
));
750 ZeroMemory(&tvins
, sizeof(tvins
));
752 tvi
.mask
= TVIF_TEXT
| TVIF_PARAM
| TVIF_IMAGE
| TVIF_SELECTEDIMAGE
;
753 tvi
.pszText
= lpLabel
;
754 tvi
.cchTextMax
= wcslen(lpLabel
);
755 tvi
.lParam
= (LPARAM
)Node
;
756 tvi
.iImage
= Node
->GetClassImage();
757 tvi
.iSelectedImage
= Node
->GetClassImage();
759 // try to cast it to a device node. This will only suceed if it's the correct type
760 CDeviceNode
*DeviceNode
= dynamic_cast<CDeviceNode
*>(Node
);
761 if (DeviceNode
&& DeviceNode
->GetOverlayImage())
763 tvi
.mask
|= TVIF_STATE
;
764 tvi
.stateMask
= TVIS_OVERLAYMASK
;
765 tvi
.state
= INDEXTOOVERLAYMASK(DeviceNode
->GetOverlayImage());
769 tvins
.hParent
= hParent
;
771 return TreeView_InsertItem(m_hTreeView
, &tvins
);
775 CDeviceView::BuildActionMenuForNode(
776 _In_ HMENU OwnerMenu
,
781 // Create a seperator structure
782 MENUITEMINFOW MenuSeperator
= { 0 };
783 MenuSeperator
.cbSize
= sizeof(MENUITEMINFOW
);
784 MenuSeperator
.fType
= MFT_SEPARATOR
;
787 MENUITEMINFOW MenuItemInfo
= { 0 };
788 MenuItemInfo
.cbSize
= sizeof(MENUITEMINFOW
);
789 MenuItemInfo
.fMask
= MIIM_ID
| MIIM_STRING
| MIIM_DATA
| MIIM_SUBMENU
;
790 MenuItemInfo
.fType
= MFT_STRING
;
795 // Device nodes have extra data
796 if (Node
->GetNodeType() == DeviceNode
)
798 CDeviceNode
*DeviceNode
= dynamic_cast<CDeviceNode
*>(Node
);
800 if (DeviceNode
->CanUpdate())
802 String
.LoadStringW(g_hInstance
, IDS_MENU_UPDATE
);
803 MenuItemInfo
.wID
= IDC_UPDATE_DRV
;
804 MenuItemInfo
.dwTypeData
= String
.GetBuffer();
805 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuItemInfo
);
809 if (DeviceNode
->IsDisabled())
811 String
.LoadStringW(g_hInstance
, IDS_MENU_ENABLE
);
812 MenuItemInfo
.wID
= IDC_ENABLE_DRV
;
813 MenuItemInfo
.dwTypeData
= String
.GetBuffer();
814 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuItemInfo
);
818 if (DeviceNode
->CanDisable() && !DeviceNode
->IsDisabled())
820 String
.LoadStringW(g_hInstance
, IDS_MENU_DISABLE
);
821 MenuItemInfo
.wID
= IDC_DISABLE_DRV
;
822 MenuItemInfo
.dwTypeData
= String
.GetBuffer();
823 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuItemInfo
);
827 if (DeviceNode
->CanUninstall())
829 String
.LoadStringW(g_hInstance
, IDS_MENU_UNINSTALL
);
830 MenuItemInfo
.wID
= IDC_UNINSTALL_DRV
;
831 MenuItemInfo
.dwTypeData
= String
.GetBuffer();
832 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuItemInfo
);
836 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuSeperator
);
840 // All nodes have the scan option
841 String
.LoadStringW(g_hInstance
, IDS_MENU_SCAN
);
842 MenuItemInfo
.wID
= IDC_SCAN_HARDWARE
;
843 MenuItemInfo
.dwTypeData
= String
.GetBuffer();
844 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuItemInfo
);
847 if ((Node
->GetNodeType() == RootNode
) || (MainMenu
== true))
849 String
.LoadStringW(g_hInstance
, IDS_MENU_ADD
);
850 MenuItemInfo
.wID
= IDC_ADD_HARDWARE
;
851 MenuItemInfo
.dwTypeData
= String
.GetBuffer();
852 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuItemInfo
);
856 if (Node
->HasProperties())
858 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuSeperator
);
861 String
.LoadStringW(g_hInstance
, IDS_MENU_PROPERTIES
);
862 MenuItemInfo
.wID
= IDC_PROPERTIES
;
863 MenuItemInfo
.dwTypeData
= String
.GetBuffer();
864 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuItemInfo
);
867 SetMenuDefaultItem(OwnerMenu
, IDC_PROPERTIES
, FALSE
);
872 CDeviceView::RecurseFindDevice(
873 _In_ HTREEITEM hParentItem
,
882 // Check if this node has any children
883 hItem
= TreeView_GetChild(m_hTreeView
, hParentItem
);
884 if (hItem
== NULL
) return NULL
;
886 // The lParam contains the node pointer data
887 tvItem
.hItem
= hItem
;
888 tvItem
.mask
= TVIF_PARAM
;
889 if (TreeView_GetItem(m_hTreeView
, &tvItem
) &&
890 tvItem
.lParam
!= NULL
)
892 // check for a matching deviceid
893 Node
= reinterpret_cast<CNode
*>(tvItem
.lParam
);
894 if (Node
->GetDeviceId() &&
895 (wcscmp(Node
->GetDeviceId(), DeviceId
) == 0))
901 // This node may have its own children
902 FoundItem
= RecurseFindDevice(hItem
, DeviceId
);
903 if (FoundItem
) return FoundItem
;
905 // Loop all the siblings
908 // Get the next item at this level
909 hItem
= TreeView_GetNextSibling(m_hTreeView
, hItem
);
910 if (hItem
== NULL
) break;
912 // The lParam contains the node pointer data
913 tvItem
.hItem
= hItem
;
914 tvItem
.mask
= TVIF_PARAM
;
915 if (TreeView_GetItem(m_hTreeView
, &tvItem
))
917 // check for a matching deviceid
918 Node
= reinterpret_cast<CNode
*>(tvItem
.lParam
);
919 if (Node
->GetDeviceId() &&
920 wcscmp(Node
->GetDeviceId(), DeviceId
) == 0)
926 // This node may have its own children
927 FoundItem
= RecurseFindDevice(hItem
, DeviceId
);
928 if (FoundItem
) return FoundItem
;
935 CDeviceView::SelectNode(
939 HTREEITEM hRoot
, hItem
;
941 // Check if there are any items in the tree
942 hRoot
= TreeView_GetRoot(m_hTreeView
);
943 if (hRoot
== NULL
) return;
945 // If we don't want to set select a node, just select root
946 if (DeviceId
== NULL
)
948 TreeView_SelectItem(m_hTreeView
, hRoot
);
952 // Scan the tree looking for the node we want
953 hItem
= RecurseFindDevice(hRoot
, DeviceId
);
956 TreeView_SelectItem(m_hTreeView
, hItem
);
957 TreeView_Expand(m_hTreeView
, hItem
, TVM_EXPAND
);
961 TreeView_SelectItem(m_hTreeView
, hRoot
);
967 CDeviceView::EmptyDeviceView()
969 (VOID
)TreeView_DeleteAllItems(m_hTreeView
);
974 CDeviceView::GetClassNode(
975 _In_ LPGUID ClassGuid
981 Pos
= m_ClassNodeList
.GetHeadPosition();
985 Node
= m_ClassNodeList
.GetNext(Pos
);
986 if (IsEqualGUID(*Node
->GetClassGuid(), *ClassGuid
))
988 //ATLASSERT(Node->GetType() == NodeClass);
994 } while (Pos
!= NULL
);
1000 CDeviceView::GetDeviceNode(
1007 Pos
= m_DeviceNodeList
.GetHeadPosition();
1011 Node
= m_DeviceNodeList
.GetNext(Pos
);
1012 if (Node
->GetDeviceInst() == Device
)
1014 //ATLASSERT(Node->GetType() == NodeDevice);
1020 } while (Pos
!= NULL
);
1025 CNode
* CDeviceView::GetNode(
1026 _In_ LPTV_ITEMW TvItem
1029 TvItem
->mask
= TVIF_PARAM
;
1030 if (TreeView_GetItem(m_hTreeView
, TvItem
))
1032 return (CNode
*)TvItem
->lParam
;
1037 CNode
* CDeviceView::GetSelectedNode()
1040 TvItem
.hItem
= TreeView_GetSelection(m_hTreeView
);
1041 return GetNode(&TvItem
);
1045 CDeviceView::EmptyLists()
1049 while (!m_ClassNodeList
.IsEmpty())
1051 Node
= m_ClassNodeList
.RemoveTail();
1055 while (!m_DeviceNodeList
.IsEmpty())
1057 Node
= m_DeviceNodeList
.RemoveTail();
1063 CDeviceView::RefreshDeviceList()
1066 CClassNode
*ClassNode
;
1067 CDeviceNode
*DeviceNode
;
1069 SP_DEVINFO_DATA DeviceInfoData
;
1073 ULONG ClassIndex
= 0;
1077 if (m_RootNode
) delete m_RootNode
;
1078 m_RootNode
= new CRootNode(&m_ImageListData
);
1079 m_RootNode
->SetupNode();
1080 // Loop through all the classes
1083 Success
= GetNextClass(ClassIndex
, &ClassGuid
, &hDevInfo
);
1086 // Create a new class node and add it to the list
1087 ClassNode
= new CClassNode(&ClassGuid
, &m_ImageListData
);
1088 if (ClassNode
->SetupNode())
1090 m_ClassNodeList
.AddTail(ClassNode
);
1093 SetupDiDestroyDeviceInfoList(hDevInfo
);
1099 // Get all the devices on the local machine
1100 hDevInfo
= SetupDiGetClassDevsW(NULL
,
1103 DIGCF_PRESENT
| DIGCF_ALLCLASSES
);
1104 if (hDevInfo
== INVALID_HANDLE_VALUE
)
1109 // loop though all the devices
1110 DeviceInfoData
.cbSize
= sizeof(SP_DEVINFO_DATA
);
1113 // Get the devinst for this device
1114 Success
= SetupDiEnumDeviceInfo(hDevInfo
, i
, &DeviceInfoData
);
1115 if (Success
== FALSE
) break;
1117 // create a new device node and add it to the list
1118 DeviceNode
= new CDeviceNode(DeviceInfoData
.DevInst
, &m_ImageListData
);
1119 if (DeviceNode
->SetupNode())
1121 m_DeviceNodeList
.AddTail(DeviceNode
);
1125 SetupDiDestroyDeviceInfoList(hDevInfo
);