- support remote device property sheets
[reactos.git] / reactos / lib / devmgr / misc.c
1 /*
2 * ReactOS Device Manager Applet
3 * Copyright (C) 2004 - 2005 ReactOS Team
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19 /* $Id: devmgr.c 12852 2005-01-06 13:58:04Z mf $
20 *
21 * PROJECT: ReactOS devmgr.dll
22 * FILE: lib/devmgr/misc.c
23 * PURPOSE: ReactOS Device Manager
24 * PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
25 * UPDATE HISTORY:
26 * 2005/11/24 Created
27 */
28 #include <precomp.h>
29
30 HINSTANCE hDllInstance = NULL;
31
32
33 static INT
34 LengthOfStrResource(IN HINSTANCE hInst,
35 IN UINT uID)
36 {
37 HRSRC hrSrc;
38 HGLOBAL hRes;
39 LPWSTR lpName, lpStr;
40
41 if (hInst == NULL)
42 {
43 return -1;
44 }
45
46 /* There are always blocks of 16 strings */
47 lpName = (LPWSTR)MAKEINTRESOURCE((uID >> 4) + 1);
48
49 /* Find the string table block */
50 if ((hrSrc = FindResourceW(hInst, lpName, (LPWSTR)RT_STRING)) &&
51 (hRes = LoadResource(hInst, hrSrc)) &&
52 (lpStr = LockResource(hRes)))
53 {
54 UINT x;
55
56 /* Find the string we're looking for */
57 uID &= 0xF; /* position in the block, same as % 16 */
58 for (x = 0; x < uID; x++)
59 {
60 lpStr += (*lpStr) + 1;
61 }
62
63 /* Found the string */
64 return (int)(*lpStr);
65 }
66 return -1;
67 }
68
69
70 static INT
71 AllocAndLoadString(OUT LPWSTR *lpTarget,
72 IN HINSTANCE hInst,
73 IN UINT uID)
74 {
75 INT ln;
76
77 ln = LengthOfStrResource(hInst,
78 uID);
79 if (ln++ > 0)
80 {
81 (*lpTarget) = (LPWSTR)LocalAlloc(LMEM_FIXED,
82 ln * sizeof(WCHAR));
83 if ((*lpTarget) != NULL)
84 {
85 INT Ret;
86 if (!(Ret = LoadStringW(hInst, uID, *lpTarget, ln)))
87 {
88 LocalFree((HLOCAL)(*lpTarget));
89 }
90 return Ret;
91 }
92 }
93 return 0;
94 }
95
96
97 static INT
98 AllocAndLoadStringsCat(OUT LPWSTR *lpTarget,
99 IN HINSTANCE hInst,
100 IN UINT uID1,
101 IN UINT uID2)
102 {
103 INT ln;
104
105 ln = LengthOfStrResource(hInst,
106 uID1);
107 ln += LengthOfStrResource(hInst,
108 uID2);
109 if (ln++ > 0)
110 {
111 (*lpTarget) = (LPWSTR)LocalAlloc(LMEM_FIXED,
112 ln * sizeof(WCHAR));
113 if ((*lpTarget) != NULL)
114 {
115 INT Ret, Ret2 = 0;
116 if (!(Ret = LoadStringW(hInst, uID1, *lpTarget, ln)))
117 {
118 LocalFree((HLOCAL)(*lpTarget));
119 }
120 else if (!(Ret2 = LoadStringW(hInst, uID2, *lpTarget + Ret, ln - Ret)))
121 {
122 LocalFree((HLOCAL)(*lpTarget));
123 Ret = 0;
124 }
125 return Ret + Ret2;
126 }
127 }
128 return 0;
129 }
130
131
132 DWORD
133 LoadAndFormatString(IN HINSTANCE hInstance,
134 IN UINT uID,
135 OUT LPWSTR *lpTarget,
136 ...)
137 {
138 DWORD Ret = 0;
139 LPWSTR lpFormat;
140 va_list lArgs;
141
142 if (AllocAndLoadString(&lpFormat,
143 hInstance,
144 uID) > 0)
145 {
146 va_start(lArgs, lpTarget);
147 /* let's use FormatMessage to format it because it has the ability to allocate
148 memory automatically */
149 Ret = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
150 lpFormat,
151 0,
152 0,
153 (LPWSTR)lpTarget,
154 0,
155 &lArgs);
156 va_end(lArgs);
157
158 LocalFree((HLOCAL)lpFormat);
159 }
160
161 return Ret;
162 }
163
164
165 DWORD
166 LoadAndFormatStringsCat(IN HINSTANCE hInstance,
167 IN UINT uID1,
168 IN UINT uID2,
169 OUT LPWSTR *lpTarget,
170 ...)
171 {
172 DWORD Ret = 0;
173 LPWSTR lpFormat;
174 va_list lArgs;
175
176 if (AllocAndLoadStringsCat(&lpFormat,
177 hInstance,
178 uID1,
179 uID2) > 0)
180 {
181 va_start(lArgs, lpTarget);
182 /* let's use FormatMessage to format it because it has the ability to allocate
183 memory automatically */
184 Ret = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
185 lpFormat,
186 0,
187 0,
188 (LPWSTR)lpTarget,
189 0,
190 &lArgs);
191 va_end(lArgs);
192
193 LocalFree((HLOCAL)lpFormat);
194 }
195
196 return Ret;
197 }
198
199
200 LPARAM
201 ListViewGetSelectedItemData(IN HWND hwnd)
202 {
203 int Index;
204
205 Index = ListView_GetNextItem(hwnd,
206 -1,
207 LVNI_SELECTED);
208 if (Index != -1)
209 {
210 LVITEM li;
211
212 li.mask = LVIF_PARAM;
213 li.iItem = Index;
214 li.iSubItem = 0;
215
216 if (ListView_GetItem(hwnd,
217 &li))
218 {
219 return li.lParam;
220 }
221 }
222
223 return 0;
224 }
225
226
227 LPWSTR
228 ConvertMultiByteToUnicode(IN LPCSTR lpMultiByteStr,
229 IN UINT uCodePage)
230 {
231 LPWSTR lpUnicodeStr;
232 INT nLength;
233
234 nLength = MultiByteToWideChar(uCodePage,
235 0,
236 lpMultiByteStr,
237 -1,
238 NULL,
239 0);
240 if (nLength == 0)
241 return NULL;
242
243 lpUnicodeStr = HeapAlloc(GetProcessHeap(),
244 0,
245 nLength * sizeof(WCHAR));
246 if (lpUnicodeStr == NULL)
247 return NULL;
248
249 if (!MultiByteToWideChar(uCodePage,
250 0,
251 lpMultiByteStr,
252 nLength,
253 lpUnicodeStr,
254 nLength))
255 {
256 HeapFree(GetProcessHeap(),
257 0,
258 lpUnicodeStr);
259 return NULL;
260 }
261
262 return lpUnicodeStr;
263 }
264
265
266 BOOL
267 GetDeviceManufacturerString(IN HDEVINFO DeviceInfoSet,
268 IN PSP_DEVINFO_DATA DeviceInfoData,
269 OUT LPWSTR szBuffer,
270 IN DWORD BufferSize)
271 {
272 DWORD RegDataType;
273 BOOL Ret = FALSE;
274
275 if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
276 DeviceInfoData,
277 SPDRP_MFG,
278 &RegDataType,
279 (PBYTE)szBuffer,
280 BufferSize * sizeof(WCHAR),
281 NULL) ||
282 RegDataType != REG_SZ)
283 {
284 szBuffer[0] = L'\0';
285 if (LoadString(hDllInstance,
286 IDS_UNKNOWN,
287 szBuffer,
288 BufferSize))
289 {
290 Ret = TRUE;
291 }
292 }
293 else
294 {
295 /* FIXME - check string for NULL termination! */
296 Ret = TRUE;
297 }
298
299 return Ret;
300 }
301
302
303 BOOL
304 GetDeviceLocationString(IN DEVINST dnDevInst,
305 OUT LPWSTR szBuffer,
306 IN DWORD BufferSize)
307 {
308 DWORD RegDataType;
309 ULONG DataSize;
310 CONFIGRET cRet;
311 BOOL Ret = FALSE;
312
313 DataSize = BufferSize * sizeof(WCHAR);
314 cRet = CM_Get_DevNode_Registry_Property(dnDevInst,
315 CM_DRP_LOCATION_INFORMATION,
316 &RegDataType,
317 szBuffer,
318 &DataSize,
319 0);
320 if (cRet != CR_SUCCESS ||
321 RegDataType != REG_SZ)
322 {
323 szBuffer[0] = L'\0';
324 if (LoadString(hDllInstance,
325 IDS_UNKNOWN,
326 szBuffer,
327 BufferSize))
328 {
329 Ret = TRUE;
330 }
331 }
332 else
333 {
334 /* FIXME - check string for NULL termination! */
335 Ret = TRUE;
336 }
337
338 if (szBuffer[0] >= L'0' && szBuffer[0] <= L'9')
339 {
340 /* convert the string to an integer value and create a
341 formatted string */
342 LPWSTR szFormatted;
343 ULONG ulLocation = (ULONG)wcstoul(szBuffer,
344 NULL,
345 10);
346 if (LoadAndFormatString(hDllInstance,
347 IDS_LOCATIONSTR,
348 &szFormatted,
349 ulLocation,
350 szBuffer) != 0)
351 {
352 wcsncpy(szBuffer,
353 szFormatted,
354 BufferSize - 1);
355 szBuffer[BufferSize - 1] = L'\0';
356 LocalFree((HLOCAL)szFormatted);
357 }
358 else
359 Ret = FALSE;
360 }
361
362 return Ret;
363 }
364
365
366 static const UINT ProblemStringId[] =
367 {
368 IDS_DEV_NO_PROBLEM,
369 IDS_DEV_NOT_CONFIGURED,
370 IDS_DEV_OUT_OF_MEMORY,
371 IDS_DEV_ENTRY_IS_WRONG_TYPE,
372 IDS_DEV_LACKED_ARBITRATOR,
373 IDS_DEV_BOOT_CONFIG_CONFLICT,
374 IDS_DEV_FAILED_FILTER,
375 IDS_DEV_DEVLOADER_NOT_FOUND,
376 IDS_DEV_INVALID_DATA,
377 IDS_DEV_FAILED_START,
378 IDS_DEV_LIAR,
379 IDS_DEV_NORMAL_CONFLICT,
380 IDS_DEV_NOT_VERIFIED,
381 IDS_DEV_NEED_RESTART,
382 IDS_DEV_REENUMERATION,
383 IDS_DEV_PARTIAL_LOG_CONF,
384 IDS_DEV_UNKNOWN_RESOURCE,
385 IDS_DEV_REINSTALL,
386 IDS_DEV_REGISTRY,
387 IDS_UNKNOWN, /* CM_PROB_VXDLDR, not used on NT */
388 IDS_DEV_WILL_BE_REMOVED,
389 IDS_DEV_DISABLED,
390 IDS_DEV_DEVLOADER_NOT_READY,
391 IDS_DEV_DEVICE_NOT_THERE,
392 IDS_DEV_MOVED,
393 IDS_DEV_TOO_EARLY,
394 IDS_DEV_NO_VALID_LOG_CONF,
395 IDS_DEV_FAILED_INSTALL,
396 IDS_DEV_HARDWARE_DISABLED,
397 IDS_DEV_CANT_SHARE_IRQ,
398 IDS_DEV_FAILED_ADD,
399 IDS_DEV_DISABLED_SERVICE,
400 IDS_DEV_TRANSLATION_FAILED,
401 IDS_DEV_NO_SOFTCONFIG,
402 IDS_DEV_BIOS_TABLE,
403 IDS_DEV_IRQ_TRANSLATION_FAILED,
404 IDS_DEV_FAILED_DRIVER_ENTRY,
405 IDS_DEV_DRIVER_FAILED_PRIOR_UNLOAD,
406 IDS_DEV_DRIVER_FAILED_LOAD,
407 IDS_DEV_DRIVER_SERVICE_KEY_INVALID,
408 IDS_DEV_LEGACY_SERVICE_NO_DEVICES,
409 IDS_DEV_DUPLICATE_DEVICE,
410 IDS_DEV_FAILED_POST_START,
411 IDS_DEV_HALTED,
412 IDS_DEV_PHANTOM,
413 IDS_DEV_SYSTEM_SHUTDOWN,
414 IDS_DEV_HELD_FOR_EJECT,
415 IDS_DEV_DRIVER_BLOCKED,
416 IDS_DEV_REGISTRY_TOO_LARGE,
417 IDS_DEV_SETPROPERTIES_FAILED,
418 };
419
420
421 BOOL
422 GetDeviceStatusString(IN DEVINST DevInst,
423 IN HANDLE hMachine,
424 OUT LPWSTR szBuffer,
425 IN DWORD BufferSize)
426 {
427 CONFIGRET cr;
428 ULONG Status, ProblemNumber;
429 BOOL Ret = FALSE;
430
431 if (hMachine != NULL)
432 {
433 cr = CM_Get_DevNode_Status_Ex(&Status,
434 &ProblemNumber,
435 DevInst,
436 0,
437 hMachine);
438 }
439 else
440 {
441 cr = CM_Get_DevNode_Status(&Status,
442 &ProblemNumber,
443 DevInst,
444 0);
445 }
446
447 if (cr == CR_SUCCESS)
448 {
449 UINT MessageId;
450
451 if (ProblemNumber < sizeof(ProblemStringId) / sizeof(ProblemStringId[0]))
452 MessageId = ProblemStringId[ProblemNumber];
453 else
454 MessageId = IDS_UNKNOWN;
455
456 szBuffer[0] = L'\0';
457 if (ProblemNumber == 0)
458 {
459 if (LoadString(hDllInstance,
460 MessageId,
461 szBuffer,
462 BufferSize))
463 {
464 Ret = TRUE;
465 }
466 }
467 else
468 {
469 LPWSTR szProblem;
470
471 if (LoadAndFormatStringsCat(hDllInstance,
472 MessageId,
473 IDS_DEVCODE,
474 &szProblem,
475 ProblemNumber))
476 {
477 wcsncpy(szBuffer,
478 szProblem,
479 BufferSize - 1);
480 szBuffer[BufferSize - 1] = L'\0';
481
482 LocalFree((HLOCAL)szProblem);
483
484 Ret = TRUE;
485 }
486 }
487 }
488
489 return Ret;
490 }
491
492
493 BOOL
494 GetDeviceTypeString(IN PSP_DEVINFO_DATA DeviceInfoData,
495 OUT LPWSTR szBuffer,
496 IN DWORD BufferSize)
497 {
498 BOOL Ret = FALSE;
499
500 if (!SetupDiGetClassDescription(&DeviceInfoData->ClassGuid,
501 szBuffer,
502 BufferSize,
503 NULL))
504 {
505 szBuffer[0] = L'\0';
506 if (LoadString(hDllInstance,
507 IDS_UNKNOWN,
508 szBuffer,
509 BufferSize))
510 {
511 Ret = TRUE;
512 }
513 }
514 else
515 {
516 /* FIXME - check string for NULL termination! */
517 Ret = TRUE;
518 }
519
520 return Ret;
521 }
522
523
524 BOOL
525 GetDeviceDescriptionString(IN HDEVINFO DeviceInfoSet,
526 IN PSP_DEVINFO_DATA DeviceInfoData,
527 OUT LPWSTR szBuffer,
528 IN DWORD BufferSize)
529 {
530 DWORD RegDataType;
531 BOOL Ret = FALSE;
532
533 if ((SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
534 DeviceInfoData,
535 SPDRP_FRIENDLYNAME,
536 &RegDataType,
537 (PBYTE)szBuffer,
538 BufferSize * sizeof(WCHAR),
539 NULL) ||
540 SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
541 DeviceInfoData,
542 SPDRP_DEVICEDESC,
543 &RegDataType,
544 (PBYTE)szBuffer,
545 BufferSize * sizeof(WCHAR),
546 NULL)) &&
547 RegDataType == REG_SZ)
548 {
549 /* FIXME - check string for NULL termination! */
550 Ret = TRUE;
551 }
552 else
553 {
554 szBuffer[0] = L'\0';
555 if (LoadString(hDllInstance,
556 IDS_UNKNOWN,
557 szBuffer,
558 BufferSize))
559 {
560 Ret = TRUE;
561 }
562 }
563
564 return Ret;
565 }
566
567
568 HINSTANCE
569 LoadAndInitComctl32(VOID)
570 {
571 typedef VOID (WINAPI *PINITCOMMONCONTROLS)(VOID);
572 PINITCOMMONCONTROLS pInitCommonControls;
573 HINSTANCE hComCtl32;
574
575 hComCtl32 = LoadLibrary(L"comctl32.dll");
576 if (hComCtl32 != NULL)
577 {
578 /* initialize the common controls */
579 pInitCommonControls = (PINITCOMMONCONTROLS)GetProcAddress(hComCtl32,
580 "InitCommonControls");
581 if (pInitCommonControls == NULL)
582 {
583 FreeLibrary(hComCtl32);
584 return NULL;
585 }
586
587 pInitCommonControls();
588 }
589
590 return hComCtl32;
591 }
592
593
594 BOOL
595 STDCALL
596 DllMain(IN HINSTANCE hinstDLL,
597 IN DWORD dwReason,
598 IN LPVOID lpvReserved)
599 {
600 switch (dwReason)
601 {
602 case DLL_PROCESS_ATTACH:
603 DisableThreadLibraryCalls(hinstDLL);
604 hDllInstance = hinstDLL;
605 break;
606 }
607
608 return TRUE;
609 }