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