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