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