Sync to trunk r65566.
[reactos.git] / base / applications / mscutils / devmgmt / enumdevices.c
1 /*
2 * PROJECT: ReactOS Device Managment
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/devmgmt/enumdevices.c
5 * PURPOSE: Enumerates all devices on the local machine
6 * COPYRIGHT: Copyright 2006 Ged Murphy <gedmurphy@gmail.com>
7 *
8 */
9
10 #include "precomp.h"
11
12 #include <cfgmgr32.h>
13 #include <dll/devmgr/devmgr.h>
14 #include <initguid.h>
15 #include <devguid.h>
16
17 static SP_CLASSIMAGELIST_DATA ImageListData;
18
19
20 VOID
21 FreeDeviceStrings(HWND hTreeView)
22 {
23 HTREEITEM hItem;
24
25 hItem = TreeView_GetRoot(hTreeView);
26
27 if (hItem)
28 {
29 hItem = TreeView_GetChild(hTreeView,
30 hItem);
31 /* loop the parent items */
32 while (hItem)
33 {
34 hItem = TreeView_GetChild(hTreeView,
35 hItem);
36 if (hItem == NULL)
37 break;
38
39 /* loop the child items and free the DeviceID */
40 while (TRUE)
41 {
42 HTREEITEM hOldItem;
43 TV_ITEM tvItem;
44 //TCHAR Buf[100];
45
46 tvItem.hItem = hItem;
47 tvItem.mask = TVIF_PARAM;// | TVIF_TEXT;
48 //tvItem.pszText = Buf;
49 //tvItem.cchTextMax = 99;
50
51 (void)TreeView_GetItem(hTreeView, &tvItem);
52
53 //MessageBox(NULL, Buf, NULL, 0);
54
55 HeapFree(GetProcessHeap(),
56 0,
57 (LPTSTR)tvItem.lParam);
58
59 hOldItem = hItem;
60
61 hItem = TreeView_GetNextSibling(hTreeView,
62 hItem);
63 if (hItem == NULL)
64 {
65 hItem = hOldItem;
66 break;
67 }
68 }
69
70 hItem = TreeView_GetParent(hTreeView,
71 hItem);
72 hItem = TreeView_GetNextSibling(hTreeView,
73 hItem);
74 }
75 }
76 }
77
78
79 VOID
80 OpenPropSheet(HWND hTreeView,
81 HTREEITEM hItem)
82 {
83 TV_ITEM tvItem;
84
85 tvItem.hItem = hItem;
86 tvItem.mask = TVIF_PARAM;
87
88 if (TreeView_GetItem(hTreeView, &tvItem) &&
89 (LPTSTR)tvItem.lParam != NULL)
90 {
91 DevicePropertiesExW(hTreeView,
92 NULL,
93 (LPTSTR)tvItem.lParam,
94 DPF_EXTENDED,
95 FALSE);
96 }
97 }
98
99
100 static HTREEITEM
101 InsertIntoTreeView(HWND hTreeView,
102 HTREEITEM hRoot,
103 LPTSTR lpLabel,
104 LPTSTR DeviceID,
105 INT DevImage,
106 UINT OverlayImage)
107 {
108 TV_ITEM tvi;
109 TV_INSERTSTRUCT tvins;
110
111 ZeroMemory(&tvi, sizeof(tvi));
112 ZeroMemory(&tvins, sizeof(tvins));
113
114 tvi.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
115 tvi.pszText = lpLabel;
116 tvi.cchTextMax = lstrlen(lpLabel);
117 tvi.lParam = (LPARAM)DeviceID;
118 tvi.iImage = DevImage;
119 tvi.iSelectedImage = DevImage;
120
121 if (OverlayImage != 0)
122 {
123 tvi.mask |= TVIF_STATE;
124 tvi.stateMask = TVIS_OVERLAYMASK;
125 tvi.state = INDEXTOOVERLAYMASK(OverlayImage);
126 }
127
128 tvins.item = tvi;
129 tvins.hParent = hRoot;
130
131 return TreeView_InsertItem(hTreeView, &tvins);
132 }
133
134
135 static
136 ULONG
137 GetClassCount(VOID)
138 {
139 ULONG ulClassIndex;
140 GUID ClassGuid;
141 CONFIGRET cr;
142
143 for (ulClassIndex = 0; ; ulClassIndex++)
144 {
145 cr = CM_Enumerate_Classes(ulClassIndex,
146 &ClassGuid,
147 0);
148 if (cr == CR_NO_SUCH_VALUE)
149 return ulClassIndex;
150 }
151 }
152
153
154 static
155 PDEVCLASS_ENTRY
156 GetClassFromClassGuid(
157 PDEVCLASS_ENTRY pClassArray,
158 ULONG ulClassCount,
159 GUID *pGuid)
160 {
161 PDEVCLASS_ENTRY pClass, pUnknownClass = NULL;
162 ULONG i;
163
164 for (i = 0; i < ulClassCount; i++)
165 {
166 pClass = &pClassArray[i];
167
168 if (IsEqualGUID(&pClass->ClassGuid, &GUID_DEVCLASS_UNKNOWN))
169 pUnknownClass = pClass;
170
171 if (IsEqualGUID(&pClass->ClassGuid, pGuid))
172 return pClass;
173 }
174
175 return pUnknownClass;
176 }
177
178
179 static
180 VOID
181 EnumDeviceClasses(
182 HWND hTreeView,
183 HTREEITEM hRoot,
184 PDEVCLASS_ENTRY pClassArray,
185 ULONG ClassCount)
186 {
187 WCHAR ClassName[MAX_DEV_LEN];
188 WCHAR ClassDesc[MAX_DEV_LEN];
189 PDEVCLASS_ENTRY pClass;
190 ULONG ClassIndex;
191 DWORD dwSize;
192 LONG lSize;
193 HKEY hKey;
194 CONFIGRET cr;
195
196 for (ClassIndex = 0; ClassIndex < ClassCount; ClassIndex++)
197 {
198 pClass = &pClassArray[ClassIndex];
199
200 cr = CM_Enumerate_Classes(ClassIndex,
201 &pClass->ClassGuid,
202 0);
203 if (cr == CR_NO_SUCH_VALUE)
204 return;
205
206 dwSize = MAX_CLASS_NAME_LEN;
207 if (!SetupDiClassNameFromGuid(&pClass->ClassGuid,
208 ClassName,
209 dwSize,
210 &dwSize))
211 {
212 ClassName[0] = _T('\0');
213 }
214
215 if (!SetupDiGetClassImageIndex(&ImageListData,
216 &pClass->ClassGuid,
217 &pClass->ClassImage))
218 {
219 /* FIXME: can we do this?
220 * Set the blank icon: IDI_SETUPAPI_BLANK = 41
221 * it'll be image 24 in the imagelist */
222 pClass->ClassImage = 24;
223 }
224
225 hKey = SetupDiOpenClassRegKeyEx(&pClass->ClassGuid,
226 MAXIMUM_ALLOWED,
227 DIOCR_INSTALLER,
228 NULL,
229 0);
230 if (hKey != INVALID_HANDLE_VALUE)
231 {
232 lSize = MAX_DEV_LEN;
233 if (RegQueryValue(hKey,
234 NULL,
235 ClassDesc,
236 &lSize) != ERROR_SUCCESS)
237 {
238 ClassDesc[0] = _T('\0');
239 }
240
241 RegCloseKey(hKey);
242 }
243
244 pClass->hItem = InsertIntoTreeView(hTreeView,
245 hRoot,
246 (ClassDesc[0] != _T('\0')) ? ClassDesc : ClassName,
247 NULL,
248 pClass->ClassImage,
249 0);
250 }
251 }
252
253
254 static
255 VOID
256 EnumDevices(
257 HWND hTreeView,
258 PDEVCLASS_ENTRY pClassArray,
259 ULONG ulClassCount,
260 BOOL bShowHidden)
261 {
262 HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
263 SP_DEVINFO_DATA DeviceInfoData;
264 ULONG Status, Problem;
265 DWORD DevIdSize;
266 TCHAR DeviceName[MAX_DEV_LEN];
267 DWORD DevIndex;
268 LPTSTR InstanceId;
269 PDEVCLASS_ENTRY pClass;
270 UINT OverlayImage;
271 CONFIGRET cr;
272
273
274 /* Get device info for all devices of a particular class */
275 hDevInfo = SetupDiGetClassDevs(NULL,
276 NULL,
277 NULL,
278 DIGCF_PRESENT | DIGCF_ALLCLASSES);
279 if (hDevInfo == INVALID_HANDLE_VALUE)
280 return;
281
282 for (DevIndex = 0; ; DevIndex++)
283 {
284 ZeroMemory(&DeviceInfoData, sizeof(SP_DEVINFO_DATA));
285 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
286
287 InstanceId = NULL;
288 DeviceName[0] = _T('\0');
289 OverlayImage = 0;
290
291 if (!SetupDiEnumDeviceInfo(hDevInfo,
292 DevIndex,
293 &DeviceInfoData))
294 break;
295
296 if (bShowHidden == FALSE &&
297 (IsEqualGUID(&DeviceInfoData.ClassGuid, &GUID_DEVCLASS_LEGACYDRIVER) ||
298 IsEqualGUID(&DeviceInfoData.ClassGuid, &GUID_DEVCLASS_VOLUME)))
299 continue;
300
301 pClass = GetClassFromClassGuid(pClassArray,
302 ulClassCount,
303 &DeviceInfoData.ClassGuid);
304
305 /* get the device ID */
306 if (!SetupDiGetDeviceInstanceId(hDevInfo,
307 &DeviceInfoData,
308 NULL,
309 0,
310 &DevIdSize))
311 {
312 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
313 {
314 InstanceId = (LPTSTR)HeapAlloc(GetProcessHeap(),
315 0,
316 DevIdSize * sizeof(TCHAR));
317 if (InstanceId != NULL)
318 {
319 if (!SetupDiGetDeviceInstanceId(hDevInfo,
320 &DeviceInfoData,
321 InstanceId,
322 DevIdSize,
323 NULL))
324 {
325 HeapFree(GetProcessHeap(),
326 0,
327 InstanceId);
328 InstanceId = NULL;
329 }
330 }
331 }
332 }
333
334 /* Skip the root device */
335 if (InstanceId != NULL &&
336 _tcscmp(InstanceId, _T("HTREE\\ROOT\\0")) == 0)
337 {
338 HeapFree(GetProcessHeap(),
339 0,
340 InstanceId);
341 InstanceId = NULL;
342 continue;
343 }
344
345 /* Get the device's friendly name */
346 if (!SetupDiGetDeviceRegistryProperty(hDevInfo,
347 &DeviceInfoData,
348 SPDRP_FRIENDLYNAME,
349 0,
350 (BYTE*)DeviceName,
351 MAX_DEV_LEN,
352 NULL))
353 {
354 /* If the friendly name fails, try the description instead */
355 SetupDiGetDeviceRegistryProperty(hDevInfo,
356 &DeviceInfoData,
357 SPDRP_DEVICEDESC,
358 0,
359 (BYTE*)DeviceName,
360 MAX_DEV_LEN,
361 NULL);
362 }
363
364 cr = CM_Get_DevNode_Status_Ex(&Status,
365 &Problem,
366 DeviceInfoData.DevInst,
367 0,
368 NULL);
369 if ((cr == CR_SUCCESS) &&
370 (Status & DN_HAS_PROBLEM))
371 {
372 if (Problem == CM_PROB_DISABLED ||
373 Problem == CM_PROB_HARDWARE_DISABLED)
374 OverlayImage = 2;
375 else
376 OverlayImage = 1;
377 }
378
379 InsertIntoTreeView(hTreeView,
380 pClass->hItem,
381 DeviceName,
382 InstanceId,
383 pClass->ClassImage,
384 OverlayImage);
385
386 if (OverlayImage != 0)
387 {
388 /* Expand the class if the device has a problem */
389 (void)TreeView_Expand(hTreeView,
390 pClass->hItem,
391 TVE_EXPAND);
392 }
393
394 pClass->bUsed = TRUE;
395 }
396
397 if (hDevInfo != INVALID_HANDLE_VALUE)
398 SetupDiDestroyDeviceInfoList(hDevInfo);
399 }
400
401
402 static
403 VOID
404 CleanupDeviceClasses(
405 HWND hTreeView,
406 PDEVCLASS_ENTRY pClassArray,
407 ULONG ulClassCount)
408 {
409 PDEVCLASS_ENTRY pClass;
410 ULONG i;
411
412 for (i = 0; i < ulClassCount; i++)
413 {
414 pClass = &pClassArray[i];
415
416 if (pClass->bUsed == FALSE)
417 (void)TreeView_DeleteItem(hTreeView,
418 pClass->hItem);
419 else
420 (void)TreeView_SortChildren(hTreeView,
421 pClass->hItem,
422 0);
423 }
424 }
425
426
427 VOID
428 ListDevicesByType(HWND hTreeView,
429 HTREEITEM hRoot,
430 BOOL bShowHidden)
431 {
432 PDEVCLASS_ENTRY pClassArray;
433 ULONG ulClassCount;
434
435 ulClassCount = GetClassCount();
436
437 pClassArray = HeapAlloc(GetProcessHeap(),
438 HEAP_ZERO_MEMORY,
439 ulClassCount * sizeof(DEVCLASS_ENTRY));
440 if (pClassArray == NULL)
441 return;
442
443 EnumDeviceClasses(hTreeView,
444 hRoot,
445 pClassArray,
446 ulClassCount);
447
448 EnumDevices(hTreeView,
449 pClassArray,
450 ulClassCount,
451 bShowHidden);
452
453 CleanupDeviceClasses(hTreeView,
454 pClassArray,
455 ulClassCount);
456
457 if (pClassArray != NULL)
458 HeapFree(GetProcessHeap(), 0, pClassArray);
459
460 (void)TreeView_Expand(hTreeView,
461 hRoot,
462 TVE_EXPAND);
463
464 (void)TreeView_SortChildren(hTreeView,
465 hRoot,
466 0);
467
468 (void)TreeView_SelectItem(hTreeView,
469 hRoot);
470 }
471
472
473 static HTREEITEM
474 AddDeviceToTree(HWND hTreeView,
475 HTREEITEM hRoot,
476 DEVINST dnDevInst,
477 BOOL bShowHidden)
478 {
479 TCHAR DevName[MAX_DEV_LEN];
480 TCHAR FriendlyName[MAX_DEV_LEN];
481 TCHAR ClassGuidString[MAX_GUID_STRING_LEN];
482 GUID ClassGuid;
483 ULONG ulLength;
484 LPTSTR DeviceID = NULL;
485 INT ClassImage = 24;
486 CONFIGRET cr;
487
488 ulLength = MAX_GUID_STRING_LEN * sizeof(TCHAR);
489 cr = CM_Get_DevNode_Registry_Property(dnDevInst,
490 CM_DRP_CLASSGUID,
491 NULL,
492 ClassGuidString,
493 &ulLength,
494 0);
495 if (cr == CR_SUCCESS)
496 {
497 pSetupGuidFromString(ClassGuidString, &ClassGuid);
498
499 if (bShowHidden == FALSE &&
500 (IsEqualGUID(&ClassGuid, &GUID_DEVCLASS_LEGACYDRIVER) ||
501 IsEqualGUID(&ClassGuid, &GUID_DEVCLASS_VOLUME)))
502 return NULL;
503 }
504 else
505 {
506 /* It's a device with no driver */
507 ClassGuid = GUID_DEVCLASS_UNKNOWN;
508 }
509
510 cr = CM_Get_Device_ID(dnDevInst,
511 DevName,
512 MAX_DEV_LEN,
513 0);
514 if (cr != CR_SUCCESS)
515 return NULL;
516
517 ulLength = MAX_DEV_LEN * sizeof(TCHAR);
518 cr = CM_Get_DevNode_Registry_Property(dnDevInst,
519 CM_DRP_FRIENDLYNAME,
520 NULL,
521 FriendlyName,
522 &ulLength,
523 0);
524 if (cr != CR_SUCCESS)
525 {
526 ulLength = MAX_DEV_LEN * sizeof(TCHAR);
527 cr = CM_Get_DevNode_Registry_Property(dnDevInst,
528 CM_DRP_DEVICEDESC,
529 NULL,
530 FriendlyName,
531 &ulLength,
532 0);
533 if (cr != CR_SUCCESS)
534 return NULL;
535 }
536
537 if (!SetupDiGetClassImageIndex(&ImageListData,
538 &ClassGuid,
539 &ClassImage))
540 {
541 /* FIXME: can we do this?
542 * Set the blank icon: IDI_SETUPAPI_BLANK = 41
543 * it'll be image 24 in the imagelist */
544 ClassImage = 24;
545 }
546
547 if (DevName != NULL)
548 {
549 DeviceID = HeapAlloc(GetProcessHeap(),
550 0,
551 (lstrlen(DevName) + 1) * sizeof(TCHAR));
552 if (DeviceID == NULL)
553 {
554 return NULL;
555 }
556
557 lstrcpy(DeviceID, DevName);
558 }
559
560 return InsertIntoTreeView(hTreeView,
561 hRoot,
562 FriendlyName,
563 DeviceID,
564 ClassImage,
565 0);
566 }
567
568
569 static VOID
570 EnumChildDevices(HWND hTreeView,
571 HTREEITEM hRoot,
572 DEVINST dnParentDevInst,
573 BOOL bShowHidden)
574 {
575 HTREEITEM hDevItem;
576 DEVINST dnDevInst;
577 CONFIGRET cr;
578
579 cr = CM_Get_Child(&dnDevInst,
580 dnParentDevInst,
581 0);
582 if (cr != CR_SUCCESS)
583 return;
584
585 hDevItem = AddDeviceToTree(hTreeView,
586 hRoot,
587 dnDevInst,
588 bShowHidden);
589 if (hDevItem != NULL)
590 {
591 EnumChildDevices(hTreeView,
592 hDevItem,
593 dnDevInst,
594 bShowHidden);
595 }
596
597 while (cr == CR_SUCCESS)
598 {
599 cr = CM_Get_Sibling(&dnDevInst,
600 dnDevInst,
601 0);
602 if (cr != CR_SUCCESS)
603 break;
604
605 hDevItem = AddDeviceToTree(hTreeView,
606 hRoot,
607 dnDevInst,
608 bShowHidden);
609 if (hDevItem != NULL)
610 {
611 EnumChildDevices(hTreeView,
612 hDevItem,
613 dnDevInst,
614 bShowHidden);
615 }
616 }
617
618 (void)TreeView_SortChildren(hTreeView,
619 hRoot,
620 0);
621 }
622
623
624 VOID
625 ListDevicesByConnection(HWND hTreeView,
626 HTREEITEM hRoot,
627 BOOL bShowHidden)
628 {
629 DEVINST devInst;
630 CONFIGRET cr;
631
632 cr = CM_Locate_DevNode(&devInst,
633 NULL,
634 CM_LOCATE_DEVNODE_NORMAL);
635 if (cr == CR_SUCCESS)
636 EnumChildDevices(hTreeView,
637 hRoot,
638 devInst,
639 bShowHidden);
640
641 (void)TreeView_Expand(hTreeView,
642 hRoot,
643 TVE_EXPAND);
644
645 (void)TreeView_SelectItem(hTreeView,
646 hRoot);
647 }
648
649
650 HTREEITEM
651 InitTreeView(HWND hTreeView)
652 {
653 HTREEITEM hRoot;
654 TCHAR ComputerName[MAX_PATH];
655 DWORD dwSize = MAX_PATH;
656 INT RootImage;
657
658 (void)TreeView_DeleteAllItems(hTreeView);
659
660 /* Get the device image list */
661 ImageListData.cbSize = sizeof(ImageListData);
662 SetupDiGetClassImageList(&ImageListData);
663
664 (void)TreeView_SetImageList(hTreeView,
665 ImageListData.ImageList,
666 TVSIL_NORMAL);
667
668 if (!GetComputerName(ComputerName,
669 &dwSize))
670 {
671 ComputerName[0] = _T('\0');
672 }
673
674 /* Get the image index of the computer class */
675 SetupDiGetClassImageIndex(&ImageListData,
676 &GUID_DEVCLASS_COMPUTER,
677 &RootImage);
678
679 /* Insert the root item into the tree */
680 hRoot = InsertIntoTreeView(hTreeView,
681 NULL,
682 ComputerName,
683 NULL,
684 RootImage,
685 0);
686
687 return hRoot;
688 }