[DEVMGR]
[reactos.git] / reactos / dll / win32 / devmgr / devmgmt / Node.cpp
1 /*
2 * PROJECT: ReactOS Device Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/devmgr/devmgr/node.cpp
5 * PURPOSE: Object for each device in the tree
6 * COPYRIGHT: Copyright 2015 Ged Murphy <gedmurphy@reactos.org>
7 *
8 */
9
10 #include "stdafx.h"
11 #include "devmgmt.h"
12 #include "Node.h"
13
14
15 /* PUBLIC METHODS *******************************************/
16
17 CNode::CNode(_In_ LPGUID ClassGuid,
18 _In_ PSP_CLASSIMAGELIST_DATA ImageListData) :
19 m_ImageListData(ImageListData),
20 m_NodeType(NodeClass),
21 m_DevInst(0),
22 m_DeviceId(NULL),
23 m_ClassImage(0),
24 m_Status(0),
25 m_ProblemNumber(0),
26 m_OverlayImage(0)
27 {
28 m_DisplayName[0] = UNICODE_NULL;
29 CopyMemory(&m_ClassGuid, ClassGuid, sizeof(GUID));
30 }
31
32 CNode::CNode(_In_opt_ DEVINST Device,
33 _In_ PSP_CLASSIMAGELIST_DATA ImageListData) :
34 m_ImageListData(ImageListData),
35 m_NodeType(NodeDevice),
36 m_DevInst(Device),
37 m_DeviceId(NULL),
38 m_ClassImage(0),
39 m_Status(0),
40 m_ProblemNumber(0),
41 m_OverlayImage(0)
42 {
43 m_DisplayName[0] = UNICODE_NULL;
44 CopyMemory(&m_ClassGuid, &GUID_NULL, sizeof(GUID));
45 }
46
47 CNode::~CNode()
48 {
49 Cleanup();
50 }
51
52 bool
53 CNode::Setup()
54 {
55 // TODO: Make this polymorphic
56
57 if (m_NodeType == NodeClass)
58 {
59 return SetupClassNode();
60 }
61 else if (m_NodeType == NodeDevice)
62 {
63 return SetupDeviceNode();
64 }
65
66 return FALSE;
67 }
68
69 bool
70 CNode::HasProperties()
71 {
72 return (m_DeviceId != NULL);
73 }
74
75 bool
76 CNode::IsHidden()
77 {
78 return ((m_Status & DN_NO_SHOW_IN_DM) != 0);
79 }
80
81 bool
82 CNode::CanDisable()
83 {
84 return (m_NodeType == NodeDevice && ((m_Status & DN_DISABLEABLE) != 0));
85 }
86
87 bool
88 CNode::IsDisabled()
89 {
90 return ((m_ProblemNumber & (CM_PROB_DISABLED | CM_PROB_HARDWARE_DISABLED)) != 0);
91 }
92
93 bool
94 CNode::IsStarted()
95 {
96 return ((m_Status & DN_STARTED) != 0);
97 }
98
99 bool
100 CNode::IsInstalled()
101 {
102 return ((m_Status & DN_HAS_PROBLEM) != 0 ||
103 (m_Status & (DN_DRIVER_LOADED | DN_STARTED)) != 0);
104 }
105
106
107 /* PRIVATE METHODS ******************************************/
108
109 bool
110 CNode::SetupClassNode()
111 {
112 DWORD RequiredSize, Type, Size;
113 DWORD Success;
114 HKEY hKey;
115
116 // Open the registry key for this class
117 hKey = SetupDiOpenClassRegKeyExW(&m_ClassGuid,
118 MAXIMUM_ALLOWED,
119 DIOCR_INSTALLER,
120 NULL,
121 0);
122 if (hKey != INVALID_HANDLE_VALUE)
123 {
124 Size = DISPLAY_NAME_LEN;
125 Type = REG_SZ;
126
127 // Lookup the class description (win7+)
128 Success = RegQueryValueExW(hKey,
129 L"ClassDesc",
130 NULL,
131 &Type,
132 (LPBYTE)m_DisplayName,
133 &Size);
134 if (Success == ERROR_SUCCESS)
135 {
136 // Check if the string starts with an @
137 if (m_DisplayName[0] == L'@')
138 {
139 // The description is located in a module resource
140 Success = ConvertResourceDescriptorToString(m_DisplayName, DISPLAY_NAME_LEN);
141 }
142 }
143 else if (Success == ERROR_FILE_NOT_FOUND)
144 {
145 // WinXP stores the description in the default value
146 Success = RegQueryValueExW(hKey,
147 NULL,
148 NULL,
149 &Type,
150 (LPBYTE)m_DisplayName,
151 &Size);
152 }
153
154 // Close the registry key
155 RegCloseKey(hKey);
156 }
157 else
158 {
159 Success = GetLastError();
160 }
161
162 // Check if we failed to get the class description
163 if (Success != ERROR_SUCCESS)
164 {
165 // Use the class name as the description
166 RequiredSize = DISPLAY_NAME_LEN;
167 (VOID)SetupDiClassNameFromGuidW(&m_ClassGuid,
168 m_DisplayName,
169 RequiredSize,
170 &RequiredSize);
171 }
172
173 // Get the image index for this class
174 (VOID)SetupDiGetClassImageIndex(m_ImageListData,
175 &m_ClassGuid,
176 &m_ClassImage);
177
178 return true;
179 }
180
181 bool
182 CNode::SetupDeviceNode()
183 {
184 WCHAR ClassGuidString[MAX_GUID_STRING_LEN];
185 ULONG ulLength;
186 CONFIGRET cr;
187
188 // ATLASSERT(m_DeviceId == NULL);
189
190 // Get the length of the device id string
191 cr = CM_Get_Device_ID_Size(&ulLength, m_DevInst, 0);
192 if (cr == CR_SUCCESS)
193 {
194 // We alloc heap here because this will be stored in the lParam of the TV
195 m_DeviceId = (LPWSTR)HeapAlloc(GetProcessHeap(),
196 0,
197 (ulLength + 1) * sizeof(WCHAR));
198 if (m_DeviceId)
199 {
200 // Now get the actual device id
201 cr = CM_Get_Device_IDW(m_DevInst,
202 m_DeviceId,
203 ulLength + 1,
204 0);
205 if (cr != CR_SUCCESS)
206 {
207 HeapFree(GetProcessHeap(), 0, m_DeviceId);
208 m_DeviceId = NULL;
209 }
210 }
211 }
212
213 // Make sure we got the string
214 if (m_DeviceId == NULL)
215 return false;
216
217 // Get the current status of the device
218 cr = CM_Get_DevNode_Status_Ex(&m_Status,
219 &m_ProblemNumber,
220 m_DevInst,
221 0,
222 NULL);
223 if (cr != CR_SUCCESS)
224 {
225 HeapFree(GetProcessHeap(), 0, m_DeviceId);
226 m_DeviceId = NULL;
227 return false;
228 }
229
230 // Check if the device has a problem
231 if (m_Status & DN_HAS_PROBLEM)
232 {
233 m_OverlayImage = 1;
234 }
235
236 // The disabled overlay takes precidence over the problem overlay
237 if (m_ProblemNumber & (CM_PROB_DISABLED | CM_PROB_HARDWARE_DISABLED))
238 {
239 m_OverlayImage = 2;
240 }
241
242
243 // Get the class guid for this device
244 ulLength = MAX_GUID_STRING_LEN * sizeof(WCHAR);
245 cr = CM_Get_DevNode_Registry_PropertyW(m_DevInst,
246 CM_DRP_CLASSGUID,
247 NULL,
248 ClassGuidString,
249 &ulLength,
250 0);
251 if (cr == CR_SUCCESS)
252 {
253 // Convert the string to a proper guid
254 CLSIDFromString(ClassGuidString, &m_ClassGuid);
255 }
256 else
257 {
258 // It's a device with no driver
259 m_ClassGuid = GUID_DEVCLASS_UNKNOWN;
260 }
261
262
263 // Get the image for the class this device is in
264 SetupDiGetClassImageIndex(m_ImageListData,
265 &m_ClassGuid,
266 &m_ClassImage);
267
268 // Get the description for the device
269 ulLength = DISPLAY_NAME_LEN * sizeof(WCHAR);
270 cr = CM_Get_DevNode_Registry_PropertyW(m_DevInst,
271 CM_DRP_FRIENDLYNAME,
272 NULL,
273 m_DisplayName,
274 &ulLength,
275 0);
276 if (cr != CR_SUCCESS)
277 {
278 ulLength = DISPLAY_NAME_LEN * sizeof(WCHAR);
279 cr = CM_Get_DevNode_Registry_PropertyW(m_DevInst,
280 CM_DRP_DEVICEDESC,
281 NULL,
282 m_DisplayName,
283 &ulLength,
284 0);
285
286 }
287
288 // Cleanup if something failed
289 if (cr != CR_SUCCESS)
290 {
291 HeapFree(GetProcessHeap(), 0, m_DeviceId);
292 m_DeviceId = NULL;
293 }
294
295 return (cr == CR_SUCCESS ? true : false);
296 }
297
298 void
299 CNode::Cleanup()
300 {
301 if (m_DeviceId)
302 {
303 HeapFree(GetProcessHeap(), 0, m_DeviceId);
304 m_DeviceId = NULL;
305 }
306 }
307
308 DWORD
309 CNode::ConvertResourceDescriptorToString(
310 _Inout_z_ LPWSTR ResourceDescriptor,
311 _In_ DWORD ResourceDescriptorSize
312 )
313 {
314 WCHAR ModulePath[MAX_PATH];
315 WCHAR ResString[256];
316 INT ResourceId;
317 HMODULE hModule;
318 LPWSTR ptr;
319 DWORD Size;
320 DWORD dwError;
321
322
323 // First check for a semi colon */
324 ptr = wcschr(ResourceDescriptor, L';');
325 if (ptr)
326 {
327 // This must be an inf based descriptor, the desc is after the semi colon
328 wcscpy_s(ResourceDescriptor, ResourceDescriptorSize, ++ptr);
329 dwError = ERROR_SUCCESS;
330 }
331 else
332 {
333 // This must be a dll resource based descriptor. Find the comma
334 ptr = wcschr(ResourceDescriptor, L',');
335 if (ptr == NULL) return ERROR_INVALID_DATA;
336
337 // Terminate the string where the comma was
338 *ptr = UNICODE_NULL;
339
340 // Expand any environment strings
341 Size = ExpandEnvironmentStringsW(&ResourceDescriptor[1], ModulePath, MAX_PATH);
342 if (Size > MAX_PATH) return ERROR_BUFFER_OVERFLOW;
343 if (Size == 0) return GetLastError();
344
345 // Put the comma back and move past it
346 *ptr = L',';
347 ptr++;
348
349 // Load the dll
350 hModule = LoadLibraryExW(ModulePath, NULL, LOAD_LIBRARY_AS_DATAFILE);
351 if (hModule == NULL) return GetLastError();
352
353 // Convert the resource id to a number
354 ResourceId = _wtoi(ptr);
355
356 // If the number is negative, make it positive
357 if (ResourceId < 0) ResourceId = -ResourceId;
358
359 // Load the string from the dll
360 if (LoadStringW(hModule, ResourceId, ResString, 256))
361 {
362 wcscpy_s(ResourceDescriptor, ResourceDescriptorSize, ResString);
363 dwError = ERROR_SUCCESS;
364 }
365 else
366 {
367 dwError = GetLastError();
368 }
369
370 // Free the library
371 FreeLibrary(hModule);
372 }
373
374 return dwError;
375 }