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