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