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