[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 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 VOID
591 CDeviceView::RecurseChildDevices(
592 _In_ DEVINST ParentDevice,
593 _In_ HTREEITEM hParentTreeItem
594 )
595 {
596
597 HTREEITEM hDevItem = NULL;
598 DEVINST Device;
599 BOOL bSuccess;
600
601 // Check if the parent has any child devices
602 if (GetChildDevice(ParentDevice, &Device) == FALSE)
603 return;
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;
612 }
613
614
615 // Check if this is a hidden device
616 if ((m_ShowHidden == TRUE) || (!(DeviceNode->IsHidden())))
617 {
618 // Add this device to the tree under its parent
619 hDevItem = InsertIntoTreeView(hParentTreeItem,
620 DeviceNode);
621
622
623 if (hDevItem)
624 {
625 // Check if this child has any children itself
626 RecurseChildDevices(Device, hDevItem);
627 }
628 }
629
630
631 for (;;)
632 {
633 // Check if the parent device has anything at the same level
634 bSuccess = GetSiblingDevice(Device, &Device);
635 if (bSuccess == FALSE) break;
636
637 DeviceNode = dynamic_cast<CDeviceNode *>(GetDeviceNode(Device));
638 if (DeviceNode == NULL)
639 {
640 ATLASSERT(FALSE);
641 }
642
643 // Check if this is a hidden device
644 if (DeviceNode->IsHidden())
645 {
646 if (m_ShowHidden == FALSE)
647 continue;
648 }
649
650 // Add this device to the tree under its parent
651 hDevItem = InsertIntoTreeView(hParentTreeItem,
652 DeviceNode);
653 if (hDevItem)
654 {
655 // Check if this child has any children itself
656 RecurseChildDevices(Device, hDevItem);
657 }
658 }
659
660 (void)TreeView_SortChildren(m_hTreeView,
661 hParentTreeItem,
662 0);
663
664 }
665
666 bool
667 CDeviceView::GetChildDevice(
668 _In_ DEVINST ParentDevInst,
669 _Out_ PDEVINST DevInst
670 )
671 {
672 CONFIGRET cr;
673 cr = CM_Get_Child(DevInst,
674 ParentDevInst,
675 0);
676 return (cr == CR_SUCCESS);
677 }
678
679 bool
680 CDeviceView::GetSiblingDevice(
681 _In_ DEVINST PrevDevice,
682 _Out_ PDEVINST DevInst
683 )
684 {
685 CONFIGRET cr;
686 cr = CM_Get_Sibling(DevInst,
687 PrevDevice,
688 0);
689 return (cr == CR_SUCCESS);
690 }
691
692 HTREEITEM
693 CDeviceView::InsertIntoTreeView(
694 _In_ HTREEITEM hParent,
695 _In_ CNode *Node
696 )
697 {
698
699 LPWSTR lpLabel;
700 lpLabel = Node->GetDisplayName();
701
702 TV_ITEMW tvi;
703 TV_INSERTSTRUCT tvins;
704 ZeroMemory(&tvi, sizeof(tvi));
705 ZeroMemory(&tvins, sizeof(tvins));
706
707 tvi.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
708 tvi.pszText = lpLabel;
709 tvi.cchTextMax = wcslen(lpLabel);
710 tvi.lParam = (LPARAM)Node;
711 tvi.iImage = Node->GetClassImage();
712 tvi.iSelectedImage = Node->GetClassImage();
713
714 // try to cast it to a device node. This will only suceed if it's the correct type
715 CDeviceNode *DeviceNode = dynamic_cast<CDeviceNode *>(Node);
716 if (DeviceNode && DeviceNode->GetOverlayImage())
717 {
718 tvi.mask |= TVIF_STATE;
719 tvi.stateMask = TVIS_OVERLAYMASK;
720 tvi.state = INDEXTOOVERLAYMASK(DeviceNode->GetOverlayImage());
721 }
722
723 tvins.item = tvi;
724 tvins.hParent = hParent;
725
726 return TreeView_InsertItem(m_hTreeView, &tvins);
727 }
728
729 void
730 CDeviceView::RecurseDeviceView(
731 _In_ HTREEITEM hParentItem
732 )
733 {
734 HTREEITEM hItem;
735 TVITEMW tvItem;
736
737 // Check if this node has any children
738 hItem = TreeView_GetChild(m_hTreeView, hParentItem);
739 if (hItem == NULL) return;
740
741 // The lParam contains the node pointer data
742 tvItem.hItem = hItem;
743 tvItem.mask = TVIF_PARAM;
744 if (TreeView_GetItem(m_hTreeView, &tvItem) &&
745 tvItem.lParam != NULL)
746 {
747 // Delete the node class
748 //delete reinterpret_cast<CNode *>(tvItem.lParam);
749 }
750
751 // This node may have its own children
752 RecurseDeviceView(hItem);
753
754 // Delete all the siblings
755 for (;;)
756 {
757 // Get the next item at this level
758 hItem = TreeView_GetNextSibling(m_hTreeView, hItem);
759 if (hItem == NULL) break;
760
761 // The lParam contains the node pointer data
762 tvItem.hItem = hItem;
763 tvItem.mask = TVIF_PARAM;
764 if (TreeView_GetItem(m_hTreeView, &tvItem))
765 {
766 //if (tvItem.lParam != NULL)
767 // delete reinterpret_cast<CNode *>(tvItem.lParam);
768 }
769
770 // This node may have its own children
771 RecurseDeviceView(hItem);
772 }
773 }
774
775
776 void
777 CDeviceView::EmptyDeviceView()
778 {
779 HTREEITEM hItem;
780
781 // Check if there are any items in the tree
782 hItem = TreeView_GetRoot(m_hTreeView);
783 if (hItem == NULL) return;
784
785 // Free all the class nodes
786 //RecurseDeviceView(hItem);
787
788 // Delete all the items
789 (VOID)TreeView_DeleteAllItems(m_hTreeView);
790 }
791
792
793
794
795 CClassNode*
796 CDeviceView::GetClassNode(_In_ LPGUID ClassGuid)
797 {
798 POSITION Pos;
799 CClassNode *Node;
800
801 Pos = m_ClassNodeList.GetHeadPosition();
802
803 do
804 {
805 Node = m_ClassNodeList.GetNext(Pos);
806 if (IsEqualGUID(*Node->GetClassGuid(), *ClassGuid))
807 {
808 //ATLASSERT(Node->GetType() == NodeClass);
809 break;
810 }
811
812 Node = NULL;
813
814 } while (Pos != NULL);
815
816 return Node;
817 }
818
819 CDeviceNode*
820 CDeviceView::GetDeviceNode(_In_ DEVINST Device)
821 {
822 POSITION Pos;
823 CDeviceNode *Node;
824
825 Pos = m_DeviceNodeList.GetHeadPosition();
826
827 do
828 {
829 Node = m_DeviceNodeList.GetNext(Pos);
830 if (Node->GetDeviceInst() == Device)
831 {
832 //ATLASSERT(Node->GetType() == NodeDevice);
833 break;
834 }
835
836 Node = NULL;
837
838 } while (Pos != NULL);
839
840 return Node;
841 }
842
843 CNode* CDeviceView::GetNode(LPTV_ITEMW TvItem)
844 {
845 TvItem->mask = TVIF_PARAM;
846 if (TreeView_GetItem(m_hTreeView, TvItem))
847 {
848 return (CNode *)TvItem->lParam;
849 }
850 return NULL;
851 }
852
853 CNode* CDeviceView::GetSelectedNode()
854 {
855 TV_ITEM TvItem;
856 TvItem.hItem = TreeView_GetSelection(m_hTreeView);
857 return GetNode(&TvItem);
858 }
859
860 void
861 CDeviceView::EmptyLists()
862 {
863 POSITION Pos;
864 CNode *Node;
865
866 if (!m_ClassNodeList.IsEmpty())
867 {
868 Pos = m_ClassNodeList.GetHeadPosition();
869 do
870 {
871 Node = m_ClassNodeList.GetNext(Pos);
872 delete Node;
873
874 } while (Pos != NULL);
875 }
876
877 if (!m_DeviceNodeList.IsEmpty())
878 {
879 Pos = m_DeviceNodeList.GetHeadPosition();
880 do
881 {
882 Node = m_DeviceNodeList.GetNext(Pos);
883 delete Node;
884
885 } while (Pos != NULL);
886 }
887 }
888
889 bool
890 CDeviceView::RefreshDeviceList()
891 {
892 GUID ClassGuid;
893 CClassNode *ClassNode;
894 CDeviceNode *DeviceNode;
895 HDEVINFO hDevInfo;
896 SP_DEVINFO_DATA DeviceInfoData;
897 DWORD i;
898 BOOL Success;
899
900 ULONG ClassIndex = 0;
901
902 EmptyLists();
903
904 // Loop through all the classes
905 do
906 {
907 Success = GetNextClass(ClassIndex, &ClassGuid, &hDevInfo);
908 if (Success)
909 {
910 // Create a new class node and add it to the list
911 ClassNode = new CClassNode(&ClassGuid, &m_ImageListData);
912 if (ClassNode->SetupNode())
913 {
914 m_ClassNodeList.AddTail(ClassNode);
915 }
916 }
917 ClassIndex++;
918 } while (Success);
919
920
921 // Get all the devices on the local machine
922 hDevInfo = SetupDiGetClassDevsW(NULL,
923 0,
924 0,
925 DIGCF_PRESENT | DIGCF_ALLCLASSES);
926 if (hDevInfo == INVALID_HANDLE_VALUE)
927 {
928 return false;
929 }
930
931 // loop though all the devices
932 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
933 for (i = 0;; i++)
934 {
935 // Get the devinst for this device
936 Success = SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData);
937 if (Success == FALSE) break;
938
939 // create a new device node and add it to the list
940 DeviceNode = new CDeviceNode(DeviceInfoData.DevInst, &m_ImageListData);
941 if (DeviceNode->SetupNode())
942 {
943 m_DeviceNodeList.AddTail(DeviceNode);
944 }
945 }
946
947 SetupDiDestroyDeviceInfoList(hDevInfo);
948
949 return TRUE;
950 }