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