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