2 * PROJECT: ReactOS Device Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/devmgr/devmgmt/ClassNode.cpp
5 * PURPOSE: Class object for
6 * COPYRIGHT: Copyright 2015 Ged Murphy <gedmurphy@reactos.org>
12 #include "DeviceNode.h"
15 CDeviceNode::CDeviceNode(
16 _In_opt_ DEVINST Device
,
17 _In_ PSP_CLASSIMAGELIST_DATA ImageListData
19 CNode(DeviceNode
, ImageListData
),
26 ZeroMemory(&m_DevinfoData
, sizeof(SP_DEVINFO_DATA
));
29 CDeviceNode::CDeviceNode(
30 _In_
const CDeviceNode
&Node
34 m_DevInst
= Node
.m_DevInst
;
35 m_hDevInfo
= Node
.m_hDevInfo
;
36 m_Status
= Node
.m_Status
;
37 m_ProblemNumber
= Node
.m_ProblemNumber
;
38 m_OverlayImage
= Node
.m_OverlayImage
;
39 CopyMemory(&m_DevinfoData
, &Node
.m_DevinfoData
, sizeof(SP_DEVINFO_DATA
));
41 size_t size
= wcslen(Node
.m_DeviceId
) + 1;
42 m_DeviceId
= new WCHAR
[size
];
43 StringCbCopyW(m_DeviceId
, size
* sizeof(WCHAR
), Node
.m_DeviceId
);
47 CDeviceNode::~CDeviceNode()
53 CDeviceNode::SetupNode()
55 WCHAR ClassGuidString
[MAX_GUID_STRING_LEN
];
59 // Get the length of the device id string
60 cr
= CM_Get_Device_ID_Size(&ulLength
, m_DevInst
, 0);
63 // We alloc heap here because this will be stored in the lParam of the TV
64 m_DeviceId
= new WCHAR
[ulLength
+ 1];
66 // Now get the actual device id
67 cr
= CM_Get_Device_IDW(m_DevInst
,
71 if (cr
!= CR_SUCCESS
|| wcscmp(m_DeviceId
, L
"HTREE\\ROOT\\0") == 0)
79 // Make sure we got the string
80 if (m_DeviceId
== NULL
)
83 // Build up a handle a and devinfodata struct
84 m_hDevInfo
= SetupDiCreateDeviceInfoListExW(NULL
,
88 if (m_hDevInfo
!= INVALID_HANDLE_VALUE
)
90 m_DevinfoData
.cbSize
= sizeof(SP_DEVINFO_DATA
);
91 SetupDiOpenDeviceInfoW(m_hDevInfo
,
99 // Check if the device has a problem
104 m_OverlayImage
= OverlayDisabled
;
108 m_OverlayImage
= OverlayProblem
;
115 // Get the class guid for this device
116 ulLength
= MAX_GUID_STRING_LEN
* sizeof(WCHAR
);
117 cr
= CM_Get_DevNode_Registry_PropertyW(m_DevInst
,
123 if (cr
== CR_SUCCESS
)
125 // Convert the string to a proper guid
126 CLSIDFromString(ClassGuidString
, &m_ClassGuid
);
130 // It's a device with no driver
131 m_ClassGuid
= GUID_DEVCLASS_UNKNOWN
;
135 // Get the image for the class this device is in
136 SetupDiGetClassImageIndex(m_ImageListData
,
141 // Get the description for the device
142 ulLength
= DISPLAY_NAME_LEN
* sizeof(WCHAR
);
143 cr
= CM_Get_DevNode_Registry_PropertyW(m_DevInst
,
149 if (cr
!= CR_SUCCESS
)
151 ulLength
= DISPLAY_NAME_LEN
* sizeof(WCHAR
);
152 cr
= CM_Get_DevNode_Registry_PropertyW(m_DevInst
,
161 if (cr
!= CR_SUCCESS
)
164 if (str
.LoadStringW(g_hThisInstance
, IDS_UNKNOWNDEVICE
))
165 StringCchCopyW(m_DisplayName
, MAX_PATH
, str
.GetBuffer());
172 CDeviceNode::HasProblem()
175 cr
= CM_Get_DevNode_Status_Ex(&m_Status
,
180 if (cr
== CR_SUCCESS
)
182 return ((m_Status
& (DN_HAS_PROBLEM
| DN_PRIVATE_PROBLEM
)) != 0);
189 CDeviceNode::IsHidden()
192 cr
= CM_Get_DevNode_Status_Ex(&m_Status
,
197 if (cr
== CR_SUCCESS
)
199 if (m_Status
& DN_NO_SHOW_IN_DM
)
203 if (IsEqualGUID(*GetClassGuid(), GUID_DEVCLASS_LEGACYDRIVER
) ||
204 IsEqualGUID(*GetClassGuid(), GUID_DEVCLASS_VOLUME
))
211 CDeviceNode::CanDisable()
214 cr
= CM_Get_DevNode_Status_Ex(&m_Status
,
219 if (cr
== CR_SUCCESS
)
221 return ((m_Status
& DN_DISABLEABLE
) != 0);
228 CDeviceNode::IsDisabled()
231 cr
= CM_Get_DevNode_Status_Ex(&m_Status
,
236 if (cr
== CR_SUCCESS
)
238 return ((m_ProblemNumber
== CM_PROB_DISABLED
) || (m_ProblemNumber
== CM_PROB_HARDWARE_DISABLED
));
245 CDeviceNode::IsStarted()
248 cr
= CM_Get_DevNode_Status_Ex(&m_Status
,
253 if (cr
== CR_SUCCESS
)
255 return ((m_Status
& DN_STARTED
) != 0);
262 CDeviceNode::IsInstalled()
265 cr
= CM_Get_DevNode_Status_Ex(&m_Status
,
270 if (cr
== CR_SUCCESS
)
272 return ((m_Status
& DN_HAS_PROBLEM
) != 0 ||
273 (m_Status
& (DN_DRIVER_LOADED
| DN_STARTED
)) != 0);
280 CDeviceNode::CanUninstall()
283 cr
= CM_Get_DevNode_Status_Ex(&m_Status
,
288 if (cr
== CR_SUCCESS
)
290 if ((m_Status
& DN_ROOT_ENUMERATED
) != 0 &&
291 (m_Status
& DN_DISABLEABLE
) == 0)
299 CDeviceNode::EnableDevice(
301 _Out_
bool &NeedsReboot
304 bool Canceled
= false;
306 SetFlags(DI_NODI_DEFAULTACTION
, 0);
308 SP_PROPCHANGE_PARAMS pcp
;
309 pcp
.ClassInstallHeader
.cbSize
= sizeof(SP_CLASSINSTALL_HEADER
);
310 pcp
.ClassInstallHeader
.InstallFunction
= DIF_PROPERTYCHANGE
;
311 pcp
.StateChange
= (Enable
? DICS_ENABLE
: DICS_DISABLE
);
315 // check both scopes to make sure we can make the change
316 for (int i
= 0; i
< 2; i
++)
318 // Check globally first, then check config specific
319 pcp
.Scope
= (i
== 0) ? DICS_FLAG_CONFIGGENERAL
: DICS_FLAG_CONFIGSPECIFIC
;
321 if (SetupDiSetClassInstallParamsW(m_hDevInfo
,
323 &pcp
.ClassInstallHeader
,
324 sizeof(SP_PROPCHANGE_PARAMS
)))
326 SetupDiCallClassInstaller(DIF_PROPERTYCHANGE
,
331 if (GetLastError() == ERROR_CANCELLED
)
338 if (Canceled
== false)
340 pcp
.Scope
= DICS_FLAG_CONFIGSPECIFIC
;
341 if (SetupDiSetClassInstallParamsW(m_hDevInfo
,
343 &pcp
.ClassInstallHeader
,
344 sizeof(SP_PROPCHANGE_PARAMS
)))
346 SetupDiChangeState(m_hDevInfo
, &m_DevinfoData
);
352 // config specific enabling first, then global enabling.
353 // The global appears to be the one that starts the device
354 pcp
.Scope
= DICS_FLAG_GLOBAL
;
355 if (SetupDiSetClassInstallParamsW(m_hDevInfo
,
357 &pcp
.ClassInstallHeader
,
358 sizeof(SP_PROPCHANGE_PARAMS
)))
360 SetupDiChangeState(m_hDevInfo
, &m_DevinfoData
);
364 SetFlags(DI_PROPERTIES_CHANGE
, 0);
366 NeedsReboot
= ((GetFlags() & (DI_NEEDRESTART
| DI_NEEDREBOOT
)) != 0);
369 RemoveFlags(DI_NODI_DEFAULTACTION
, 0);
375 CDeviceNode::UninstallDevice()
378 if (CanUninstall() == false)
381 SP_REMOVEDEVICE_PARAMS RemoveDevParams
;
382 RemoveDevParams
.ClassInstallHeader
.cbSize
= sizeof(SP_CLASSINSTALL_HEADER
);
383 RemoveDevParams
.ClassInstallHeader
.InstallFunction
= DIF_REMOVE
;
384 RemoveDevParams
.Scope
= DI_REMOVEDEVICE_GLOBAL
;
385 RemoveDevParams
.HwProfile
= 0;
388 // We probably need to walk all the siblings of this
389 // device and ask if they're happy with the uninstall
394 SetupDiSetClassInstallParamsW(m_hDevInfo
,
396 &RemoveDevParams
.ClassInstallHeader
,
397 sizeof(SP_REMOVEDEVICE_PARAMS
));
398 SetupDiCallClassInstaller(DIF_REMOVE
, m_hDevInfo
, &m_DevinfoData
);
400 // Clear the install params
401 SetupDiSetClassInstallParamsW(m_hDevInfo
,
410 /* PRIVATE METHODS ******************************************************/
413 CDeviceNode::Cleanup()
422 SetupDiDestroyDeviceInfoList(m_hDevInfo
);
428 CDeviceNode::GetFlags(
431 SP_DEVINSTALL_PARAMS DevInstallParams
;
432 DevInstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS
);
433 if (SetupDiGetDeviceInstallParamsW(m_hDevInfo
,
437 return DevInstallParams
.Flags
;
443 CDeviceNode::SetFlags(
448 SP_DEVINSTALL_PARAMS DevInstallParams
;
449 DevInstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS
);
450 if (SetupDiGetDeviceInstallParamsW(m_hDevInfo
,
454 DevInstallParams
.Flags
|= Flags
;
455 DevInstallParams
.FlagsEx
|= FlagsEx
;
456 return (SetupDiSetDeviceInstallParamsW(m_hDevInfo
,
458 &DevInstallParams
) != 0);
464 CDeviceNode::RemoveFlags(
469 SP_DEVINSTALL_PARAMS DevInstallParams
;
470 DevInstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS
);
471 if (SetupDiGetDeviceInstallParamsW(m_hDevInfo
,
475 DevInstallParams
.Flags
&= ~Flags
;
476 DevInstallParams
.FlagsEx
&= ~FlagsEx
;
477 return (SetupDiSetDeviceInstallParamsW(m_hDevInfo
,
479 &DevInstallParams
) != 0);