52dd464cd3879d723574c46e18131ff72ab6bd2a
[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 return 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(
352 _In_ ULONG ClassIndex,
353 _Out_ LPGUID ClassGuid,
354 _Out_ HDEVINFO *hDevInfo
355 )
356 {
357 CONFIGRET cr;
358
359 // Get the next class in the list
360 cr = CM_Enumerate_Classes(ClassIndex,
361 ClassGuid,
362 0);
363 if (cr != CR_SUCCESS) return false;
364
365 // Check for devices without a class
366 if (IsEqualGUID(*ClassGuid, GUID_DEVCLASS_UNKNOWN))
367 {
368 // Get device info for all devices for all classes
369 *hDevInfo = SetupDiGetClassDevsW(NULL,
370 NULL,
371 NULL,
372 DIGCF_ALLCLASSES);
373 }
374 else
375 {
376 // We only want the devices for this class
377 *hDevInfo = SetupDiGetClassDevsW(ClassGuid,
378 NULL,
379 NULL,
380 DIGCF_PRESENT);
381
382 }
383
384 return (hDevInfo != INVALID_HANDLE_VALUE);
385 }
386
387 unsigned int __stdcall CDeviceView::RefreshThread(void *Param)
388 {
389 RefreshThreadData *ThreadData = (RefreshThreadData *)Param;
390 CDeviceView *This = ThreadData->This;
391
392
393 // Empty the treeview
394 This->EmptyDeviceView();
395 This->m_hTreeRoot = NULL;
396
397 // Refresh the devices only if requested. This means
398 // switching views uses the cache and remains fast
399 if (ThreadData->ScanForChanges)
400 {
401 This->RefreshDeviceList();
402 }
403
404 // display the type of view the user wants
405 switch (This->m_ViewType)
406 {
407 case DevicesByType:
408 (void)This->ListDevicesByType();
409 break;
410
411 case DevicesByConnection:
412 (VOID)This->ListDevicesByConnection();
413 break;
414
415 case ResourcesByType:
416 break;
417
418 case ResourcesByConnection:
419 break;
420 }
421
422 delete ThreadData;
423
424 return 0;
425 }
426
427
428 bool
429 CDeviceView::ListDevicesByType()
430 {
431 CClassNode *ClassNode;
432 CDeviceNode *DeviceNode;
433 HDEVINFO hDevInfo;
434 HTREEITEM hTreeItem = NULL;
435 GUID ClassGuid;
436 INT ClassIndex;
437 LPTSTR DeviceId = NULL;
438 BOOL bClassSuccess, bSuccess;
439
440 // Start by adding the root node to the tree
441 bSuccess = AddRootDevice();
442 if (bSuccess == false) return false;
443
444 ClassIndex = 0;
445 do
446 {
447 // Loop through all the device classes
448 bClassSuccess = GetNextClass(ClassIndex, &ClassGuid, &hDevInfo);
449 if (bClassSuccess)
450 {
451 bool bClassUnknown = false;
452 bool AddedParent = false;
453 INT DeviceIndex = 0;
454 BOOL MoreItems;
455
456 // Get the cached class node
457 ClassNode = GetClassNode(&ClassGuid);
458 if (ClassNode == NULL)
459 {
460 ATLASSERT(FALSE);
461 ClassIndex++;
462 continue;
463 }
464
465 // Set a flag is this is the (special case) unknown class
466 if (IsEqualGUID(ClassGuid, GUID_DEVCLASS_UNKNOWN))
467 bClassUnknown = true;
468
469 do
470 {
471 // Get a handle to all the devices in this class
472 SP_DEVINFO_DATA DeviceInfoData;
473 ZeroMemory(&DeviceInfoData, sizeof(SP_DEVINFO_DATA));
474 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
475 bSuccess = SetupDiEnumDeviceInfo(hDevInfo,
476 DeviceIndex,
477 &DeviceInfoData);
478 if (bSuccess == FALSE && GetLastError() == ERROR_NO_MORE_ITEMS)
479 MoreItems = FALSE;
480
481 if (bSuccess)
482 {
483 MoreItems = TRUE;
484
485 // The unknown class handle contains all devices on the system,
486 // and we're just looking for the ones with a null GUID
487 if (bClassUnknown)
488 {
489 if (IsEqualGUID(DeviceInfoData.ClassGuid, GUID_NULL) == FALSE)
490 {
491 // This is a known device, we aren't interested in it
492 DeviceIndex++;
493 continue;
494 }
495 }
496
497 // Get the cached device node
498 DeviceNode = GetDeviceNode(DeviceInfoData.DevInst);
499 if (DeviceNode == NULL)
500 {
501 ATLASSERT(bClassUnknown == true);
502 DeviceIndex++;
503 continue;
504 }
505
506 // Check if this is a hidden device
507 if (DeviceNode->IsHidden())
508 {
509 // Ignore this device if we aren't displaying hidden devices
510 if (m_ShowHidden == FALSE)
511 {
512 DeviceIndex++;
513 continue;
514 }
515 }
516
517 // We have a device, we need to add the parent if it hasn't yet been added
518 if (AddedParent == false)
519 {
520 // Insert the new class under the root item
521 hTreeItem = InsertIntoTreeView(m_hTreeRoot,
522 ClassNode);
523 AddedParent = true;
524 }
525
526 // Add the device under the class item node
527 (void)InsertIntoTreeView(hTreeItem, DeviceNode);
528
529 // Expand the class if it has a problem device
530 if (DeviceNode->HasProblem())
531 {
532 (void)TreeView_Expand(m_hTreeView,
533 hTreeItem,
534 TVE_EXPAND);
535 }
536 }
537
538 DeviceIndex++;
539
540 } while (MoreItems);
541
542 // If this class has devices, sort them alphabetically
543 if (AddedParent == true)
544 {
545 (void)TreeView_SortChildren(m_hTreeView,
546 hTreeItem,
547 0);
548 }
549 }
550
551 ClassIndex++;
552
553 } while (bClassSuccess);
554
555 // Sort the classes alphabetically
556 (void)TreeView_SortChildren(m_hTreeView,
557 m_hTreeRoot,
558 0);
559
560 // Expand the root item
561 (void)TreeView_Expand(m_hTreeView,
562 m_hTreeRoot,
563 TVE_EXPAND);
564
565 // Pre-select the root item
566 (VOID)TreeView_SelectItem(m_hTreeView,
567 m_hTreeRoot);
568
569 return 0;
570 }
571
572 bool
573 CDeviceView::ListDevicesByConnection()
574 {
575 bool bSuccess;
576
577 // Start by adding the root node to the tree
578 bSuccess = AddRootDevice();
579 if (bSuccess == false) return false;
580
581 // Walk the device tree and add all the devices
582 (void)RecurseChildDevices(m_RootDevInst, m_hTreeRoot);
583
584 // Expand the root item
585 (void)TreeView_Expand(m_hTreeView,
586 m_hTreeRoot,
587 TVE_EXPAND);
588
589 return true;
590 }
591
592 bool
593 CDeviceView::RecurseChildDevices(
594 _In_ DEVINST ParentDevice,
595 _In_ HTREEITEM hParentTreeItem
596 )
597 {
598 HTREEITEM hDevItem = NULL;
599 DEVINST Device;
600 bool HasProblem = false;
601 bool bSuccess;
602
603 // Check if the parent has any child devices
604 if (GetChildDevice(ParentDevice, &Device) == FALSE)
605 return true;
606
607 // Get the cached device node
608 CDeviceNode *DeviceNode;
609 DeviceNode = dynamic_cast<CDeviceNode *>(GetDeviceNode(Device));
610 if (DeviceNode == NULL)
611 {
612 ATLASSERT(FALSE);
613 return false;
614 }
615
616 // Don't show hidden devices if not requested
617 if ((m_ShowHidden == TRUE) || (!(DeviceNode->IsHidden())))
618 {
619 // Add this device to the tree under its parent
620 hDevItem = InsertIntoTreeView(hParentTreeItem,
621 DeviceNode);
622 if (hDevItem)
623 {
624 // Check if this child has any children itself
625 if (!RecurseChildDevices(Device, hDevItem))
626 HasProblem = true;
627 }
628
629 if (DeviceNode->HasProblem())
630 {
631 HasProblem = true;
632 }
633 }
634
635
636 // Check for siblings
637 for (;;)
638 {
639 // Check if the parent device has anything at the same level
640 bSuccess = GetSiblingDevice(Device, &Device);
641 if (bSuccess == FALSE) break;
642
643 DeviceNode = dynamic_cast<CDeviceNode *>(GetDeviceNode(Device));
644 if (DeviceNode == NULL)
645 {
646 ATLASSERT(FALSE);
647 }
648
649 // Don't show hidden devices if not requested
650 if ((m_ShowHidden == TRUE) || (!(DeviceNode->IsHidden())))
651 {
652 if (DeviceNode->HasProblem())
653 {
654 HasProblem = true;
655 }
656
657 // Add this device to the tree under its parent
658 hDevItem = InsertIntoTreeView(hParentTreeItem,
659 DeviceNode);
660 if (hDevItem)
661 {
662 // Check if this child has any children itself
663 if (!RecurseChildDevices(Device, hDevItem))
664 HasProblem = true;
665 }
666 }
667 }
668
669 (void)TreeView_SortChildren(m_hTreeView,
670 hParentTreeItem,
671 0);
672
673 // Expand the class if it has a problem device
674 if (HasProblem == true)
675 {
676 (void)TreeView_Expand(m_hTreeView,
677 hParentTreeItem,
678 TVE_EXPAND);
679 }
680
681 // If there was a problem, expand the ancestors
682 if (HasProblem) return false;
683
684 return true;
685 }
686
687 bool
688 CDeviceView::GetChildDevice(
689 _In_ DEVINST ParentDevInst,
690 _Out_ PDEVINST DevInst
691 )
692 {
693 CONFIGRET cr;
694 cr = CM_Get_Child(DevInst,
695 ParentDevInst,
696 0);
697 return (cr == CR_SUCCESS);
698 }
699
700 bool
701 CDeviceView::GetSiblingDevice(
702 _In_ DEVINST PrevDevice,
703 _Out_ PDEVINST DevInst
704 )
705 {
706 CONFIGRET cr;
707 cr = CM_Get_Sibling(DevInst,
708 PrevDevice,
709 0);
710 return (cr == CR_SUCCESS);
711 }
712
713 HTREEITEM
714 CDeviceView::InsertIntoTreeView(
715 _In_ HTREEITEM hParent,
716 _In_ CNode *Node
717 )
718 {
719
720 LPWSTR lpLabel;
721 lpLabel = Node->GetDisplayName();
722
723 TV_ITEMW tvi;
724 TV_INSERTSTRUCT tvins;
725 ZeroMemory(&tvi, sizeof(tvi));
726 ZeroMemory(&tvins, sizeof(tvins));
727
728 tvi.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
729 tvi.pszText = lpLabel;
730 tvi.cchTextMax = wcslen(lpLabel);
731 tvi.lParam = (LPARAM)Node;
732 tvi.iImage = Node->GetClassImage();
733 tvi.iSelectedImage = Node->GetClassImage();
734
735 // try to cast it to a device node. This will only suceed if it's the correct type
736 CDeviceNode *DeviceNode = dynamic_cast<CDeviceNode *>(Node);
737 if (DeviceNode && DeviceNode->GetOverlayImage())
738 {
739 tvi.mask |= TVIF_STATE;
740 tvi.stateMask = TVIS_OVERLAYMASK;
741 tvi.state = INDEXTOOVERLAYMASK(DeviceNode->GetOverlayImage());
742 }
743
744 tvins.item = tvi;
745 tvins.hParent = hParent;
746
747 return TreeView_InsertItem(m_hTreeView, &tvins);
748 }
749
750 void
751 CDeviceView::RecurseDeviceView(
752 _In_ HTREEITEM hParentItem
753 )
754 {
755 HTREEITEM hItem;
756 TVITEMW tvItem;
757
758 // Check if this node has any children
759 hItem = TreeView_GetChild(m_hTreeView, hParentItem);
760 if (hItem == NULL) return;
761
762 // The lParam contains the node pointer data
763 tvItem.hItem = hItem;
764 tvItem.mask = TVIF_PARAM;
765 if (TreeView_GetItem(m_hTreeView, &tvItem) &&
766 tvItem.lParam != NULL)
767 {
768 // Delete the node class
769 //delete reinterpret_cast<CNode *>(tvItem.lParam);
770 }
771
772 // This node may have its own children
773 RecurseDeviceView(hItem);
774
775 // Delete all the siblings
776 for (;;)
777 {
778 // Get the next item at this level
779 hItem = TreeView_GetNextSibling(m_hTreeView, hItem);
780 if (hItem == NULL) break;
781
782 // The lParam contains the node pointer data
783 tvItem.hItem = hItem;
784 tvItem.mask = TVIF_PARAM;
785 if (TreeView_GetItem(m_hTreeView, &tvItem))
786 {
787 //if (tvItem.lParam != NULL)
788 // delete reinterpret_cast<CNode *>(tvItem.lParam);
789 }
790
791 // This node may have its own children
792 RecurseDeviceView(hItem);
793 }
794 }
795
796
797 void
798 CDeviceView::EmptyDeviceView()
799 {
800 HTREEITEM hItem;
801
802 // Check if there are any items in the tree
803 hItem = TreeView_GetRoot(m_hTreeView);
804 if (hItem == NULL) return;
805
806 // Free all the class nodes
807 //RecurseDeviceView(hItem);
808
809 // Delete all the items
810 (VOID)TreeView_DeleteAllItems(m_hTreeView);
811 }
812
813
814
815
816 CClassNode*
817 CDeviceView::GetClassNode(
818 _In_ LPGUID ClassGuid
819 )
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(
844 _In_ DEVINST Device
845 )
846 {
847 POSITION Pos;
848 CDeviceNode *Node;
849
850 Pos = m_DeviceNodeList.GetHeadPosition();
851
852 do
853 {
854 Node = m_DeviceNodeList.GetNext(Pos);
855 if (Node->GetDeviceInst() == Device)
856 {
857 //ATLASSERT(Node->GetType() == NodeDevice);
858 break;
859 }
860
861 Node = NULL;
862
863 } while (Pos != NULL);
864
865 return Node;
866 }
867
868 CNode* CDeviceView::GetNode(
869 _In_ LPTV_ITEMW TvItem
870 )
871 {
872 TvItem->mask = TVIF_PARAM;
873 if (TreeView_GetItem(m_hTreeView, TvItem))
874 {
875 return (CNode *)TvItem->lParam;
876 }
877 return NULL;
878 }
879
880 CNode* CDeviceView::GetSelectedNode()
881 {
882 TV_ITEM TvItem;
883 TvItem.hItem = TreeView_GetSelection(m_hTreeView);
884 return GetNode(&TvItem);
885 }
886
887 void
888 CDeviceView::EmptyLists()
889 {
890 CNode *Node;
891
892 while (!m_ClassNodeList.IsEmpty())
893 {
894 Node = m_ClassNodeList.RemoveTail();
895 delete Node;
896 }
897
898 while (!m_DeviceNodeList.IsEmpty())
899 {
900 Node = m_DeviceNodeList.RemoveTail();
901 delete Node;
902 }
903 }
904
905 bool
906 CDeviceView::RefreshDeviceList()
907 {
908 GUID ClassGuid;
909 CClassNode *ClassNode;
910 CDeviceNode *DeviceNode;
911 HDEVINFO hDevInfo;
912 SP_DEVINFO_DATA DeviceInfoData;
913 DWORD i;
914 BOOL Success;
915
916 ULONG ClassIndex = 0;
917
918 EmptyLists();
919
920 // Loop through all the classes
921 do
922 {
923 Success = GetNextClass(ClassIndex, &ClassGuid, &hDevInfo);
924 if (Success)
925 {
926 // Create a new class node and add it to the list
927 ClassNode = new CClassNode(&ClassGuid, &m_ImageListData);
928 if (ClassNode->SetupNode())
929 {
930 m_ClassNodeList.AddTail(ClassNode);
931 }
932 }
933 ClassIndex++;
934 } while (Success);
935
936
937 // Get all the devices on the local machine
938 hDevInfo = SetupDiGetClassDevsW(NULL,
939 0,
940 0,
941 DIGCF_PRESENT | DIGCF_ALLCLASSES);
942 if (hDevInfo == INVALID_HANDLE_VALUE)
943 {
944 return false;
945 }
946
947 // loop though all the devices
948 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
949 for (i = 0;; i++)
950 {
951 // Get the devinst for this device
952 Success = SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData);
953 if (Success == FALSE) break;
954
955 // create a new device node and add it to the list
956 DeviceNode = new CDeviceNode(DeviceInfoData.DevInst, &m_ImageListData);
957 if (DeviceNode->SetupNode())
958 {
959 m_DeviceNodeList.AddTail(DeviceNode);
960 }
961 }
962
963 SetupDiDestroyDeviceInfoList(hDevInfo);
964
965 return TRUE;
966 }