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