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::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 LPTSTR DeviceId
= NULL
;
462 BOOL bClassSuccess
, bSuccess
;
464 // Start by adding the root node to the tree
465 bSuccess
= AddRootDevice();
466 if (bSuccess
== false) return false;
471 // Loop through all the device classes
472 bClassSuccess
= GetNextClass(ClassIndex
, &ClassGuid
, &hDevInfo
);
475 bool bClassUnknown
= false;
476 bool AddedParent
= false;
480 // Get the cached class node
481 ClassNode
= GetClassNode(&ClassGuid
);
482 if (ClassNode
== NULL
)
489 // Set a flag is this is the (special case) unknown class
490 if (IsEqualGUID(ClassGuid
, GUID_DEVCLASS_UNKNOWN
))
491 bClassUnknown
= true;
495 // Get a handle to all the devices in this class
496 SP_DEVINFO_DATA DeviceInfoData
;
497 ZeroMemory(&DeviceInfoData
, sizeof(SP_DEVINFO_DATA
));
498 DeviceInfoData
.cbSize
= sizeof(SP_DEVINFO_DATA
);
499 bSuccess
= SetupDiEnumDeviceInfo(hDevInfo
,
502 if (bSuccess
== FALSE
&& GetLastError() == ERROR_NO_MORE_ITEMS
)
509 // The unknown class handle contains all devices on the system,
510 // and we're just looking for the ones with a null GUID
513 if (IsEqualGUID(DeviceInfoData
.ClassGuid
, GUID_NULL
) == FALSE
)
515 // This is a known device, we aren't interested in it
521 // Get the cached device node
522 DeviceNode
= GetDeviceNode(DeviceInfoData
.DevInst
);
523 if (DeviceNode
== NULL
)
525 ATLASSERT(bClassUnknown
== true);
530 // Check if this is a hidden device
531 if (DeviceNode
->IsHidden())
533 // Ignore this device if we aren't displaying hidden devices
534 if (m_ShowHidden
== FALSE
)
541 // We have a device, we need to add the parent if it hasn't yet been added
542 if (AddedParent
== false)
544 // Insert the new class under the root item
545 hTreeItem
= InsertIntoTreeView(m_hTreeRoot
,
550 // Add the device under the class item node
551 (void)InsertIntoTreeView(hTreeItem
, DeviceNode
);
553 // Expand the class if it has a problem device
554 if (DeviceNode
->HasProblem())
556 (void)TreeView_Expand(m_hTreeView
,
566 // If this class has devices, sort them alphabetically
567 if (AddedParent
== true)
569 (void)TreeView_SortChildren(m_hTreeView
,
577 } while (bClassSuccess
);
579 // Sort the classes alphabetically
580 (void)TreeView_SortChildren(m_hTreeView
,
584 // Expand the root item
585 (void)TreeView_Expand(m_hTreeView
,
589 // Pre-select the root item
590 (VOID
)TreeView_SelectItem(m_hTreeView
,
597 CDeviceView::ListDevicesByConnection()
601 // Start by adding the root node to the tree
602 bSuccess
= AddRootDevice();
603 if (bSuccess
== false) return false;
605 // Walk the device tree and add all the devices
606 (void)RecurseChildDevices(m_RootNode
->GetDeviceInst(), m_hTreeRoot
);
608 // Expand the root item
609 (void)TreeView_Expand(m_hTreeView
,
617 CDeviceView::RecurseChildDevices(
618 _In_ DEVINST ParentDevice
,
619 _In_ HTREEITEM hParentTreeItem
622 HTREEITEM hDevItem
= NULL
;
624 bool HasProblem
= false;
627 // Check if the parent has any child devices
628 if (GetChildDevice(ParentDevice
, &Device
) == FALSE
)
631 // Get the cached device node
632 CDeviceNode
*DeviceNode
;
633 DeviceNode
= dynamic_cast<CDeviceNode
*>(GetDeviceNode(Device
));
634 if (DeviceNode
== nullptr)
640 // Don't show hidden devices if not requested
641 if ((m_ShowHidden
== TRUE
) || (!(DeviceNode
->IsHidden())))
643 // Add this device to the tree under its parent
644 hDevItem
= InsertIntoTreeView(hParentTreeItem
,
648 // Check if this child has any children itself
649 if (!RecurseChildDevices(Device
, hDevItem
))
653 if (DeviceNode
->HasProblem())
660 // Check for siblings
663 // Check if the parent device has anything at the same level
664 bSuccess
= GetSiblingDevice(Device
, &Device
);
665 if (bSuccess
== FALSE
) break;
667 DeviceNode
= dynamic_cast<CDeviceNode
*>(GetDeviceNode(Device
));
668 if (DeviceNode
== nullptr)
673 // Don't show hidden devices if not requested
674 if ((m_ShowHidden
== TRUE
) || (!(DeviceNode
->IsHidden())))
676 if (DeviceNode
->HasProblem())
681 // Add this device to the tree under its parent
682 hDevItem
= InsertIntoTreeView(hParentTreeItem
,
686 // Check if this child has any children itself
687 if (!RecurseChildDevices(Device
, hDevItem
))
693 (void)TreeView_SortChildren(m_hTreeView
,
697 // Expand the class if it has a problem device
698 if (HasProblem
== true)
700 (void)TreeView_Expand(m_hTreeView
,
705 // If there was a problem, expand the ancestors
706 if (HasProblem
) return false;
712 CDeviceView::EnableSelectedDevice(
714 _Out_
bool &NeedsReboot
717 CDeviceNode
*Node
= dynamic_cast<CDeviceNode
*>(GetSelectedNode());
718 if (Node
== nullptr) return false;
723 if (str
.LoadStringW(g_hInstance
, IDS_CONFIRM_DISABLE
))
725 if (MessageBoxW(m_hMainWnd
,
727 Node
->GetDisplayName(),
728 MB_YESNO
| MB_ICONWARNING
| MB_DEFBUTTON2
) != IDYES
)
735 if (Node
->EnableDevice(Enable
, NeedsReboot
))
737 Refresh(m_ViewType
, true, true, Node
->GetDeviceId());
745 CDeviceView::UninstallSelectedDevice(
748 CDeviceNode
*Node
= dynamic_cast<CDeviceNode
*>(GetSelectedNode());
749 if (Node
== nullptr) return false;
751 return Node
->UninstallDevice();
755 CDeviceView::GetChildDevice(
756 _In_ DEVINST ParentDevInst
,
757 _Out_ PDEVINST DevInst
761 cr
= CM_Get_Child(DevInst
,
764 return (cr
== CR_SUCCESS
);
768 CDeviceView::GetSiblingDevice(
769 _In_ DEVINST PrevDevice
,
770 _Out_ PDEVINST DevInst
774 cr
= CM_Get_Sibling(DevInst
,
777 return (cr
== CR_SUCCESS
);
781 CDeviceView::InsertIntoTreeView(
782 _In_opt_ HTREEITEM hParent
,
787 lpLabel
= Node
->GetDisplayName();
790 TV_INSERTSTRUCT tvins
;
791 ZeroMemory(&tvi
, sizeof(tvi
));
792 ZeroMemory(&tvins
, sizeof(tvins
));
794 tvi
.mask
= TVIF_TEXT
| TVIF_PARAM
| TVIF_IMAGE
| TVIF_SELECTEDIMAGE
;
795 tvi
.pszText
= lpLabel
;
796 tvi
.cchTextMax
= wcslen(lpLabel
);
797 tvi
.lParam
= (LPARAM
)Node
;
798 tvi
.iImage
= Node
->GetClassImage();
799 tvi
.iSelectedImage
= Node
->GetClassImage();
801 // try to cast it to a device node. This will only suceed if it's the correct type
802 CDeviceNode
*DeviceNode
= dynamic_cast<CDeviceNode
*>(Node
);
803 if (DeviceNode
&& DeviceNode
->GetOverlayImage())
805 tvi
.mask
|= TVIF_STATE
;
806 tvi
.stateMask
= TVIS_OVERLAYMASK
;
807 tvi
.state
= INDEXTOOVERLAYMASK(DeviceNode
->GetOverlayImage());
811 tvins
.hParent
= hParent
;
813 return TreeView_InsertItem(m_hTreeView
, &tvins
);
817 CDeviceView::BuildActionMenuForNode(
818 _In_ HMENU OwnerMenu
,
823 // Create a seperator structure
824 MENUITEMINFOW MenuSeperator
= { 0 };
825 MenuSeperator
.cbSize
= sizeof(MENUITEMINFOW
);
826 MenuSeperator
.fType
= MFT_SEPARATOR
;
829 MENUITEMINFOW MenuItemInfo
= { 0 };
830 MenuItemInfo
.cbSize
= sizeof(MENUITEMINFOW
);
831 MenuItemInfo
.fMask
= MIIM_ID
| MIIM_STRING
| MIIM_DATA
| MIIM_SUBMENU
;
832 MenuItemInfo
.fType
= MFT_STRING
;
837 // Device nodes have extra data
838 if (Node
->GetNodeType() == DeviceNode
)
840 CDeviceNode
*DeviceNode
= dynamic_cast<CDeviceNode
*>(Node
);
842 if (DeviceNode
->CanUpdate())
844 String
.LoadStringW(g_hInstance
, IDS_MENU_UPDATE
);
845 MenuItemInfo
.wID
= IDC_UPDATE_DRV
;
846 MenuItemInfo
.dwTypeData
= String
.GetBuffer();
847 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuItemInfo
);
851 if (DeviceNode
->IsDisabled())
853 String
.LoadStringW(g_hInstance
, IDS_MENU_ENABLE
);
854 MenuItemInfo
.wID
= IDC_ENABLE_DRV
;
855 MenuItemInfo
.dwTypeData
= String
.GetBuffer();
856 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuItemInfo
);
860 if (DeviceNode
->CanDisable() && !DeviceNode
->IsDisabled())
862 String
.LoadStringW(g_hInstance
, IDS_MENU_DISABLE
);
863 MenuItemInfo
.wID
= IDC_DISABLE_DRV
;
864 MenuItemInfo
.dwTypeData
= String
.GetBuffer();
865 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuItemInfo
);
869 if (DeviceNode
->CanUninstall())
871 String
.LoadStringW(g_hInstance
, IDS_MENU_UNINSTALL
);
872 MenuItemInfo
.wID
= IDC_UNINSTALL_DRV
;
873 MenuItemInfo
.dwTypeData
= String
.GetBuffer();
874 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuItemInfo
);
878 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuSeperator
);
882 // All nodes have the scan option
883 String
.LoadStringW(g_hInstance
, IDS_MENU_SCAN
);
884 MenuItemInfo
.wID
= IDC_SCAN_HARDWARE
;
885 MenuItemInfo
.dwTypeData
= String
.GetBuffer();
886 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuItemInfo
);
889 if ((Node
->GetNodeType() == RootNode
) || (MainMenu
== true))
891 String
.LoadStringW(g_hInstance
, IDS_MENU_ADD
);
892 MenuItemInfo
.wID
= IDC_ADD_HARDWARE
;
893 MenuItemInfo
.dwTypeData
= String
.GetBuffer();
894 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuItemInfo
);
898 if (Node
->HasProperties())
900 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuSeperator
);
903 String
.LoadStringW(g_hInstance
, IDS_MENU_PROPERTIES
);
904 MenuItemInfo
.wID
= IDC_PROPERTIES
;
905 MenuItemInfo
.dwTypeData
= String
.GetBuffer();
906 InsertMenuItemW(OwnerMenu
, i
, TRUE
, &MenuItemInfo
);
909 SetMenuDefaultItem(OwnerMenu
, IDC_PROPERTIES
, FALSE
);
914 CDeviceView::RecurseFindDevice(
915 _In_ HTREEITEM hParentItem
,
924 // Check if this node has any children
925 hItem
= TreeView_GetChild(m_hTreeView
, hParentItem
);
926 if (hItem
== NULL
) return NULL
;
928 // The lParam contains the node pointer data
929 tvItem
.hItem
= hItem
;
930 tvItem
.mask
= TVIF_PARAM
;
931 if (TreeView_GetItem(m_hTreeView
, &tvItem
) &&
932 tvItem
.lParam
!= NULL
)
934 // check for a matching deviceid
935 Node
= reinterpret_cast<CNode
*>(tvItem
.lParam
);
936 if (Node
->GetDeviceId() &&
937 (wcscmp(Node
->GetDeviceId(), DeviceId
) == 0))
943 // This node may have its own children
944 FoundItem
= RecurseFindDevice(hItem
, DeviceId
);
945 if (FoundItem
) return FoundItem
;
947 // Loop all the siblings
950 // Get the next item at this level
951 hItem
= TreeView_GetNextSibling(m_hTreeView
, hItem
);
952 if (hItem
== NULL
) break;
954 // The lParam contains the node pointer data
955 tvItem
.hItem
= hItem
;
956 tvItem
.mask
= TVIF_PARAM
;
957 if (TreeView_GetItem(m_hTreeView
, &tvItem
))
959 // check for a matching deviceid
960 Node
= reinterpret_cast<CNode
*>(tvItem
.lParam
);
961 if (Node
->GetDeviceId() &&
962 wcscmp(Node
->GetDeviceId(), DeviceId
) == 0)
968 // This node may have its own children
969 FoundItem
= RecurseFindDevice(hItem
, DeviceId
);
970 if (FoundItem
) return FoundItem
;
977 CDeviceView::SelectNode(
981 HTREEITEM hRoot
, hItem
;
983 // Check if there are any items in the tree
984 hRoot
= TreeView_GetRoot(m_hTreeView
);
985 if (hRoot
== NULL
) return;
987 // If we don't want to set select a node, just select root
988 if (DeviceId
== NULL
)
990 TreeView_SelectItem(m_hTreeView
, hRoot
);
994 // Scan the tree looking for the node we want
995 hItem
= RecurseFindDevice(hRoot
, DeviceId
);
998 TreeView_SelectItem(m_hTreeView
, hItem
);
999 TreeView_Expand(m_hTreeView
, hItem
, TVM_EXPAND
);
1003 TreeView_SelectItem(m_hTreeView
, hRoot
);
1009 CDeviceView::EmptyDeviceView()
1011 (VOID
)TreeView_DeleteAllItems(m_hTreeView
);
1016 CDeviceView::GetClassNode(
1017 _In_ LPGUID ClassGuid
1023 Pos
= m_ClassNodeList
.GetHeadPosition();
1027 Node
= m_ClassNodeList
.GetNext(Pos
);
1028 if (IsEqualGUID(*Node
->GetClassGuid(), *ClassGuid
))
1030 //ATLASSERT(Node->GetType() == NodeClass);
1036 } while (Pos
!= NULL
);
1042 CDeviceView::GetDeviceNode(
1049 Pos
= m_DeviceNodeList
.GetHeadPosition();
1053 Node
= m_DeviceNodeList
.GetNext(Pos
);
1054 if (Node
->GetDeviceInst() == Device
)
1056 //ATLASSERT(Node->GetType() == NodeDevice);
1062 } while (Pos
!= NULL
);
1067 CNode
* CDeviceView::GetNode(
1068 _In_ LPTV_ITEMW TvItem
1071 TvItem
->mask
= TVIF_PARAM
;
1072 if (TreeView_GetItem(m_hTreeView
, TvItem
))
1074 return (CNode
*)TvItem
->lParam
;
1080 CDeviceView::EmptyLists()
1084 while (!m_ClassNodeList
.IsEmpty())
1086 Node
= m_ClassNodeList
.RemoveTail();
1090 while (!m_DeviceNodeList
.IsEmpty())
1092 Node
= m_DeviceNodeList
.RemoveTail();
1098 CDeviceView::RefreshDeviceList()
1101 CClassNode
*ClassNode
;
1102 CDeviceNode
*DeviceNode
;
1104 SP_DEVINFO_DATA DeviceInfoData
;
1108 ULONG ClassIndex
= 0;
1112 if (m_RootNode
) delete m_RootNode
;
1113 m_RootNode
= new CRootNode(&m_ImageListData
);
1114 m_RootNode
->SetupNode();
1115 // Loop through all the classes
1118 Success
= GetNextClass(ClassIndex
, &ClassGuid
, &hDevInfo
);
1121 // Create a new class node and add it to the list
1122 ClassNode
= new CClassNode(&ClassGuid
, &m_ImageListData
);
1123 if (ClassNode
->SetupNode())
1125 m_ClassNodeList
.AddTail(ClassNode
);
1128 SetupDiDestroyDeviceInfoList(hDevInfo
);
1134 // Get all the devices on the local machine
1135 hDevInfo
= SetupDiGetClassDevsW(NULL
,
1138 DIGCF_PRESENT
| DIGCF_ALLCLASSES
);
1139 if (hDevInfo
== INVALID_HANDLE_VALUE
)
1144 // loop though all the devices
1145 DeviceInfoData
.cbSize
= sizeof(SP_DEVINFO_DATA
);
1148 // Get the devinst for this device
1149 Success
= SetupDiEnumDeviceInfo(hDevInfo
, i
, &DeviceInfoData
);
1150 if (Success
== FALSE
) break;
1152 // create a new device node and add it to the list
1153 DeviceNode
= new CDeviceNode(DeviceInfoData
.DevInst
, &m_ImageListData
);
1154 if (DeviceNode
->SetupNode())
1156 m_DeviceNodeList
.AddTail(DeviceNode
);
1160 SetupDiDestroyDeviceInfoList(hDevInfo
);