31f7d1e8839d666e508e6ebf47d9999cf0535722
[reactos.git] / reactos / dll / win32 / devmgr / devmgmt / DeviceNode.cpp
1 /*
2 * PROJECT: ReactOS Device Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/devmgr/devmgr/ClassNode.cpp
5 * PURPOSE: Class object for
6 * COPYRIGHT: Copyright 2015 Ged Murphy <gedmurphy@reactos.org>
7 *
8 */
9
10 #include "stdafx.h"
11 #include "devmgmt.h"
12 #include "DeviceNode.h"
13
14
15 CDeviceNode::CDeviceNode(
16 _In_opt_ DEVINST Device,
17 _In_ PSP_CLASSIMAGELIST_DATA ImageListData
18 ) :
19 CNode(ImageListData),
20 m_DevInst(Device),
21 m_Status(0),
22 m_ProblemNumber(0),
23 m_OverlayImage(0)
24 {
25 ZeroMemory(&m_DevinfoData, sizeof(SP_DEVINFO_DATA));
26 }
27
28 CDeviceNode::~CDeviceNode()
29 {
30 SetupDiDestroyDeviceInfoList(m_hDevInfo);
31 }
32
33 bool
34 CDeviceNode::SetupNode()
35 {
36 WCHAR ClassGuidString[MAX_GUID_STRING_LEN];
37 ULONG ulLength;
38 CONFIGRET cr;
39
40 // ATLASSERT(m_DeviceId == NULL);
41
42
43 // Get the length of the device id string
44 cr = CM_Get_Device_ID_Size(&ulLength, m_DevInst, 0);
45 if (cr == CR_SUCCESS)
46 {
47 // We alloc heap here because this will be stored in the lParam of the TV
48 m_DeviceId = (LPWSTR)HeapAlloc(GetProcessHeap(),
49 0,
50 (ulLength + 1) * sizeof(WCHAR));
51 if (m_DeviceId)
52 {
53 // Now get the actual device id
54 cr = CM_Get_Device_IDW(m_DevInst,
55 m_DeviceId,
56 ulLength + 1,
57 0);
58 if (cr != CR_SUCCESS)
59 {
60 HeapFree(GetProcessHeap(), 0, m_DeviceId);
61 m_DeviceId = NULL;
62 }
63 }
64 }
65
66 // Make sure we got the string
67 if (m_DeviceId == NULL)
68 return false;
69
70 //SP_DEVINFO_DATA DevinfoData;
71 m_hDevInfo = SetupDiCreateDeviceInfoListExW(NULL,
72 NULL,
73 NULL,
74 NULL);
75 if (m_hDevInfo != INVALID_HANDLE_VALUE)
76 {
77 m_DevinfoData.cbSize = sizeof(SP_DEVINFO_DATA);
78 SetupDiOpenDeviceInfoW(m_hDevInfo,
79 m_DeviceId,
80 NULL,
81 0,
82 &m_DevinfoData);
83 }
84
85
86
87 // Get the current status of the device
88 cr = CM_Get_DevNode_Status_Ex(&m_Status,
89 &m_ProblemNumber,
90 m_DevInst,
91 0,
92 NULL);
93 if (cr != CR_SUCCESS)
94 {
95 HeapFree(GetProcessHeap(), 0, m_DeviceId);
96 m_DeviceId = NULL;
97 return false;
98 }
99
100 // Check if the device has a problem
101 if (m_Status & DN_HAS_PROBLEM)
102 {
103 m_OverlayImage = 1;
104 }
105
106 // The disabled overlay takes precidence over the problem overlay
107 if (m_ProblemNumber & (CM_PROB_DISABLED | CM_PROB_HARDWARE_DISABLED))
108 {
109 m_OverlayImage = 2;
110 }
111
112
113 // Get the class guid for this device
114 ulLength = MAX_GUID_STRING_LEN * sizeof(WCHAR);
115 cr = CM_Get_DevNode_Registry_PropertyW(m_DevInst,
116 CM_DRP_CLASSGUID,
117 NULL,
118 ClassGuidString,
119 &ulLength,
120 0);
121 if (cr == CR_SUCCESS)
122 {
123 // Convert the string to a proper guid
124 CLSIDFromString(ClassGuidString, &m_ClassGuid);
125 }
126 else
127 {
128 // It's a device with no driver
129 m_ClassGuid = GUID_DEVCLASS_UNKNOWN;
130 }
131
132
133 // Get the image for the class this device is in
134 SetupDiGetClassImageIndex(m_ImageListData,
135 &m_ClassGuid,
136 &m_ClassImage);
137
138 // Get the description for the device
139 ulLength = DISPLAY_NAME_LEN * sizeof(WCHAR);
140 cr = CM_Get_DevNode_Registry_PropertyW(m_DevInst,
141 CM_DRP_FRIENDLYNAME,
142 NULL,
143 m_DisplayName,
144 &ulLength,
145 0);
146 if (cr != CR_SUCCESS)
147 {
148 ulLength = DISPLAY_NAME_LEN * sizeof(WCHAR);
149 cr = CM_Get_DevNode_Registry_PropertyW(m_DevInst,
150 CM_DRP_DEVICEDESC,
151 NULL,
152 m_DisplayName,
153 &ulLength,
154 0);
155
156 }
157
158 // Cleanup if something failed
159 if (cr != CR_SUCCESS)
160 {
161 HeapFree(GetProcessHeap(), 0, m_DeviceId);
162 m_DeviceId = NULL;
163 }
164
165 return (cr == CR_SUCCESS ? true : false);
166 }
167
168 bool
169 CDeviceNode::HasProblem()
170 {
171 CONFIGRET cr;
172 cr = CM_Get_DevNode_Status_Ex(&m_Status,
173 &m_ProblemNumber,
174 m_DevInst,
175 0,
176 NULL);
177 if (cr == CR_SUCCESS)
178 {
179 return ((m_Status & (DN_HAS_PROBLEM | DN_PRIVATE_PROBLEM)) != 0);
180 }
181
182 return false;
183 }
184
185 bool
186 CDeviceNode::IsHidden()
187 {
188 CONFIGRET cr;
189 cr = CM_Get_DevNode_Status_Ex(&m_Status,
190 &m_ProblemNumber,
191 m_DevInst,
192 0,
193 NULL);
194 if (cr == CR_SUCCESS)
195 {
196 return ((m_Status & DN_NO_SHOW_IN_DM) != 0);
197 }
198
199 return false;
200 }
201
202 bool
203 CDeviceNode::CanDisable()
204 {
205 CONFIGRET cr;
206 cr = CM_Get_DevNode_Status_Ex(&m_Status,
207 &m_ProblemNumber,
208 m_DevInst,
209 0,
210 NULL);
211 if (cr == CR_SUCCESS)
212 {
213 return ((m_Status & DN_DISABLEABLE) != 0);
214 }
215
216 return false;
217 }
218
219 bool
220 CDeviceNode::IsDisabled()
221 {
222 CONFIGRET cr;
223 cr = CM_Get_DevNode_Status_Ex(&m_Status,
224 &m_ProblemNumber,
225 m_DevInst,
226 0,
227 NULL);
228 if (cr == CR_SUCCESS)
229 {
230 return ((m_ProblemNumber & (CM_PROB_DISABLED | CM_PROB_HARDWARE_DISABLED)) != 0);
231 }
232
233 return false;
234 }
235
236 bool
237 CDeviceNode::IsStarted()
238 {
239 CONFIGRET cr;
240 cr = CM_Get_DevNode_Status_Ex(&m_Status,
241 &m_ProblemNumber,
242 m_DevInst,
243 0,
244 NULL);
245 if (cr == CR_SUCCESS)
246 {
247 return ((m_Status & DN_STARTED) != 0);
248 }
249
250 return false;
251 }
252
253 bool
254 CDeviceNode::IsInstalled()
255 {
256 CONFIGRET cr;
257 cr = CM_Get_DevNode_Status_Ex(&m_Status,
258 &m_ProblemNumber,
259 m_DevInst,
260 0,
261 NULL);
262 if (cr == CR_SUCCESS)
263 {
264 return ((m_Status & DN_HAS_PROBLEM) != 0 ||
265 (m_Status & (DN_DRIVER_LOADED | DN_STARTED)) != 0);
266 }
267
268 return false;
269 }
270
271 bool
272 CDeviceNode::CanUninstall()
273 {
274 CONFIGRET cr;
275 cr = CM_Get_DevNode_Status_Ex(&m_Status,
276 &m_ProblemNumber,
277 m_DevInst,
278 0,
279 NULL);
280 if (cr == CR_SUCCESS)
281 {
282 return ((m_Status & DN_DISABLEABLE) != 0 &&
283 (m_Status & DN_ROOT_ENUMERATED) == 0);
284 }
285
286 return false;
287 }
288
289 bool
290 CDeviceNode::EnableDevice(
291 _In_ bool Enable,
292 _Out_ bool &NeedsReboot
293 )
294 {
295 bool Ret = false;
296 bool Canceled = false;
297
298 SetFlags(DI_NODI_DEFAULTACTION, 0);
299
300 SP_PROPCHANGE_PARAMS pcp;
301 pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
302 pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
303 pcp.StateChange = (Enable ? DICS_ENABLE : DICS_DISABLE);
304 pcp.HwProfile = 0;
305
306
307 // check both scopes to make sure we can make the change
308 for (int i = 0; i < 2; i++)
309 {
310 // Check globally first, then check config specific
311 pcp.Scope = (i == 0) ? DICS_FLAG_GLOBAL : DICS_FLAG_CONFIGSPECIFIC;
312
313 if (SetupDiSetClassInstallParamsW(m_hDevInfo,
314 &m_DevinfoData,
315 &pcp.ClassInstallHeader,
316 sizeof(SP_PROPCHANGE_PARAMS)))
317 {
318 SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
319 m_hDevInfo,
320 &m_DevinfoData);
321 }
322
323 if (GetLastError() == ERROR_CANCELLED)
324 {
325 Canceled = true;
326 break;
327 }
328 }
329
330 if (Canceled == false)
331 {
332 pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
333 if (SetupDiSetClassInstallParamsW(m_hDevInfo,
334 &m_DevinfoData,
335 &pcp.ClassInstallHeader,
336 sizeof(SP_PROPCHANGE_PARAMS)))
337 {
338 SetupDiChangeState(m_hDevInfo, &m_DevinfoData);
339 }
340
341 if (Enable)
342 {
343 pcp.Scope = DICS_FLAG_GLOBAL;
344 if (SetupDiSetClassInstallParamsW(m_hDevInfo,
345 &m_DevinfoData,
346 &pcp.ClassInstallHeader,
347 sizeof(SP_PROPCHANGE_PARAMS)))
348 {
349 SetupDiChangeState(m_hDevInfo, &m_DevinfoData);
350 }
351 }
352
353 SetFlags(DI_PROPERTIES_CHANGE, 0);
354
355 NeedsReboot = ((GetFlags() & (DI_NEEDRESTART | DI_NEEDREBOOT)) != 0);
356 }
357
358 RemoveFlags(DI_NODI_DEFAULTACTION, 0);
359
360 return true;
361 }
362
363 DWORD
364 CDeviceNode::GetFlags(
365 )
366 {
367 SP_DEVINSTALL_PARAMS DevInstallParams;
368 DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
369 if (SetupDiGetDeviceInstallParamsW(m_hDevInfo,
370 &m_DevinfoData,
371 &DevInstallParams))
372 {
373 return DevInstallParams.Flags;
374 }
375 return 0;
376 }
377
378 bool
379 CDeviceNode::SetFlags(
380 _In_ DWORD Flags,
381 _In_ DWORD FlagsEx
382 )
383 {
384 SP_DEVINSTALL_PARAMS DevInstallParams;
385 DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
386 if (SetupDiGetDeviceInstallParamsW(m_hDevInfo,
387 &m_DevinfoData,
388 &DevInstallParams))
389 {
390 DevInstallParams.Flags |= Flags;
391 DevInstallParams.FlagsEx |= FlagsEx;
392 return SetupDiSetDeviceInstallParamsW(m_hDevInfo,
393 &m_DevinfoData,
394 &DevInstallParams);
395 }
396 return false;
397 }
398
399 bool
400 CDeviceNode::RemoveFlags(
401 _In_ DWORD Flags,
402 _In_ DWORD FlagsEx
403 )
404 {
405 SP_DEVINSTALL_PARAMS DevInstallParams;
406 DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
407 if (SetupDiGetDeviceInstallParamsW(m_hDevInfo,
408 &m_DevinfoData,
409 &DevInstallParams))
410 {
411 DevInstallParams.Flags &= ~Flags;
412 DevInstallParams.FlagsEx &= ~FlagsEx;
413 return SetupDiSetDeviceInstallParamsW(m_hDevInfo,
414 &m_DevinfoData,
415 &DevInstallParams);
416 }
417 return false;
418 }
419
420