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
);
46 CDeviceNode::~CDeviceNode()
52 CDeviceNode::SetupNode()
54 WCHAR ClassGuidString
[MAX_GUID_STRING_LEN
];
58 // Get the length of the device id string
59 cr
= CM_Get_Device_ID_Size(&ulLength
, m_DevInst
, 0);
62 // We alloc heap here because this will be stored in the lParam of the TV
63 m_DeviceId
= new WCHAR
[ulLength
+ 1];
65 // Now get the actual device id
66 cr
= CM_Get_Device_IDW(m_DevInst
,
70 if (cr
!= CR_SUCCESS
|| wcscmp(m_DeviceId
, L
"HTREE\\ROOT\\0") == 0)
77 // Make sure we got the string
78 if (m_DeviceId
== NULL
)
81 // Build up a handle a and devinfodata struct
82 m_hDevInfo
= SetupDiCreateDeviceInfoListExW(NULL
,
86 if (m_hDevInfo
!= INVALID_HANDLE_VALUE
)
88 m_DevinfoData
.cbSize
= sizeof(SP_DEVINFO_DATA
);
89 SetupDiOpenDeviceInfoW(m_hDevInfo
,
96 // Check if the device has a problem
101 m_OverlayImage
= OverlayDisabled
;
105 m_OverlayImage
= OverlayProblem
;
109 // Get the class guid for this device
110 ulLength
= MAX_GUID_STRING_LEN
* sizeof(WCHAR
);
111 cr
= CM_Get_DevNode_Registry_PropertyW(m_DevInst
,
117 if (cr
== CR_SUCCESS
)
119 // Convert the string to a proper guid
120 CLSIDFromString(ClassGuidString
, &m_ClassGuid
);
124 // It's a device with no driver
125 m_ClassGuid
= GUID_DEVCLASS_UNKNOWN
;
128 // Get the image for the class this device is in
129 SetupDiGetClassImageIndex(m_ImageListData
,
133 // Get the description for the device
134 ulLength
= DISPLAY_NAME_LEN
* sizeof(WCHAR
);
135 cr
= CM_Get_DevNode_Registry_PropertyW(m_DevInst
,
141 if (cr
!= CR_SUCCESS
)
143 ulLength
= DISPLAY_NAME_LEN
* sizeof(WCHAR
);
144 cr
= CM_Get_DevNode_Registry_PropertyW(m_DevInst
,
152 if (cr
!= CR_SUCCESS
)
155 if (str
.LoadStringW(g_hThisInstance
, IDS_UNKNOWNDEVICE
))
156 StringCchCopyW(m_DisplayName
, MAX_PATH
, str
.GetBuffer());
163 CDeviceNode::HasProblem()
166 cr
= CM_Get_DevNode_Status_Ex(&m_Status
,
171 if (cr
== CR_SUCCESS
)
173 return ((m_Status
& (DN_HAS_PROBLEM
| DN_PRIVATE_PROBLEM
)) != 0);
180 CDeviceNode::IsHidden()
183 cr
= CM_Get_DevNode_Status_Ex(&m_Status
,
188 if (cr
== CR_SUCCESS
)
190 if (m_Status
& DN_NO_SHOW_IN_DM
)
194 if (IsEqualGUID(*GetClassGuid(), GUID_DEVCLASS_LEGACYDRIVER
) ||
195 IsEqualGUID(*GetClassGuid(), GUID_DEVCLASS_VOLUME
))
202 CDeviceNode::CanDisable()
205 cr
= CM_Get_DevNode_Status_Ex(&m_Status
,
210 if (cr
== CR_SUCCESS
)
212 return ((m_Status
& DN_DISABLEABLE
) != 0);
219 CDeviceNode::IsDisabled()
222 cr
= CM_Get_DevNode_Status_Ex(&m_Status
,
227 if (cr
== CR_SUCCESS
)
229 return ((m_ProblemNumber
== CM_PROB_DISABLED
) || (m_ProblemNumber
== CM_PROB_HARDWARE_DISABLED
));
236 CDeviceNode::IsStarted()
239 cr
= CM_Get_DevNode_Status_Ex(&m_Status
,
244 if (cr
== CR_SUCCESS
)
246 return ((m_Status
& DN_STARTED
) != 0);
253 CDeviceNode::IsInstalled()
256 cr
= CM_Get_DevNode_Status_Ex(&m_Status
,
261 if (cr
== CR_SUCCESS
)
263 return ((m_Status
& DN_HAS_PROBLEM
) != 0 ||
264 (m_Status
& (DN_DRIVER_LOADED
| DN_STARTED
)) != 0);
271 CDeviceNode::CanUninstall()
274 cr
= CM_Get_DevNode_Status_Ex(&m_Status
,
279 if (cr
== CR_SUCCESS
)
281 if ((m_Status
& DN_ROOT_ENUMERATED
) != 0 &&
282 (m_Status
& DN_DISABLEABLE
) == 0)
290 CDeviceNode::EnableDevice(
292 _Out_
bool &NeedsReboot
295 bool Canceled
= false;
297 SetFlags(DI_NODI_DEFAULTACTION
, 0);
299 SP_PROPCHANGE_PARAMS pcp
;
300 pcp
.ClassInstallHeader
.cbSize
= sizeof(SP_CLASSINSTALL_HEADER
);
301 pcp
.ClassInstallHeader
.InstallFunction
= DIF_PROPERTYCHANGE
;
302 pcp
.StateChange
= (Enable
? DICS_ENABLE
: DICS_DISABLE
);
305 // check both scopes to make sure we can make the change
306 for (int i
= 0; i
< 2; i
++)
308 // Check globally first, then check config specific
309 pcp
.Scope
= (i
== 0) ? DICS_FLAG_CONFIGGENERAL
: DICS_FLAG_CONFIGSPECIFIC
;
311 if (SetupDiSetClassInstallParamsW(m_hDevInfo
,
313 &pcp
.ClassInstallHeader
,
314 sizeof(SP_PROPCHANGE_PARAMS
)))
316 SetupDiCallClassInstaller(DIF_PROPERTYCHANGE
,
321 if (GetLastError() == ERROR_CANCELLED
)
328 if (Canceled
== false)
330 pcp
.Scope
= DICS_FLAG_CONFIGSPECIFIC
;
331 if (SetupDiSetClassInstallParamsW(m_hDevInfo
,
333 &pcp
.ClassInstallHeader
,
334 sizeof(SP_PROPCHANGE_PARAMS
)))
336 SetupDiChangeState(m_hDevInfo
, &m_DevinfoData
);
342 // config specific enabling first, then global enabling.
343 // The global appears to be the one that starts the device
344 pcp
.Scope
= DICS_FLAG_GLOBAL
;
345 if (SetupDiSetClassInstallParamsW(m_hDevInfo
,
347 &pcp
.ClassInstallHeader
,
348 sizeof(SP_PROPCHANGE_PARAMS
)))
350 SetupDiChangeState(m_hDevInfo
, &m_DevinfoData
);
354 SetFlags(DI_PROPERTIES_CHANGE
, 0);
356 NeedsReboot
= ((GetFlags() & (DI_NEEDRESTART
| DI_NEEDREBOOT
)) != 0);
359 RemoveFlags(DI_NODI_DEFAULTACTION
, 0);
365 CDeviceNode::UninstallDevice()
367 if (CanUninstall() == false)
370 SP_REMOVEDEVICE_PARAMS RemoveDevParams
;
371 RemoveDevParams
.ClassInstallHeader
.cbSize
= sizeof(SP_CLASSINSTALL_HEADER
);
372 RemoveDevParams
.ClassInstallHeader
.InstallFunction
= DIF_REMOVE
;
373 RemoveDevParams
.Scope
= DI_REMOVEDEVICE_GLOBAL
;
374 RemoveDevParams
.HwProfile
= 0;
377 // We probably need to walk all the siblings of this
378 // device and ask if they're happy with the uninstall
382 SetupDiSetClassInstallParamsW(m_hDevInfo
,
384 &RemoveDevParams
.ClassInstallHeader
,
385 sizeof(SP_REMOVEDEVICE_PARAMS
));
386 SetupDiCallClassInstaller(DIF_REMOVE
, m_hDevInfo
, &m_DevinfoData
);
388 // Clear the install params
389 SetupDiSetClassInstallParamsW(m_hDevInfo
,
397 /* PRIVATE METHODS ******************************************************/
400 CDeviceNode::Cleanup()
409 SetupDiDestroyDeviceInfoList(m_hDevInfo
);
415 CDeviceNode::GetFlags()
417 SP_DEVINSTALL_PARAMS DevInstallParams
;
418 DevInstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS
);
419 if (SetupDiGetDeviceInstallParamsW(m_hDevInfo
,
423 return DevInstallParams
.Flags
;
429 CDeviceNode::SetFlags(
434 SP_DEVINSTALL_PARAMS DevInstallParams
;
435 DevInstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS
);
436 if (SetupDiGetDeviceInstallParamsW(m_hDevInfo
,
440 DevInstallParams
.Flags
|= Flags
;
441 DevInstallParams
.FlagsEx
|= FlagsEx
;
442 return (SetupDiSetDeviceInstallParamsW(m_hDevInfo
,
444 &DevInstallParams
) != 0);
450 CDeviceNode::RemoveFlags(
455 SP_DEVINSTALL_PARAMS DevInstallParams
;
456 DevInstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS
);
457 if (SetupDiGetDeviceInstallParamsW(m_hDevInfo
,
461 DevInstallParams
.Flags
&= ~Flags
;
462 DevInstallParams
.FlagsEx
&= ~FlagsEx
;
463 return (SetupDiSetDeviceInstallParamsW(m_hDevInfo
,
465 &DevInstallParams
) != 0);