[NTDLL]
[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 static SP_CLASSIMAGELIST_DATA ImageListData;
13 static HDEVINFO hDevInfo;
14
15
16 VOID
17 FreeDeviceStrings(HWND hTreeView)
18 {
19 HTREEITEM hItem;
20
21 hItem = TreeView_GetRoot(hTreeView);
22
23 if (hItem)
24 {
25 hItem = TreeView_GetChild(hTreeView,
26 hItem);
27 /* loop the parent items */
28 while (hItem)
29 {
30 hItem = TreeView_GetChild(hTreeView,
31 hItem);
32 if (hItem == NULL)
33 break;
34
35 /* loop the child items and free the DeviceID */
36 while (TRUE)
37 {
38 HTREEITEM hOldItem;
39 TV_ITEM tvItem;
40 //TCHAR Buf[100];
41
42 tvItem.hItem = hItem;
43 tvItem.mask = TVIF_PARAM;// | TVIF_TEXT;
44 //tvItem.pszText = Buf;
45 //tvItem.cchTextMax = 99;
46
47 (void)TreeView_GetItem(hTreeView, &tvItem);
48
49 //MessageBox(NULL, Buf, NULL, 0);
50
51 HeapFree(GetProcessHeap(),
52 0,
53 (LPTSTR)tvItem.lParam);
54
55 hOldItem = hItem;
56
57 hItem = TreeView_GetNextSibling(hTreeView,
58 hItem);
59 if (hItem == NULL)
60 {
61 hItem = hOldItem;
62 break;
63 }
64 }
65
66 hItem = TreeView_GetParent(hTreeView,
67 hItem);
68 hItem = TreeView_GetNextSibling(hTreeView,
69 hItem);
70 }
71 }
72 }
73
74
75 VOID
76 OpenPropSheet(HWND hTreeView,
77 HTREEITEM hItem)
78 {
79 TV_ITEM tvItem;
80
81 tvItem.hItem = hItem;
82 tvItem.mask = TVIF_PARAM;
83
84 if (TreeView_GetItem(hTreeView, &tvItem) &&
85 (LPTSTR)tvItem.lParam != NULL)
86 {
87 DevicePropertiesExW(hTreeView,
88 NULL,
89 (LPTSTR)tvItem.lParam,
90 DPF_EXTENDED,
91 FALSE);
92 }
93
94 }
95
96
97 static HTREEITEM
98 InsertIntoTreeView(HWND hTreeView,
99 HTREEITEM hRoot,
100 LPTSTR lpLabel,
101 LPTSTR DeviceID,
102 INT DevImage,
103 LONG DevProb)
104 {
105 TV_ITEM tvi;
106 TV_INSERTSTRUCT tvins;
107
108 ZeroMemory(&tvi, sizeof(tvi));
109 ZeroMemory(&tvins, sizeof(tvins));
110
111 tvi.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
112 tvi.pszText = lpLabel;
113 tvi.cchTextMax = lstrlen(lpLabel);
114 tvi.lParam = (LPARAM)DeviceID;
115 tvi.iImage = DevImage;
116 tvi.iSelectedImage = DevImage;
117
118 if (DevProb != 0)
119 {
120 tvi.stateMask = TVIS_OVERLAYMASK;
121
122 if (DevProb == CM_PROB_DISABLED)
123 {
124 /* FIXME: set the overlay icon */
125 }
126
127 }
128
129 tvins.item = tvi;
130 tvins.hParent = hRoot;
131
132 return TreeView_InsertItem(hTreeView, &tvins);
133 }
134
135
136 static INT
137 EnumDeviceClasses(INT ClassIndex,
138 LPTSTR DevClassName,
139 LPTSTR DevClassDesc,
140 BOOL *DevPresent,
141 INT *ClassImage)
142 {
143 GUID ClassGuid;
144 HKEY KeyClass;
145 TCHAR ClassName[MAX_CLASS_NAME_LEN];
146 DWORD RequiredSize = MAX_CLASS_NAME_LEN;
147 UINT Ret;
148
149 *DevPresent = FALSE;
150 *DevClassName = _T('\0');
151
152 Ret = CM_Enumerate_Classes(ClassIndex,
153 &ClassGuid,
154 0);
155 if (Ret != CR_SUCCESS)
156 {
157 /* all classes enumerated */
158 if(Ret == CR_NO_SUCH_VALUE)
159 {
160 hDevInfo = NULL;
161 return -1;
162 }
163
164 if (Ret == CR_INVALID_DATA)
165 {
166 ; /*FIXME: what should we do here? */
167 }
168
169 /* handle other errors... */
170 }
171
172 if (SetupDiClassNameFromGuid(&ClassGuid,
173 ClassName,
174 RequiredSize,
175 &RequiredSize))
176 {
177 lstrcpy(DevClassName, ClassName);
178 }
179
180 if (!SetupDiGetClassImageIndex(&ImageListData,
181 &ClassGuid,
182 ClassImage))
183 {
184 /* FIXME: can we do this?
185 * Set the blank icon: IDI_SETUPAPI_BLANK = 41
186 * it'll be image 24 in the imagelist */
187 *ClassImage = 24;
188 }
189
190 /* Get device info for all devices of a particular class */
191 hDevInfo = SetupDiGetClassDevs(&ClassGuid,
192 NULL,
193 NULL,
194 DIGCF_PRESENT);
195 if (hDevInfo == INVALID_HANDLE_VALUE)
196 {
197 hDevInfo = NULL;
198 return 0;
199 }
200
201 KeyClass = SetupDiOpenClassRegKeyEx(&ClassGuid,
202 MAXIMUM_ALLOWED,
203 DIOCR_INSTALLER,
204 NULL,
205 0);
206 if (KeyClass != INVALID_HANDLE_VALUE)
207 {
208
209 LONG dwSize = MAX_DEV_LEN;
210
211 if (RegQueryValue(KeyClass,
212 NULL,
213 DevClassDesc,
214 &dwSize) != ERROR_SUCCESS)
215 {
216 *DevClassDesc = _T('\0');
217 }
218 }
219 else
220 {
221 return -3;
222 }
223
224 *DevPresent = TRUE;
225
226 RegCloseKey(KeyClass);
227
228 return 0;
229 }
230
231
232 static LONG
233 EnumDevices(INT index,
234 LPTSTR DeviceClassName,
235 LPTSTR DeviceName,
236 LPTSTR *DeviceID)
237 {
238 SP_DEVINFO_DATA DeviceInfoData;
239 CONFIGRET cr;
240 ULONG Status, ProblemNumber;
241 DWORD DevIdSize;
242
243 *DeviceName = _T('\0');
244 *DeviceID = NULL;
245
246 ZeroMemory(&DeviceInfoData, sizeof(SP_DEVINFO_DATA));
247 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
248
249 if (!SetupDiEnumDeviceInfo(hDevInfo,
250 index,
251 &DeviceInfoData))
252 {
253 /* no such device */
254 return -1;
255 }
256
257 /* get the device ID */
258 if (!SetupDiGetDeviceInstanceId(hDevInfo,
259 &DeviceInfoData,
260 NULL,
261 0,
262 &DevIdSize))
263 {
264 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
265 {
266 (*DeviceID) = (LPTSTR)HeapAlloc(GetProcessHeap(),
267 0,
268 DevIdSize * sizeof(TCHAR));
269 if (*DeviceID)
270 {
271 if (!SetupDiGetDeviceInstanceId(hDevInfo,
272 &DeviceInfoData,
273 *DeviceID,
274 DevIdSize,
275 NULL))
276 {
277 HeapFree(GetProcessHeap(),
278 0,
279 *DeviceID);
280 *DeviceID = NULL;
281 }
282 }
283 }
284 }
285
286 /* get the device's friendly name */
287 if (!SetupDiGetDeviceRegistryProperty(hDevInfo,
288 &DeviceInfoData,
289 SPDRP_FRIENDLYNAME,
290 0,
291 (BYTE*)DeviceName,
292 MAX_DEV_LEN,
293 NULL))
294 {
295 /* if the friendly name fails, try the description instead */
296 SetupDiGetDeviceRegistryProperty(hDevInfo,
297 &DeviceInfoData,
298 SPDRP_DEVICEDESC,
299 0,
300 (BYTE*)DeviceName,
301 MAX_DEV_LEN,
302 NULL);
303 }
304
305 cr = CM_Get_DevNode_Status_Ex(&Status,
306 &ProblemNumber,
307 DeviceInfoData.DevInst,
308 0,
309 NULL);
310 if (cr == CR_SUCCESS && (Status & DN_HAS_PROBLEM))
311 {
312 return ProblemNumber;
313 }
314
315 return 0;
316 }
317
318
319 VOID
320 ListDevicesByType(HWND hTreeView,
321 HTREEITEM hRoot)
322 {
323 HTREEITEM hDevItem;
324 TCHAR DevName[MAX_DEV_LEN];
325 TCHAR DevDesc[MAX_DEV_LEN];
326 LPTSTR DeviceID = NULL;
327 BOOL DevExist = FALSE;
328 INT ClassRet;
329 INT index = 0;
330 INT DevImage;
331
332 do
333 {
334 ClassRet = EnumDeviceClasses(index,
335 DevName,
336 DevDesc,
337 &DevExist,
338 &DevImage);
339
340 if ((ClassRet != -1) && (DevExist))
341 {
342 TCHAR DeviceName[MAX_DEV_LEN];
343 INT DevIndex = 0;
344 LONG Ret;
345
346 if (DevDesc[0] != _T('\0'))
347 {
348 hDevItem = InsertIntoTreeView(hTreeView,
349 hRoot,
350 DevDesc,
351 NULL,
352 DevImage,
353 0);
354 }
355 else
356 {
357 hDevItem = InsertIntoTreeView(hTreeView,
358 hRoot,
359 DevName,
360 NULL,
361 DevImage,
362 0);
363 }
364
365 do
366 {
367 Ret = EnumDevices(DevIndex,
368 DevName,
369 DeviceName,
370 &DeviceID);
371 if (Ret >= 0)
372 {
373 InsertIntoTreeView(hTreeView,
374 hDevItem,
375 DeviceName,
376 DeviceID,
377 DevImage,
378 Ret);
379 }
380
381 DevIndex++;
382
383 } while (Ret != -1);
384
385 /* kill InfoList initialized in EnumDeviceClasses */
386 if (hDevInfo)
387 {
388 SetupDiDestroyDeviceInfoList(hDevInfo);
389 hDevInfo = NULL;
390 }
391
392 /* don't insert classes with no devices */
393 if (!TreeView_GetChild(hTreeView,
394 hDevItem))
395 {
396 (void)TreeView_DeleteItem(hTreeView,
397 hDevItem);
398 }
399 else
400 {
401 (void)TreeView_SortChildren(hTreeView,
402 hDevItem,
403 0);
404 }
405 }
406
407 index++;
408
409 } while (ClassRet != -1);
410
411 (void)TreeView_Expand(hTreeView,
412 hRoot,
413 TVE_EXPAND);
414
415 (void)TreeView_SortChildren(hTreeView,
416 hRoot,
417 0);
418 }
419
420
421 HTREEITEM
422 InitTreeView(HWND hTreeView)
423 {
424 HTREEITEM hRoot;
425 HBITMAP hComp;
426 TCHAR ComputerName[MAX_PATH];
427 DWORD dwSize = MAX_PATH;
428 INT RootImage;
429
430 (void)TreeView_DeleteAllItems(hTreeView);
431
432 /* get the device image List */
433 ImageListData.cbSize = sizeof(ImageListData);
434 SetupDiGetClassImageList(&ImageListData);
435
436 hComp = LoadBitmap(hInstance,
437 MAKEINTRESOURCE(IDB_ROOT_IMAGE));
438
439 ImageList_Add(ImageListData.ImageList,
440 hComp,
441 NULL);
442
443 DeleteObject(hComp);
444
445 (void)TreeView_SetImageList(hTreeView,
446 ImageListData.ImageList,
447 TVSIL_NORMAL);
448
449 if (!GetComputerName(ComputerName,
450 &dwSize))
451 {
452 ComputerName[0] = _T('\0');
453 }
454
455 RootImage = ImageList_GetImageCount(ImageListData.ImageList) - 1;
456
457 /* insert the root item into the tree */
458 hRoot = InsertIntoTreeView(hTreeView,
459 NULL,
460 ComputerName,
461 NULL,
462 RootImage,
463 0);
464
465 return hRoot;
466 }