implemented enabling/disabling of devices
[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 *uID,
101 IN UINT nIDs)
102 {
103 INT ln = 0;
104 UINT i;
105
106 for (i = 0;
107 i != nIDs;
108 i++)
109 {
110 ln += LengthOfStrResource(hInst,
111 uID[i]);
112 }
113
114 if (ln != 0)
115 {
116 (*lpTarget) = (LPWSTR)LocalAlloc(LMEM_FIXED,
117 (ln + 1) * sizeof(WCHAR));
118 if ((*lpTarget) != NULL)
119 {
120 LPWSTR s = *lpTarget;
121 INT Ret = 0;
122
123 for (i = 0;
124 i != nIDs;
125 i++)
126 {
127 if (!(Ret = LoadStringW(hInst, uID[i], s, ln)))
128 {
129 LocalFree((HLOCAL)(*lpTarget));
130 }
131
132 s += Ret;
133 }
134
135 return s - *lpTarget;
136 }
137 }
138 return 0;
139 }
140
141
142 DWORD
143 LoadAndFormatString(IN HINSTANCE hInstance,
144 IN UINT uID,
145 OUT LPWSTR *lpTarget,
146 ...)
147 {
148 DWORD Ret = 0;
149 LPWSTR lpFormat;
150 va_list lArgs;
151
152 if (AllocAndLoadString(&lpFormat,
153 hInstance,
154 uID) != 0)
155 {
156 va_start(lArgs, lpTarget);
157 /* let's use FormatMessage to format it because it has the ability to allocate
158 memory automatically */
159 Ret = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
160 lpFormat,
161 0,
162 0,
163 (LPWSTR)lpTarget,
164 0,
165 &lArgs);
166 va_end(lArgs);
167
168 LocalFree((HLOCAL)lpFormat);
169 }
170
171 return Ret;
172 }
173
174
175 DWORD
176 LoadAndFormatStringsCat(IN HINSTANCE hInstance,
177 IN UINT *uID,
178 IN UINT nIDs,
179 OUT LPWSTR *lpTarget,
180 ...)
181 {
182 DWORD Ret = 0;
183 LPWSTR lpFormat;
184 va_list lArgs;
185
186 if (AllocAndLoadStringsCat(&lpFormat,
187 hInstance,
188 uID,
189 nIDs) != 0)
190 {
191 va_start(lArgs, lpTarget);
192 /* let's use FormatMessage to format it because it has the ability to allocate
193 memory automatically */
194 Ret = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
195 lpFormat,
196 0,
197 0,
198 (LPWSTR)lpTarget,
199 0,
200 &lArgs);
201 va_end(lArgs);
202
203 LocalFree((HLOCAL)lpFormat);
204 }
205
206 return Ret;
207 }
208
209
210 LPARAM
211 ListViewGetSelectedItemData(IN HWND hwnd)
212 {
213 int Index;
214
215 Index = ListView_GetNextItem(hwnd,
216 -1,
217 LVNI_SELECTED);
218 if (Index != -1)
219 {
220 LVITEM li;
221
222 li.mask = LVIF_PARAM;
223 li.iItem = Index;
224 li.iSubItem = 0;
225
226 if (ListView_GetItem(hwnd,
227 &li))
228 {
229 return li.lParam;
230 }
231 }
232
233 return 0;
234 }
235
236
237 LPWSTR
238 ConvertMultiByteToUnicode(IN LPCSTR lpMultiByteStr,
239 IN UINT uCodePage)
240 {
241 LPWSTR lpUnicodeStr;
242 INT nLength;
243
244 nLength = MultiByteToWideChar(uCodePage,
245 0,
246 lpMultiByteStr,
247 -1,
248 NULL,
249 0);
250 if (nLength == 0)
251 return NULL;
252
253 lpUnicodeStr = HeapAlloc(GetProcessHeap(),
254 0,
255 nLength * sizeof(WCHAR));
256 if (lpUnicodeStr == NULL)
257 {
258 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
259 return NULL;
260 }
261
262 if (!MultiByteToWideChar(uCodePage,
263 0,
264 lpMultiByteStr,
265 nLength,
266 lpUnicodeStr,
267 nLength))
268 {
269 HeapFree(GetProcessHeap(),
270 0,
271 lpUnicodeStr);
272 return NULL;
273 }
274
275 return lpUnicodeStr;
276 }
277
278
279 BOOL
280 GetDeviceManufacturerString(IN HDEVINFO DeviceInfoSet,
281 IN PSP_DEVINFO_DATA DeviceInfoData,
282 OUT LPWSTR szBuffer,
283 IN DWORD BufferSize)
284 {
285 DWORD RegDataType;
286 BOOL Ret = FALSE;
287
288 if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
289 DeviceInfoData,
290 SPDRP_MFG,
291 &RegDataType,
292 (PBYTE)szBuffer,
293 BufferSize * sizeof(WCHAR),
294 NULL) ||
295 RegDataType != REG_SZ)
296 {
297 szBuffer[0] = L'\0';
298 if (LoadString(hDllInstance,
299 IDS_UNKNOWN,
300 szBuffer,
301 BufferSize))
302 {
303 Ret = TRUE;
304 }
305 }
306 else
307 {
308 /* FIXME - check string for NULL termination! */
309 Ret = TRUE;
310 }
311
312 return Ret;
313 }
314
315
316 BOOL
317 GetDeviceLocationString(IN DEVINST dnDevInst OPTIONAL,
318 IN DEVINST dnParentDevInst OPTIONAL,
319 OUT LPWSTR szBuffer,
320 IN DWORD BufferSize)
321 {
322 DWORD RegDataType;
323 ULONG DataSize;
324 CONFIGRET cRet;
325 LPWSTR szFormatted;
326 BOOL Ret = FALSE;
327
328 DataSize = BufferSize * sizeof(WCHAR);
329 szBuffer[0] = L'\0';
330 if (dnParentDevInst != 0)
331 {
332 /* query the parent node name */
333 if (CM_Get_DevNode_Registry_Property(dnParentDevInst,
334 CM_DRP_DEVICEDESC,
335 &RegDataType,
336 szBuffer,
337 &DataSize,
338 0) == CR_SUCCESS &&
339 RegDataType == REG_SZ &&
340 LoadAndFormatString(hDllInstance,
341 IDS_DEVONPARENT,
342 &szFormatted,
343 szBuffer) != 0)
344 {
345 wcsncpy(szBuffer,
346 szFormatted,
347 BufferSize - 1);
348 szBuffer[BufferSize - 1] = L'\0';
349 LocalFree((HLOCAL)szFormatted);
350 Ret = TRUE;
351 }
352 }
353 else if (dnDevInst != 0)
354 {
355 cRet = CM_Get_DevNode_Registry_Property(dnDevInst,
356 CM_DRP_LOCATION_INFORMATION,
357 &RegDataType,
358 szBuffer,
359 &DataSize,
360 0);
361 if (cRet == CR_SUCCESS && RegDataType == REG_SZ)
362 {
363 /* FIXME - check string for NULL termination! */
364 Ret = TRUE;
365 }
366
367 if (Ret && szBuffer[0] >= L'0' && szBuffer[0] <= L'9')
368 {
369 /* convert the string to an integer value and create a
370 formatted string */
371 ULONG ulLocation = (ULONG)wcstoul(szBuffer,
372 NULL,
373 10);
374 if (LoadAndFormatString(hDllInstance,
375 IDS_LOCATIONSTR,
376 &szFormatted,
377 ulLocation,
378 szBuffer) != 0)
379 {
380 wcsncpy(szBuffer,
381 szFormatted,
382 BufferSize - 1);
383 szBuffer[BufferSize - 1] = L'\0';
384 LocalFree((HLOCAL)szFormatted);
385 }
386 else
387 Ret = FALSE;
388 }
389 }
390
391 if (!Ret &&
392 LoadString(hDllInstance,
393 IDS_UNKNOWN,
394 szBuffer,
395 BufferSize))
396 {
397 Ret = TRUE;
398 }
399
400 return Ret;
401 }
402
403
404 static const UINT ProblemStringId[NUM_CM_PROB] =
405 {
406 IDS_DEV_NO_PROBLEM,
407 IDS_DEV_NOT_CONFIGURED,
408 IDS_DEV_OUT_OF_MEMORY,
409 IDS_DEV_ENTRY_IS_WRONG_TYPE,
410 IDS_DEV_LACKED_ARBITRATOR,
411 IDS_DEV_BOOT_CONFIG_CONFLICT,
412 IDS_DEV_FAILED_FILTER,
413 IDS_DEV_DEVLOADER_NOT_FOUND,
414 IDS_DEV_INVALID_DATA,
415 IDS_DEV_FAILED_START,
416 IDS_DEV_LIAR,
417 IDS_DEV_NORMAL_CONFLICT,
418 IDS_DEV_NOT_VERIFIED,
419 IDS_DEV_NEED_RESTART,
420 IDS_DEV_REENUMERATION,
421 IDS_DEV_PARTIAL_LOG_CONF,
422 IDS_DEV_UNKNOWN_RESOURCE,
423 IDS_DEV_REINSTALL,
424 IDS_DEV_REGISTRY,
425 IDS_UNKNOWN, /* CM_PROB_VXDLDR, not used on NT */
426 IDS_DEV_WILL_BE_REMOVED,
427 IDS_DEV_DISABLED,
428 IDS_DEV_DEVLOADER_NOT_READY,
429 IDS_DEV_DEVICE_NOT_THERE,
430 IDS_DEV_MOVED,
431 IDS_DEV_TOO_EARLY,
432 IDS_DEV_NO_VALID_LOG_CONF,
433 IDS_DEV_FAILED_INSTALL,
434 IDS_DEV_HARDWARE_DISABLED,
435 IDS_DEV_CANT_SHARE_IRQ,
436 IDS_DEV_FAILED_ADD,
437 IDS_DEV_DISABLED_SERVICE,
438 IDS_DEV_TRANSLATION_FAILED,
439 IDS_DEV_NO_SOFTCONFIG,
440 IDS_DEV_BIOS_TABLE,
441 IDS_DEV_IRQ_TRANSLATION_FAILED,
442 IDS_DEV_FAILED_DRIVER_ENTRY,
443 IDS_DEV_DRIVER_FAILED_PRIOR_UNLOAD,
444 IDS_DEV_DRIVER_FAILED_LOAD,
445 IDS_DEV_DRIVER_SERVICE_KEY_INVALID,
446 IDS_DEV_LEGACY_SERVICE_NO_DEVICES,
447 IDS_DEV_DUPLICATE_DEVICE,
448 IDS_DEV_FAILED_POST_START,
449 IDS_DEV_HALTED,
450 IDS_DEV_PHANTOM,
451 IDS_DEV_SYSTEM_SHUTDOWN,
452 IDS_DEV_HELD_FOR_EJECT,
453 IDS_DEV_DRIVER_BLOCKED,
454 IDS_DEV_REGISTRY_TOO_LARGE,
455 IDS_DEV_SETPROPERTIES_FAILED,
456 };
457
458
459 BOOL
460 GetDeviceStatusString(IN DEVINST DevInst,
461 IN HMACHINE hMachine,
462 OUT LPWSTR szBuffer,
463 IN DWORD BufferSize)
464 {
465 CONFIGRET cr;
466 ULONG Status, ProblemNumber;
467 UINT MessageId = IDS_UNKNOWN;
468 BOOL Ret = FALSE;
469
470 szBuffer[0] = L'\0';
471 cr = CM_Get_DevNode_Status_Ex(&Status,
472 &ProblemNumber,
473 DevInst,
474 0,
475 hMachine);
476 if (cr == CR_SUCCESS)
477 {
478 if (Status & DN_HAS_PROBLEM)
479 {
480 if (ProblemNumber < sizeof(ProblemStringId) / sizeof(ProblemStringId[0]))
481 MessageId = ProblemStringId[ProblemNumber];
482
483 if (ProblemNumber == 0)
484 {
485 goto GeneralMessage;
486 }
487 else
488 {
489 LPWSTR szProblem;
490 UINT StringIDs[] =
491 {
492 MessageId,
493 IDS_DEVCODE,
494 };
495
496 if (LoadAndFormatStringsCat(hDllInstance,
497 StringIDs,
498 sizeof(StringIDs) / sizeof(StringIDs[0]),
499 &szProblem,
500 ProblemNumber))
501 {
502 wcsncpy(szBuffer,
503 szProblem,
504 BufferSize - 1);
505 szBuffer[BufferSize - 1] = L'\0';
506
507 LocalFree((HLOCAL)szProblem);
508
509 Ret = TRUE;
510 }
511 }
512 }
513 else
514 {
515 if (!(Status & (DN_DRIVER_LOADED | DN_STARTED)))
516 {
517 MessageId = IDS_NODRIVERLOADED;
518 }
519 else
520 {
521 MessageId = IDS_DEV_NO_PROBLEM;
522 }
523
524 goto GeneralMessage;
525 }
526 }
527 else
528 {
529 GeneralMessage:
530 if (LoadString(hDllInstance,
531 MessageId,
532 szBuffer,
533 BufferSize))
534 {
535 Ret = TRUE;
536 }
537 }
538
539 return Ret;
540 }
541
542
543 BOOL
544 IsDeviceHidden(IN DEVINST DevInst,
545 IN HMACHINE hMachine,
546 OUT BOOL *IsHidden)
547 {
548 CONFIGRET cr;
549 ULONG Status, ProblemNumber;
550 BOOL Ret = FALSE;
551
552 cr = CM_Get_DevNode_Status_Ex(&Status,
553 &ProblemNumber,
554 DevInst,
555 0,
556 hMachine);
557 if (cr == CR_SUCCESS)
558 {
559 *IsHidden = ((Status & DN_NO_SHOW_IN_DM) != 0);
560 Ret = TRUE;
561 }
562
563 return Ret;
564 }
565
566
567 BOOL
568 CanDisableDevice(IN DEVINST DevInst,
569 IN HMACHINE hMachine,
570 OUT BOOL *CanDisable)
571 {
572 CONFIGRET cr;
573 ULONG Status, ProblemNumber;
574 BOOL Ret = FALSE;
575
576 cr = CM_Get_DevNode_Status_Ex(&Status,
577 &ProblemNumber,
578 DevInst,
579 0,
580 hMachine);
581 if (cr == CR_SUCCESS)
582 {
583 *CanDisable = ((Status & DN_DISABLEABLE) != 0);
584 Ret = TRUE;
585 }
586
587 return Ret;
588 }
589
590
591 BOOL
592 IsDeviceEnabled(IN DEVINST DevInst,
593 IN HMACHINE hMachine,
594 OUT BOOL *IsEnabled)
595 {
596 CONFIGRET cr;
597 ULONG Status, ProblemNumber;
598 BOOL Ret = FALSE;
599
600 cr = CM_Get_DevNode_Status_Ex(&Status,
601 &ProblemNumber,
602 DevInst,
603 0,
604 hMachine);
605 if (cr == CR_SUCCESS)
606 {
607 *IsEnabled = ((Status & DN_STARTED) != 0);
608 Ret = TRUE;
609 }
610
611 return Ret;
612 }
613
614
615 BOOL
616 EnableDevice(IN HDEVINFO DeviceInfoSet,
617 IN PSP_DEVINFO_DATA DevInfoData OPTIONAL,
618 IN BOOL bEnable,
619 IN DWORD HardwareProfile OPTIONAL,
620 OUT BOOL *bNeedReboot OPTIONAL)
621 {
622 SP_PROPCHANGE_PARAMS pcp;
623 SP_DEVINSTALL_PARAMS dp;
624 DWORD LastErr;
625 BOOL Ret = FALSE;
626
627 pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
628 pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
629 pcp.HwProfile = HardwareProfile;
630
631 if (bEnable)
632 {
633 /* try to enable/disable the device on the global profile */
634 pcp.StateChange = DICS_ENABLE;
635 pcp.Scope = DICS_FLAG_GLOBAL;
636
637 /* ignore errors */
638 LastErr = GetLastError();
639 if (SetupDiSetClassInstallParams(DeviceInfoSet,
640 DevInfoData,
641 &pcp.ClassInstallHeader,
642 sizeof(SP_PROPCHANGE_PARAMS)))
643 {
644 SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
645 DeviceInfoSet,
646 DevInfoData);
647 }
648 SetLastError(LastErr);
649 }
650
651 /* try config-specific */
652 pcp.StateChange = (bEnable ? DICS_ENABLE : DICS_DISABLE);
653 pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
654
655 if (SetupDiSetClassInstallParams(DeviceInfoSet,
656 DevInfoData,
657 &pcp.ClassInstallHeader,
658 sizeof(SP_PROPCHANGE_PARAMS)) &&
659 SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
660 DeviceInfoSet,
661 DevInfoData))
662 {
663 dp.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
664 if (SetupDiGetDeviceInstallParams(DeviceInfoSet,
665 DevInfoData,
666 &dp))
667 {
668 if (bNeedReboot != NULL)
669 {
670 *bNeedReboot = ((dp.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)) != 0);
671 }
672
673 Ret = TRUE;
674 }
675 }
676 return Ret;
677 }
678
679
680 BOOL
681 GetDeviceTypeString(IN PSP_DEVINFO_DATA DeviceInfoData,
682 OUT LPWSTR szBuffer,
683 IN DWORD BufferSize)
684 {
685 BOOL Ret = FALSE;
686
687 if (!SetupDiGetClassDescription(&DeviceInfoData->ClassGuid,
688 szBuffer,
689 BufferSize,
690 NULL))
691 {
692 szBuffer[0] = L'\0';
693 if (LoadString(hDllInstance,
694 IDS_UNKNOWN,
695 szBuffer,
696 BufferSize))
697 {
698 Ret = TRUE;
699 }
700 }
701 else
702 {
703 /* FIXME - check string for NULL termination! */
704 Ret = TRUE;
705 }
706
707 return Ret;
708 }
709
710
711 BOOL
712 GetDeviceDescriptionString(IN HDEVINFO DeviceInfoSet,
713 IN PSP_DEVINFO_DATA DeviceInfoData,
714 OUT LPWSTR szBuffer,
715 IN DWORD BufferSize)
716 {
717 DWORD RegDataType;
718 BOOL Ret = FALSE;
719
720 if ((SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
721 DeviceInfoData,
722 SPDRP_FRIENDLYNAME,
723 &RegDataType,
724 (PBYTE)szBuffer,
725 BufferSize * sizeof(WCHAR),
726 NULL) ||
727 SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
728 DeviceInfoData,
729 SPDRP_DEVICEDESC,
730 &RegDataType,
731 (PBYTE)szBuffer,
732 BufferSize * sizeof(WCHAR),
733 NULL)) &&
734 RegDataType == REG_SZ)
735 {
736 /* FIXME - check string for NULL termination! */
737 Ret = TRUE;
738 }
739 else
740 {
741 szBuffer[0] = L'\0';
742 if (LoadString(hDllInstance,
743 IDS_UNKNOWNDEVICE,
744 szBuffer,
745 BufferSize))
746 {
747 Ret = TRUE;
748 }
749 }
750
751 return Ret;
752 }
753
754
755 HINSTANCE
756 LoadAndInitComctl32(VOID)
757 {
758 typedef VOID (WINAPI *PINITCOMMONCONTROLS)(VOID);
759 PINITCOMMONCONTROLS pInitCommonControls;
760 HINSTANCE hComCtl32;
761
762 hComCtl32 = LoadLibrary(L"comctl32.dll");
763 if (hComCtl32 != NULL)
764 {
765 /* initialize the common controls */
766 pInitCommonControls = (PINITCOMMONCONTROLS)GetProcAddress(hComCtl32,
767 "InitCommonControls");
768 if (pInitCommonControls == NULL)
769 {
770 FreeLibrary(hComCtl32);
771 return NULL;
772 }
773
774 pInitCommonControls();
775 }
776
777 return hComCtl32;
778 }
779
780
781 BOOL
782 STDCALL
783 DllMain(IN HINSTANCE hinstDLL,
784 IN DWORD dwReason,
785 IN LPVOID lpvReserved)
786 {
787 switch (dwReason)
788 {
789 case DLL_PROCESS_ATTACH:
790 DisableThreadLibraryCalls(hinstDLL);
791 hDllInstance = hinstDLL;
792 break;
793 }
794
795 return TRUE;
796 }