[DEVMGR]
[reactos.git] / reactos / dll / win32 / devmgr / devmgmt / DeviceView.cpp
1 /*
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>
7 *
8 */
9
10
11 #include "stdafx.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
21 INT_PTR
22 WINAPI
23 DevicePropertiesExW(
24 IN HWND hWndParent OPTIONAL,
25 IN LPCWSTR lpMachineName OPTIONAL,
26 IN LPCWSTR lpDeviceID OPTIONAL,
27 IN DWORD dwFlags OPTIONAL,
28 IN BOOL bShowDevMgr
29 );
30
31 typedef INT_PTR(WINAPI *pDevicePropertiesExW)(HWND,LPCWSTR,LPCWSTR,DWORD,BOOL);
32
33 struct RefreshThreadData
34 {
35 CDeviceView *This;
36 BOOL ScanForChanges;
37 BOOL UpdateView;
38 };
39
40
41 /* PUBLIC METHODS *************************************/
42
43 CDeviceView::CDeviceView(
44 HWND hMainWnd
45 ) :
46 m_hMainWnd(hMainWnd),
47 m_hTreeView(NULL),
48 m_hPropertyDialog(NULL),
49 m_hMenu(NULL),
50 m_hContextMenu(NULL),
51 m_ViewType(DevicesByType),
52 m_ShowHidden(FALSE),
53 m_RootClassImage(-1),
54 m_RootDevInst(0)
55 {
56 ZeroMemory(&m_ImageListData, sizeof(SP_CLASSIMAGELIST_DATA));
57 }
58
59 CDeviceView::~CDeviceView(void)
60 {
61 }
62
63 bool
64 CDeviceView::Initialize()
65 {
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;
70
71 // Create the main treeview
72 m_hTreeView = CreateWindowExW(WS_EX_CLIENTEDGE,
73 WC_TREEVIEW,
74 NULL,
75 WS_CHILD | WS_VISIBLE | WS_BORDER | TVS_HASLINES |
76 TVS_HASBUTTONS | TVS_SHOWSELALWAYS | TVS_LINESATROOT,
77 0, 0, 0, 0,
78 m_hMainWnd,
79 (HMENU)IDC_TREEVIEW,
80 g_hInstance,
81 NULL);
82 if (m_hTreeView)
83 {
84 // Set the image list against the treeview
85 (void)TreeView_SetImageList(m_hTreeView,
86 m_ImageListData.ImageList,
87 TVSIL_NORMAL);
88
89 // Give the treeview arrows instead of +/- boxes (on Win7)
90 SetWindowTheme(m_hTreeView, L"explorer", NULL);
91 }
92
93 // Create the context menu and make properties the default item
94 m_hMenu = LoadMenuW(g_hInstance, MAKEINTRESOURCEW(IDR_POPUP));
95 m_hContextMenu = GetSubMenu(m_hMenu, 0);
96 SetMenuDefaultItem(m_hContextMenu, IDC_PROPERTIES, FALSE);
97
98 return !!(m_hTreeView);
99 }
100
101 bool
102 CDeviceView::Uninitialize()
103 {
104 EmptyDeviceView();
105
106 if (m_ImageListData.ImageList != NULL)
107 {
108 SetupDiDestroyClassImageList(&m_ImageListData);
109 ZeroMemory(&m_ImageListData, sizeof(SP_CLASSIMAGELIST_DATA));
110 }
111
112 DestroyMenu(m_hMenu);
113
114 return true;
115 }
116
117 LRESULT
118 CDeviceView::OnSize(
119 _In_ int x,
120 _In_ int y,
121 _In_ int cx,
122 _In_ int cy
123 )
124 {
125 // Resize the treeview
126 SetWindowPos(m_hTreeView,
127 NULL,
128 x,
129 y,
130 cx,
131 cy,
132 SWP_NOZORDER);
133
134 return 0;
135 }
136
137 LRESULT
138 CDeviceView::OnRightClick(
139 _In_ LPNMHDR NmHdr
140 )
141 {
142 HTREEITEM hItem = TreeView_GetNextItem(NmHdr->hwndFrom, 0, TVGN_DROPHILITE);
143 if (hItem)
144 {
145 TreeView_SelectItem(NmHdr->hwndFrom, hItem);
146 }
147
148 return 0;
149 }
150
151 LRESULT
152 CDeviceView::OnContextMenu(
153 _In_ LPARAM lParam
154 )
155 {
156 HTREEITEM hSelected = TreeView_GetSelection(m_hTreeView);
157
158 RECT rc;
159 if (TreeView_GetItemRect(m_hTreeView,
160 hSelected,
161 &rc,
162 TRUE))
163 {
164 POINT pt;
165 if (GetCursorPos(&pt) &&
166 ScreenToClient(m_hTreeView, &pt) &&
167 PtInRect(&rc, pt))
168 {
169 INT xPos = GET_X_LPARAM(lParam);
170 INT yPos = GET_Y_LPARAM(lParam);
171
172 TrackPopupMenuEx(m_hContextMenu,
173 TPM_RIGHTBUTTON,
174 xPos,
175 yPos,
176 m_hMainWnd,
177 NULL);
178 }
179 }
180
181 return 0;
182 }
183
184
185 void
186 CDeviceView::Refresh(
187 _In_ ViewType Type,
188 _In_ bool ScanForChanges,
189 _In_ bool UpdateView
190 )
191 {
192 // Enum devices on a seperate thread to keep the gui responsive
193
194 m_ViewType = Type;
195
196 RefreshThreadData *ThreadData;
197 ThreadData = new RefreshThreadData();
198 ThreadData->This = this;
199 ThreadData->ScanForChanges = ScanForChanges;
200 ThreadData->UpdateView = UpdateView;
201
202 HANDLE hThread;
203 hThread = (HANDLE)_beginthreadex(NULL,
204 0,
205 &RefreshThread,
206 ThreadData,
207 0,
208 NULL);
209
210 if (hThread) CloseHandle(hThread);
211 }
212
213 void
214 CDeviceView::DisplayPropertySheet()
215 {
216 //
217 // In ReactOS we can link to DevicePropertiesEx but
218 // not in windows as it's not part of the SDK
219
220 #ifndef __REACTOS__
221 HMODULE hModule = LoadLibraryW(L"devmgr.dll");
222 if (hModule == NULL) return;
223
224 pDevicePropertiesExW DevicePropertiesExW;
225 DevicePropertiesExW = (pDevicePropertiesExW)GetProcAddress(hModule,
226 "DevicePropertiesExW");
227 if (DevicePropertiesExW == NULL)
228 {
229 FreeLibrary(hModule);
230 return;
231 }
232 #endif
233
234 CNode *Node = GetSelectedNode();
235 if (Node && Node->HasProperties())
236 {
237 DevicePropertiesExW(m_hTreeView,
238 NULL,
239 Node->GetDeviceId(),
240 1,//DPF_EXTENDED,
241 FALSE);
242 }
243
244 #ifndef __REACTOS__
245 FreeLibrary(hModule);
246 #endif
247 }
248
249 void
250 CDeviceView::SetFocus()
251 {
252 }
253
254 bool
255 CDeviceView::HasProperties(
256 _In_ LPTV_ITEMW TvItem
257 )
258 {
259 CNode *Node = GetNode(TvItem);
260 if (Node)
261 {
262 return Node->HasProperties();
263 }
264 return false;
265 }
266
267 bool
268 CDeviceView::IsDisabled(
269 _In_ LPTV_ITEMW TvItem
270 )
271 {
272 CNode *Node = GetNode(TvItem);
273 if (Node)
274 {
275 return Node->IsDisabled();
276 }
277 return false;
278 }
279
280 bool
281 CDeviceView::CanDisable(
282 _In_ LPTV_ITEMW TvItem
283 )
284 {
285 CNode *Node = GetNode(TvItem);
286 if (Node)
287 {
288 return Node->CanDisable();
289 }
290 return false;
291 }
292
293
294 /* PRIVATE METHODS ********************************************/
295
296 bool
297 CDeviceView::AddRootDevice()
298 {
299 // Check whether we've loaded the root bitmap into the imagelist (done on first run)
300 if (m_RootClassImage == -1)
301 {
302 // Load the bitmap we'll be using as the root image
303 HBITMAP hRootImage;
304 hRootImage = LoadBitmapW(g_hInstance,
305 MAKEINTRESOURCEW(IDB_ROOT_IMAGE));
306 if (hRootImage == NULL) return FALSE;
307
308 // Add this bitmap to the device image list. This is a bit hacky, but it's safe
309 m_RootClassImage = ImageList_Add(m_ImageListData.ImageList,
310 hRootImage,
311 NULL);
312 DeleteObject(hRootImage);
313 }
314
315 /* Get the root instance */
316 CONFIGRET cr;
317 cr = CM_Locate_DevNodeW(&m_RootDevInst,
318 NULL,
319 CM_LOCATE_DEVNODE_NORMAL);
320 if (cr != CR_SUCCESS)
321 {
322 return false;
323 }
324
325 /* The root name is the computer name */
326 WCHAR RootDeviceName[ROOT_NAME_SIZE];
327 DWORD Size = ROOT_NAME_SIZE;
328 if (GetComputerNameW(RootDeviceName, &Size))
329 _wcslwr_s(RootDeviceName);
330
331 TV_ITEMW tvi;
332 TV_INSERTSTRUCT tvins;
333 ZeroMemory(&tvi, sizeof(tvi));
334 ZeroMemory(&tvins, sizeof(tvins));
335
336 // Insert the root / parent item into our treeview
337 tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
338 tvi.pszText = RootDeviceName;
339 tvi.cchTextMax = wcslen(RootDeviceName);
340 tvi.iImage = m_RootClassImage;
341 tvi.iSelectedImage = m_RootClassImage;
342 tvins.item = tvi;
343 m_hTreeRoot = TreeView_InsertItem(m_hTreeView, &tvins);
344
345 return (m_hTreeRoot != NULL);
346
347 }
348
349 bool
350 CDeviceView::GetNextClass(_In_ ULONG ClassIndex,
351 _Out_ LPGUID ClassGuid,
352 _Out_ HDEVINFO *hDevInfo)
353 {
354 CONFIGRET cr;
355
356 // Get the next class in the list
357 cr = CM_Enumerate_Classes(ClassIndex,
358 ClassGuid,
359 0);
360 if (cr != CR_SUCCESS) return false;
361
362 // Check for devices without a class
363 if (IsEqualGUID(*ClassGuid, GUID_DEVCLASS_UNKNOWN))
364 {
365 // Get device info for all devices for all classes
366 *hDevInfo = SetupDiGetClassDevsW(NULL,
367 NULL,
368 NULL,
369 DIGCF_ALLCLASSES);
370 }
371 else
372 {
373 // We only want the devices for this class
374 *hDevInfo = SetupDiGetClassDevsW(ClassGuid,
375 NULL,
376 NULL,
377 DIGCF_PRESENT);
378
379 }
380
381 return (hDevInfo != INVALID_HANDLE_VALUE);
382 }
383
384 unsigned int __stdcall CDeviceView::RefreshThread(void *Param)
385 {
386 RefreshThreadData *ThreadData = (RefreshThreadData *)Param;
387 CDeviceView *This = ThreadData->This;
388
389
390 // Empty the treeview
391 This->EmptyDeviceView();
392 This->m_hTreeRoot = NULL;
393
394 // Refresh the devices only if requested. This means
395 // switching views uses the cache and remains fast
396 if (ThreadData->ScanForChanges)
397 {
398 This->RefreshDeviceList();
399 }
400
401 // display the type of view the user wants
402 switch (This->m_ViewType)
403 {
404 case DevicesByType:
405 (void)This->ListDevicesByType();
406 break;
407
408 case DevicesByConnection:
409 (VOID)This->ListDevicesByConnection();
410 break;
411
412 case ResourcesByType:
413 break;
414
415 case ResourcesByConnection:
416 break;
417 }
418
419 delete ThreadData;
420
421 return 0;
422 }
423
424
425 bool
426 CDeviceView::ListDevicesByType()
427 {
428 CNode *ClassNode, *DeviceNode;
429 HDEVINFO hDevInfo;
430 HTREEITEM hTreeItem = NULL;
431 GUID ClassGuid;
432 INT ClassIndex;
433 LPTSTR DeviceId = NULL;
434 BOOL bClassSuccess, bSuccess;
435
436 // Start by adding the root node to the tree
437 bSuccess = AddRootDevice();
438 if (bSuccess == false) return false;
439
440 ClassIndex = 0;
441 do
442 {
443 // Loop through all the device classes
444 bClassSuccess = GetNextClass(ClassIndex, &ClassGuid, &hDevInfo);
445 if (bClassSuccess)
446 {
447 bool bClassUnknown = false;
448 bool AddedParent = false;
449 INT DeviceIndex = 0;
450 BOOL MoreItems;
451
452 // Get the cached class node
453 ClassNode = GetClassNode(&ClassGuid);
454 if (ClassNode == NULL)
455 {
456 ATLASSERT(FALSE);
457 ClassIndex++;
458 continue;
459 }
460
461 // Set a flag is this is the (special case) unknown class
462 if (IsEqualGUID(ClassGuid, GUID_DEVCLASS_UNKNOWN))
463 bClassUnknown = true;
464
465 do
466 {
467 // Get a handle to all the devices in this class
468 SP_DEVINFO_DATA DeviceInfoData;
469 ZeroMemory(&DeviceInfoData, sizeof(SP_DEVINFO_DATA));
470 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
471 bSuccess = SetupDiEnumDeviceInfo(hDevInfo,
472 DeviceIndex,
473 &DeviceInfoData);
474 if (bSuccess == FALSE && GetLastError() == ERROR_NO_MORE_ITEMS)
475 MoreItems = FALSE;
476
477 if (bSuccess)
478 {
479 MoreItems = TRUE;
480
481 // The unknown class handle contains all devices on the system,
482 // and we're just looking for the ones with a null GUID
483 if (bClassUnknown)
484 {
485 if (IsEqualGUID(DeviceInfoData.ClassGuid, GUID_NULL) == FALSE)
486 {
487 // This is a known device, we aren't interested in it
488 DeviceIndex++;
489 continue;
490 }
491 }
492
493 // Get the cached device node
494 DeviceNode = GetDeviceNode(DeviceInfoData.DevInst);
495 if (DeviceNode == NULL)
496 {
497 ATLASSERT(bClassUnknown == true);
498 DeviceIndex++;
499 continue;
500 }
501
502 // Check if this is a hidden device
503 if (DeviceNode->IsHidden())
504 {
505 // Ignore this device if we aren't displaying hidden devices
506 if (m_ShowHidden == FALSE)
507 {
508 DeviceIndex++;
509 continue;
510 }
511 }
512
513 // We have a device, we need to add the parent if it hasn't yet been added
514 if (AddedParent == false)
515 {
516 // Insert the new class under the root item
517 hTreeItem = InsertIntoTreeView(m_hTreeRoot,
518 ClassNode);
519 AddedParent = true;
520 }
521
522 // Add the device under the class item node
523 (void)InsertIntoTreeView(hTreeItem, DeviceNode);
524
525 // Expand the class if it has a problem device
526 if (DeviceNode->HasProblem())
527 {
528 (void)TreeView_Expand(m_hTreeView,
529 hTreeItem,
530 TVE_EXPAND);
531 }
532 }
533
534 DeviceIndex++;
535
536 } while (MoreItems);
537
538 // If this class has devices, sort them alphabetically
539 if (AddedParent == true)
540 {
541 (void)TreeView_SortChildren(m_hTreeView,
542 hTreeItem,
543 0);
544 }
545 }
546
547 ClassIndex++;
548
549 } while (bClassSuccess);
550
551 // Sort the classes alphabetically
552 (void)TreeView_SortChildren(m_hTreeView,
553 m_hTreeRoot,
554 0);
555
556 // Expand the root item
557 (void)TreeView_Expand(m_hTreeView,
558 m_hTreeRoot,
559 TVE_EXPAND);
560
561 // Pre-select the root item
562 (VOID)TreeView_SelectItem(m_hTreeView,
563 m_hTreeRoot);
564
565 return 0;
566 }
567
568 bool
569 CDeviceView::ListDevicesByConnection()
570 {
571 BOOL bSuccess;
572
573 // Start by adding the root node to the tree
574 bSuccess = AddRootDevice();
575 if (bSuccess == false) return false;
576
577 /* Walk the device tree and add all the devices */
578 RecurseChildDevices(m_RootDevInst, m_hTreeRoot);
579
580 /* Expand the root item */
581 (VOID)TreeView_Expand(m_hTreeView,
582 m_hTreeRoot,
583 TVE_EXPAND);
584
585 return true;
586 }
587
588 VOID
589 CDeviceView::RecurseChildDevices(
590 _In_ DEVINST ParentDevice,
591 _In_ HTREEITEM hParentTreeItem
592 )
593 {
594
595 HTREEITEM hDevItem = NULL;
596 DEVINST Device;
597 BOOL bSuccess;
598
599 /* Check if the parent has any child devices */
600 if (GetChildDevice(ParentDevice, &Device) == FALSE)
601 return;
602
603 // Get the cached device node
604 CNode *DeviceNode;
605 DeviceNode = GetDeviceNode(Device);
606 if (DeviceNode == NULL)
607 {
608 ATLASSERT(FALSE);
609 return;
610 }
611
612
613 /* Check if this is a hidden device */
614 if ((m_ShowHidden == TRUE) || (!(DeviceNode->IsHidden())))
615 {
616 /* Add this device to the tree under its parent */
617 hDevItem = InsertIntoTreeView(hParentTreeItem,
618 DeviceNode);
619
620
621 if (hDevItem)
622 {
623 /* Check if this child has any children itself */
624 RecurseChildDevices(Device, hDevItem);
625 }
626 }
627
628
629 for (;;)
630 {
631 /* Check if the parent device has anything at the same level */
632 bSuccess = GetSiblingDevice(Device, &Device);
633 if (bSuccess == FALSE) break;
634
635 DeviceNode = GetDeviceNode(Device);
636 if (DeviceNode == NULL)
637 {
638 ATLASSERT(FALSE);
639 }
640
641 /* Check if this is a hidden device */
642 if (DeviceNode->IsHidden())
643 {
644 if (m_ShowHidden == FALSE)
645 continue;
646 }
647
648 /* Add this device to the tree under its parent */
649 hDevItem = InsertIntoTreeView(hParentTreeItem,
650 DeviceNode);
651 if (hDevItem)
652 {
653 /* Check if this child has any children itself */
654 RecurseChildDevices(Device, hDevItem);
655 }
656 }
657
658 (void)TreeView_SortChildren(m_hTreeView,
659 hParentTreeItem,
660 0);
661
662 }
663
664 bool
665 CDeviceView::GetChildDevice(
666 _In_ DEVINST ParentDevInst,
667 _Out_ PDEVINST DevInst
668 )
669 {
670 CONFIGRET cr;
671 cr = CM_Get_Child(DevInst,
672 ParentDevInst,
673 0);
674 return (cr == CR_SUCCESS);
675 }
676
677 bool
678 CDeviceView::GetSiblingDevice(
679 _In_ DEVINST PrevDevice,
680 _Out_ PDEVINST DevInst
681 )
682 {
683 CONFIGRET cr;
684 cr = CM_Get_Sibling(DevInst,
685 PrevDevice,
686 0);
687 return (cr == CR_SUCCESS);
688 }
689
690 HTREEITEM
691 CDeviceView::InsertIntoTreeView(
692 _In_ HTREEITEM hParent,
693 _In_ CNode *Node
694 )
695 {
696
697 LPWSTR lpLabel;
698 lpLabel = Node->GetDisplayName();
699
700 TV_ITEMW tvi;
701 TV_INSERTSTRUCT tvins;
702 ZeroMemory(&tvi, sizeof(tvi));
703 ZeroMemory(&tvins, sizeof(tvins));
704
705 tvi.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
706 tvi.pszText = lpLabel;
707 tvi.cchTextMax = wcslen(lpLabel);
708 tvi.lParam = (LPARAM)Node;
709 tvi.iImage = Node->GetClassImage();
710 tvi.iSelectedImage = Node->GetClassImage();
711
712 if (Node->GetOverlayImage())
713 {
714 tvi.mask |= TVIF_STATE;
715 tvi.stateMask = TVIS_OVERLAYMASK;
716 tvi.state = INDEXTOOVERLAYMASK(Node->GetOverlayImage());
717 }
718
719 tvins.item = tvi;
720 tvins.hParent = hParent;
721
722 return TreeView_InsertItem(m_hTreeView, &tvins);
723 }
724
725 void
726 CDeviceView::RecurseDeviceView(
727 _In_ HTREEITEM hParentItem
728 )
729 {
730 HTREEITEM hItem;
731 TVITEMW tvItem;
732
733 // Check if this node has any children
734 hItem = TreeView_GetChild(m_hTreeView, hParentItem);
735 if (hItem == NULL) return;
736
737 // The lParam contains the node pointer data
738 tvItem.hItem = hItem;
739 tvItem.mask = TVIF_PARAM;
740 if (TreeView_GetItem(m_hTreeView, &tvItem) &&
741 tvItem.lParam != NULL)
742 {
743 // Delete the node class
744 //delete reinterpret_cast<CNode *>(tvItem.lParam);
745 }
746
747 // This node may have its own children
748 RecurseDeviceView(hItem);
749
750 // Delete all the siblings
751 for (;;)
752 {
753 // Get the next item at this level
754 hItem = TreeView_GetNextSibling(m_hTreeView, hItem);
755 if (hItem == NULL) break;
756
757 // The lParam contains the node pointer data
758 tvItem.hItem = hItem;
759 tvItem.mask = TVIF_PARAM;
760 if (TreeView_GetItem(m_hTreeView, &tvItem))
761 {
762 //if (tvItem.lParam != NULL)
763 // delete reinterpret_cast<CNode *>(tvItem.lParam);
764 }
765
766 /* This node may have its own children */
767 RecurseDeviceView(hItem);
768 }
769 }
770
771
772 void
773 CDeviceView::EmptyDeviceView()
774 {
775 HTREEITEM hItem;
776
777 // Check if there are any items in the tree
778 hItem = TreeView_GetRoot(m_hTreeView);
779 if (hItem == NULL) return;
780
781 // Free all the class nodes
782 //RecurseDeviceView(hItem);
783
784 // Delete all the items
785 (VOID)TreeView_DeleteAllItems(m_hTreeView);
786 }
787
788
789
790
791 CNode*
792 CDeviceView::GetClassNode(_In_ LPGUID ClassGuid)
793 {
794 POSITION Pos;
795 CNode *Node;
796
797 Pos = m_ClassNodeList.GetHeadPosition();
798
799 do
800 {
801 Node = m_ClassNodeList.GetNext(Pos);
802 if (IsEqualGUID(*Node->GetClassGuid(), *ClassGuid))
803 {
804 //ATLASSERT(Node->GetType() == NodeClass);
805 break;
806 }
807
808 Node = NULL;
809
810 } while (Pos != NULL);
811
812 return Node;
813 }
814
815 CNode*
816 CDeviceView::GetDeviceNode(_In_ DEVINST Device)
817 {
818 POSITION Pos;
819 CNode *Node;
820
821 Pos = m_DeviceNodeList.GetHeadPosition();
822
823 do
824 {
825 Node = m_DeviceNodeList.GetNext(Pos);
826 if (Node->GetDeviceInst() == Device)
827 {
828 //ATLASSERT(Node->GetType() == NodeDevice);
829 break;
830 }
831
832 Node = NULL;
833
834 } while (Pos != NULL);
835
836 return Node;
837 }
838
839 CNode* CDeviceView::GetNode(LPTV_ITEMW TvItem)
840 {
841 TvItem->mask = TVIF_PARAM;
842 if (TreeView_GetItem(m_hTreeView, TvItem))
843 {
844 return (CNode *)TvItem->lParam;
845 }
846 }
847
848 CNode* CDeviceView::GetSelectedNode()
849 {
850 TV_ITEM TvItem;
851 TvItem.hItem = TreeView_GetSelection(m_hTreeView);
852 return GetNode(&TvItem);
853 }
854
855 void
856 CDeviceView::EmptyLists()
857 {
858 POSITION Pos;
859 CNode *Node;
860
861 if (!m_ClassNodeList.IsEmpty())
862 {
863 Pos = m_ClassNodeList.GetHeadPosition();
864 do
865 {
866 Node = m_ClassNodeList.GetNext(Pos);
867 delete Node;
868
869 } while (Pos != NULL);
870 }
871
872 if (!m_DeviceNodeList.IsEmpty())
873 {
874 Pos = m_DeviceNodeList.GetHeadPosition();
875 do
876 {
877 Node = m_DeviceNodeList.GetNext(Pos);
878 delete Node;
879
880 } while (Pos != NULL);
881 }
882 }
883
884 bool
885 CDeviceView::RefreshDeviceList()
886 {
887 GUID ClassGuid;
888 CNode *Node;
889 HDEVINFO hDevInfo;
890 SP_DEVINFO_DATA DeviceInfoData;
891 DWORD i;
892 BOOL Success;
893
894 ULONG ClassIndex = 0;
895
896 EmptyLists();
897
898 do
899 {
900 Success = GetNextClass(ClassIndex, &ClassGuid, &hDevInfo);
901 if (Success)
902 {
903 /* Create a new class node */
904 Node = new CNode(&ClassGuid, &m_ImageListData);
905 if (Node->Setup())
906 {
907 m_ClassNodeList.AddTail(Node);
908 }
909 }
910 ClassIndex++;
911 } while (Success);
912
913
914 hDevInfo = SetupDiGetClassDevsW(NULL,
915 0,
916 0,
917 DIGCF_PRESENT | DIGCF_ALLCLASSES);
918 if (hDevInfo == INVALID_HANDLE_VALUE)
919 {
920 return false;
921 }
922
923
924 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
925 for (i = 0;; i++)
926 {
927 Success = SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData);
928 if (Success == FALSE) break;
929
930
931 Node = new CNode(DeviceInfoData.DevInst, &m_ImageListData);
932 Node->Setup();
933 m_DeviceNodeList.AddTail(Node);
934 }
935
936 SetupDiDestroyDeviceInfoList(hDevInfo);
937
938 return TRUE;
939 }