d0bb7c8a30f635f5c0a93e0d98e10ca415fb0975
[reactos.git] / reactos / dll / win32 / devmgr / properties / misc.cpp
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19 /*
20 * PROJECT: ReactOS devmgr.dll
21 * FILE: lib/devmgr/misc.c
22 * PURPOSE: ReactOS Device Manager
23 * PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
24 * UPDATE HISTORY:
25 * 2005/11/24 Created
26 */
27
28 #include "precomp.h"
29 #include <devmgr/devmgr.h>
30 #include "properties.h"
31 #include "resource.h"
32
33
34
35 INT
36 LengthOfStrResource(IN HINSTANCE hInst,
37 IN UINT uID)
38 {
39 HRSRC hrSrc;
40 HGLOBAL hRes;
41 LPWSTR lpName, lpStr;
42
43 if (hInst == NULL)
44 {
45 return -1;
46 }
47
48 /* There are always blocks of 16 strings */
49 lpName = (LPWSTR)MAKEINTRESOURCE((uID >> 4) + 1);
50
51 /* Find the string table block */
52 if ((hrSrc = FindResourceW(hInst, lpName, (LPWSTR)RT_STRING)) &&
53 (hRes = LoadResource(hInst, hrSrc)) &&
54 (lpStr = (LPWSTR)LockResource(hRes)))
55 {
56 UINT x;
57
58 /* Find the string we're looking for */
59 uID &= 0xF; /* position in the block, same as % 16 */
60 for (x = 0; x < uID; x++)
61 {
62 lpStr += (*lpStr) + 1;
63 }
64
65 /* Found the string */
66 return (int)(*lpStr);
67 }
68 return -1;
69 }
70
71
72 static INT
73 AllocAndLoadString(OUT LPWSTR *lpTarget,
74 IN HINSTANCE hInst,
75 IN UINT uID)
76 {
77 INT ln;
78
79 ln = LengthOfStrResource(hInst,
80 uID);
81 if (ln++ > 0)
82 {
83 (*lpTarget) = (LPWSTR)LocalAlloc(LMEM_FIXED,
84 ln * sizeof(WCHAR));
85 if ((*lpTarget) != NULL)
86 {
87 INT Ret;
88 if (!(Ret = LoadStringW(hInst, uID, *lpTarget, ln)))
89 {
90 LocalFree((HLOCAL)(*lpTarget));
91 }
92 return Ret;
93 }
94 }
95 return 0;
96 }
97
98
99 static INT
100 AllocAndLoadStringsCat(OUT LPWSTR *lpTarget,
101 IN HINSTANCE hInst,
102 IN UINT *uID,
103 IN UINT nIDs)
104 {
105 INT ln = 0;
106 UINT i;
107
108 for (i = 0;
109 i != nIDs;
110 i++)
111 {
112 ln += LengthOfStrResource(hInst,
113 uID[i]);
114 }
115
116 if (ln != 0)
117 {
118 (*lpTarget) = (LPWSTR)LocalAlloc(LMEM_FIXED,
119 (ln + 1) * sizeof(WCHAR));
120 if ((*lpTarget) != NULL)
121 {
122 LPWSTR s = *lpTarget;
123 INT Ret = 0;
124
125 for (i = 0;
126 i != nIDs;
127 i++)
128 {
129 if (!(Ret = LoadStringW(hInst, uID[i], s, ln)))
130 {
131 LocalFree((HLOCAL)(*lpTarget));
132 return 0;
133 }
134
135 s += Ret;
136 }
137
138 return s - *lpTarget;
139 }
140 }
141 return 0;
142 }
143
144
145 DWORD
146 LoadAndFormatString(IN HINSTANCE hInstance,
147 IN UINT uID,
148 OUT LPWSTR *lpTarget,
149 ...)
150 {
151 DWORD Ret = 0;
152 LPWSTR lpFormat;
153 va_list lArgs;
154
155 if (AllocAndLoadString(&lpFormat,
156 hInstance,
157 uID) != 0)
158 {
159 va_start(lArgs, lpTarget);
160 /* let's use FormatMessage to format it because it has the ability to allocate
161 memory automatically */
162 Ret = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
163 lpFormat,
164 0,
165 0,
166 (LPWSTR)lpTarget,
167 0,
168 &lArgs);
169 va_end(lArgs);
170
171 LocalFree((HLOCAL)lpFormat);
172 }
173
174 return Ret;
175 }
176
177
178 DWORD
179 LoadAndFormatStringsCat(IN HINSTANCE hInstance,
180 IN UINT *uID,
181 IN UINT nIDs,
182 OUT LPWSTR *lpTarget,
183 ...)
184 {
185 DWORD Ret = 0;
186 LPWSTR lpFormat;
187 va_list lArgs;
188
189 if (AllocAndLoadStringsCat(&lpFormat,
190 hInstance,
191 uID,
192 nIDs) != 0)
193 {
194 va_start(lArgs, lpTarget);
195 /* let's use FormatMessage to format it because it has the ability to allocate
196 memory automatically */
197 Ret = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
198 lpFormat,
199 0,
200 0,
201 (LPWSTR)lpTarget,
202 0,
203 &lArgs);
204 va_end(lArgs);
205
206 LocalFree((HLOCAL)lpFormat);
207 }
208
209 return Ret;
210 }
211
212
213 LPARAM
214 ListViewGetSelectedItemData(IN HWND hwnd)
215 {
216 int Index;
217
218 Index = ListView_GetNextItem(hwnd,
219 -1,
220 LVNI_SELECTED);
221 if (Index != -1)
222 {
223 LVITEM li;
224
225 li.mask = LVIF_PARAM;
226 li.iItem = Index;
227 li.iSubItem = 0;
228
229 if (ListView_GetItem(hwnd,
230 &li))
231 {
232 return li.lParam;
233 }
234 }
235
236 return 0;
237 }
238
239
240 LPWSTR
241 ConvertMultiByteToUnicode(IN LPCSTR lpMultiByteStr,
242 IN UINT uCodePage)
243 {
244 LPWSTR lpUnicodeStr;
245 INT nLength;
246
247 nLength = MultiByteToWideChar(uCodePage,
248 0,
249 lpMultiByteStr,
250 -1,
251 NULL,
252 0);
253 if (nLength == 0)
254 return NULL;
255
256 lpUnicodeStr = (LPWSTR)HeapAlloc(GetProcessHeap(),
257 0,
258 nLength * sizeof(WCHAR));
259 if (lpUnicodeStr == NULL)
260 {
261 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
262 return NULL;
263 }
264
265 if (!MultiByteToWideChar(uCodePage,
266 0,
267 lpMultiByteStr,
268 nLength,
269 lpUnicodeStr,
270 nLength))
271 {
272 HeapFree(GetProcessHeap(),
273 0,
274 lpUnicodeStr);
275 return NULL;
276 }
277
278 return lpUnicodeStr;
279 }
280
281
282 BOOL
283 GetDeviceManufacturerString(IN HDEVINFO DeviceInfoSet,
284 IN PSP_DEVINFO_DATA DeviceInfoData,
285 OUT LPWSTR szBuffer,
286 IN DWORD BufferSize)
287 {
288 DWORD RegDataType;
289 BOOL Ret = FALSE;
290
291 if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
292 DeviceInfoData,
293 SPDRP_MFG,
294 &RegDataType,
295 (PBYTE)szBuffer,
296 BufferSize * sizeof(WCHAR),
297 NULL) ||
298 RegDataType != REG_SZ)
299 {
300 szBuffer[0] = L'\0';
301 if (LoadString(hDllInstance,
302 IDS_UNKNOWN,
303 szBuffer,
304 BufferSize))
305 {
306 Ret = TRUE;
307 }
308 }
309 else
310 {
311 /* FIXME - check string for NULL termination! */
312 Ret = TRUE;
313 }
314
315 return Ret;
316 }
317
318
319 BOOL
320 GetDeviceLocationString(IN HDEVINFO DeviceInfoSet,
321 IN PSP_DEVINFO_DATA DeviceInfoData,
322 IN DEVINST dnParentDevInst OPTIONAL,
323 OUT LPWSTR szBuffer,
324 IN DWORD BufferSize)
325 {
326 DWORD RegDataType;
327 ULONG DataSize;
328 CONFIGRET cRet;
329 LPWSTR szFormatted;
330 HKEY hKey;
331 DWORD dwSize, dwType;
332 BOOL Ret = FALSE;
333
334 DataSize = BufferSize * sizeof(WCHAR);
335 szBuffer[0] = L'\0';
336
337 hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
338 DeviceInfoData,
339 DICS_FLAG_GLOBAL,
340 0,
341 DIREG_DRV,
342 KEY_QUERY_VALUE);
343 if (hKey != INVALID_HANDLE_VALUE)
344 {
345 /* query the LocationInformationOverride value */
346 dwSize = BufferSize;
347 if (RegQueryValueEx(hKey,
348 L"LocationInformationOverride",
349 NULL,
350 &dwType,
351 (LPBYTE)szBuffer,
352 &dwSize) == ERROR_SUCCESS &&
353 dwType == REG_SZ &&
354 szBuffer[0] != L'\0')
355 {
356 Ret = TRUE;
357 }
358 else
359 {
360 szBuffer[0] = L'\0';
361 }
362
363 RegCloseKey(hKey);
364 }
365
366
367 if (!Ret)
368 {
369 if (dnParentDevInst != 0)
370 {
371 /* query the parent node name */
372 if (CM_Get_DevNode_Registry_Property(dnParentDevInst,
373 CM_DRP_DEVICEDESC,
374 &RegDataType,
375 szBuffer,
376 &DataSize,
377 0) == CR_SUCCESS &&
378 RegDataType == REG_SZ &&
379 LoadAndFormatString(hDllInstance,
380 IDS_DEVONPARENT,
381 &szFormatted,
382 szBuffer) != 0)
383 {
384 wcsncpy(szBuffer,
385 szFormatted,
386 BufferSize - 1);
387 szBuffer[BufferSize - 1] = L'\0';
388 LocalFree((HLOCAL)szFormatted);
389 Ret = TRUE;
390 }
391 }
392 else if (DeviceInfoData->DevInst != 0)
393 {
394 cRet = CM_Get_DevNode_Registry_Property(DeviceInfoData->DevInst,
395 CM_DRP_LOCATION_INFORMATION,
396 &RegDataType,
397 szBuffer,
398 &DataSize,
399 0);
400 if (cRet == CR_SUCCESS && RegDataType == REG_SZ)
401 {
402 /* FIXME - check string for NULL termination! */
403 Ret = TRUE;
404 }
405
406 if (Ret && szBuffer[0] >= L'0' && szBuffer[0] <= L'9')
407 {
408 /* convert the string to an integer value and create a
409 formatted string */
410 ULONG ulLocation = (ULONG)wcstoul(szBuffer,
411 NULL,
412 10);
413 if (LoadAndFormatString(hDllInstance,
414 IDS_LOCATIONSTR,
415 &szFormatted,
416 ulLocation,
417 szBuffer) != 0)
418 {
419 wcsncpy(szBuffer,
420 szFormatted,
421 BufferSize - 1);
422 szBuffer[BufferSize - 1] = L'\0';
423 LocalFree((HLOCAL)szFormatted);
424 }
425 else
426 Ret = FALSE;
427 }
428 }
429 }
430
431 if (!Ret &&
432 LoadString(hDllInstance,
433 IDS_UNKNOWN,
434 szBuffer,
435 BufferSize))
436 {
437 Ret = TRUE;
438 }
439
440 return Ret;
441 }
442
443
444 BOOL
445 GetDeviceStatusString(IN DEVINST DevInst,
446 IN HMACHINE hMachine,
447 OUT LPWSTR szBuffer,
448 IN DWORD BufferSize)
449 {
450 CONFIGRET cr;
451 ULONG Status, ProblemNumber;
452 UINT MessageId = IDS_UNKNOWN;
453 BOOL Ret = FALSE;
454
455 szBuffer[0] = L'\0';
456 cr = CM_Get_DevNode_Status_Ex(&Status,
457 &ProblemNumber,
458 DevInst,
459 0,
460 hMachine);
461 if (cr == CR_SUCCESS)
462 {
463 if (Status & DN_HAS_PROBLEM)
464 {
465 UINT uRet;
466
467 uRet = DeviceProblemTextW(hMachine,
468 DevInst,
469 ProblemNumber,
470 szBuffer,
471 (BufferSize != 0 ? BufferSize : BufferSize - 1));
472
473 Ret = (uRet != 0 && uRet < BufferSize);
474 }
475 else
476 {
477 if (!(Status & (DN_DRIVER_LOADED | DN_STARTED)))
478 {
479 MessageId = IDS_NODRIVERLOADED;
480 }
481 else
482 {
483 MessageId = IDS_DEV_NO_PROBLEM;
484 }
485
486 goto GeneralMessage;
487 }
488 }
489 else
490 {
491 GeneralMessage:
492 if (LoadString(hDllInstance,
493 MessageId,
494 szBuffer,
495 (int)BufferSize))
496 {
497 Ret = TRUE;
498 }
499 }
500
501 return Ret;
502 }
503
504
505 BOOL
506 GetDriverProviderString(IN HDEVINFO DeviceInfoSet,
507 IN PSP_DEVINFO_DATA DeviceInfoData,
508 OUT LPWSTR szBuffer,
509 IN DWORD BufferSize)
510 {
511 HKEY hKey;
512 DWORD dwSize, dwType;
513 BOOL Ret = FALSE;
514
515 szBuffer[0] = L'\0';
516
517 /* get driver provider, date and version */
518 hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
519 DeviceInfoData,
520 DICS_FLAG_GLOBAL,
521 0,
522 DIREG_DRV,
523 KEY_QUERY_VALUE);
524 if (hKey != INVALID_HANDLE_VALUE)
525 {
526 /* query the driver provider */
527 dwSize = BufferSize;
528 if (RegQueryValueEx(hKey,
529 REGSTR_VAL_PROVIDER_NAME,
530 NULL,
531 &dwType,
532 (LPBYTE)szBuffer,
533 &dwSize) == ERROR_SUCCESS &&
534 dwType == REG_SZ &&
535 szBuffer[0] != L'\0')
536 {
537 Ret = TRUE;
538 }
539 else
540 {
541 szBuffer[0] = L'\0';
542 }
543
544 RegCloseKey(hKey);
545 }
546
547 if (szBuffer[0] == L'\0')
548 {
549 /* unable to query the information */
550 if (LoadString(hDllInstance,
551 IDS_UNKNOWN,
552 szBuffer,
553 BufferSize))
554 {
555 Ret = TRUE;
556 }
557 }
558
559 return Ret;
560 }
561
562
563 BOOL
564 GetDriverVersionString(IN HDEVINFO DeviceInfoSet,
565 IN PSP_DEVINFO_DATA DeviceInfoData,
566 OUT LPWSTR szBuffer,
567 IN DWORD BufferSize)
568 {
569 HKEY hKey;
570 DWORD dwSize, dwType;
571 BOOL Ret = FALSE;
572
573 szBuffer[0] = L'\0';
574
575 /* get driver provider, date and version */
576 hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
577 DeviceInfoData,
578 DICS_FLAG_GLOBAL,
579 0,
580 DIREG_DRV,
581 KEY_QUERY_VALUE);
582 if (hKey != INVALID_HANDLE_VALUE)
583 {
584 /* query the driver provider */
585 dwSize = BufferSize;
586 if (RegQueryValueEx(hKey,
587 L"DriverVersion",
588 NULL,
589 &dwType,
590 (LPBYTE)szBuffer,
591 &dwSize) == ERROR_SUCCESS &&
592 dwType == REG_SZ &&
593 szBuffer[0] != L'\0')
594 {
595 Ret = TRUE;
596 }
597 else
598 {
599 szBuffer[0] = L'\0';
600 }
601
602 RegCloseKey(hKey);
603 }
604
605 if (szBuffer[0] == L'\0')
606 {
607 /* unable to query the information */
608 if (LoadString(hDllInstance,
609 IDS_NOTAVAILABLE,
610 szBuffer,
611 BufferSize))
612 {
613 Ret = TRUE;
614 }
615 }
616
617 return Ret;
618 }
619
620 BOOL
621 GetDriverDateString(IN HDEVINFO DeviceInfoSet,
622 IN PSP_DEVINFO_DATA DeviceInfoData,
623 OUT LPWSTR szBuffer,
624 IN DWORD BufferSize)
625 {
626 HKEY hKey;
627 FILETIME DriverDate;
628 SYSTEMTIME SystemTime, LocalTime;
629 DWORD dwSize, dwType;
630 BOOL Ret = FALSE;
631
632 szBuffer[0] = L'\0';
633
634 /* get driver provider, date and version */
635 hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
636 DeviceInfoData,
637 DICS_FLAG_GLOBAL,
638 0,
639 DIREG_DRV,
640 KEY_QUERY_VALUE);
641 if (hKey != INVALID_HANDLE_VALUE)
642 {
643 /* query the driver provider */
644 dwSize = sizeof(FILETIME);
645 if (RegQueryValueEx(hKey,
646 L"DriverDateData",
647 NULL,
648 &dwType,
649 (LPBYTE)&DriverDate,
650 &dwSize) == ERROR_SUCCESS &&
651 dwType == REG_BINARY &&
652 dwSize == sizeof(FILETIME) &&
653 FileTimeToSystemTime(&DriverDate,
654 &SystemTime) &&
655 SystemTimeToTzSpecificLocalTime(NULL,
656 &SystemTime,
657 &LocalTime) &&
658 GetDateFormat(LOCALE_USER_DEFAULT,
659 DATE_SHORTDATE,
660 &LocalTime,
661 NULL,
662 szBuffer,
663 BufferSize) != 0)
664 {
665 Ret = TRUE;
666 }
667
668 RegCloseKey(hKey);
669 }
670
671 if (!Ret)
672 {
673 /* unable to query the information */
674 if (LoadString(hDllInstance,
675 IDS_NOTAVAILABLE,
676 szBuffer,
677 BufferSize))
678 {
679 Ret = TRUE;
680 }
681 }
682
683 return Ret;
684 }
685
686
687
688 BOOL
689 IsDeviceHidden(IN DEVINST DevInst,
690 IN HMACHINE hMachine,
691 OUT BOOL *IsHidden)
692 {
693 CONFIGRET cr;
694 ULONG Status, ProblemNumber;
695 BOOL Ret = FALSE;
696
697 cr = CM_Get_DevNode_Status_Ex(&Status,
698 &ProblemNumber,
699 DevInst,
700 0,
701 hMachine);
702 if (cr == CR_SUCCESS)
703 {
704 *IsHidden = ((Status & DN_NO_SHOW_IN_DM) != 0);
705 Ret = TRUE;
706 }
707
708 return Ret;
709 }
710
711
712 BOOL
713 CanDisableDevice(IN DEVINST DevInst,
714 IN HMACHINE hMachine,
715 OUT BOOL *CanDisable)
716 {
717 CONFIGRET cr;
718 ULONG Status, ProblemNumber;
719 BOOL Ret = FALSE;
720
721 cr = CM_Get_DevNode_Status_Ex(&Status,
722 &ProblemNumber,
723 DevInst,
724 0,
725 hMachine);
726 if (cr == CR_SUCCESS)
727 {
728 *CanDisable = ((Status & DN_DISABLEABLE) != 0);
729 Ret = TRUE;
730 }
731
732 return Ret;
733 }
734
735
736 BOOL
737 IsDeviceStarted(IN DEVINST DevInst,
738 IN HMACHINE hMachine,
739 OUT BOOL *IsStarted)
740 {
741 CONFIGRET cr;
742 ULONG Status, ProblemNumber;
743 BOOL Ret = FALSE;
744
745 cr = CM_Get_DevNode_Status_Ex(&Status,
746 &ProblemNumber,
747 DevInst,
748 0,
749 hMachine);
750 if (cr == CR_SUCCESS)
751 {
752 *IsStarted = ((Status & DN_STARTED) != 0);
753 Ret = TRUE;
754 }
755
756 return Ret;
757 }
758
759
760 BOOL
761 IsDriverInstalled(IN DEVINST DevInst,
762 IN HMACHINE hMachine,
763 OUT BOOL *Installed)
764 {
765 CONFIGRET cr;
766 ULONG Status, ProblemNumber;
767 BOOL Ret = FALSE;
768
769 cr = CM_Get_DevNode_Status_Ex(&Status,
770 &ProblemNumber,
771 DevInst,
772 0,
773 hMachine);
774 if (cr == CR_SUCCESS)
775 {
776 *Installed = ((Status & DN_HAS_PROBLEM) != 0 ||
777 (Status & (DN_DRIVER_LOADED | DN_STARTED)) != 0);
778 Ret = TRUE;
779 }
780
781 return Ret;
782 }
783
784
785 BOOL
786 EnableDevice(IN HDEVINFO DeviceInfoSet,
787 IN PSP_DEVINFO_DATA DevInfoData OPTIONAL,
788 IN BOOL bEnable,
789 IN DWORD HardwareProfile OPTIONAL,
790 OUT BOOL *bNeedReboot OPTIONAL)
791 {
792 SP_PROPCHANGE_PARAMS pcp;
793 SP_DEVINSTALL_PARAMS dp;
794 DWORD LastErr;
795 BOOL Ret = FALSE;
796
797 pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
798 pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
799 pcp.HwProfile = HardwareProfile;
800
801 if (bEnable)
802 {
803 /* try to enable the device on the global profile */
804 pcp.StateChange = DICS_ENABLE;
805 pcp.Scope = DICS_FLAG_GLOBAL;
806
807 /* ignore errors */
808 LastErr = GetLastError();
809 if (SetupDiSetClassInstallParams(DeviceInfoSet,
810 DevInfoData,
811 &pcp.ClassInstallHeader,
812 sizeof(SP_PROPCHANGE_PARAMS)))
813 {
814 SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
815 DeviceInfoSet,
816 DevInfoData);
817 }
818 SetLastError(LastErr);
819 }
820
821 /* try config-specific */
822 pcp.StateChange = (bEnable ? DICS_ENABLE : DICS_DISABLE);
823 pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
824
825 if (SetupDiSetClassInstallParams(DeviceInfoSet,
826 DevInfoData,
827 &pcp.ClassInstallHeader,
828 sizeof(SP_PROPCHANGE_PARAMS)) &&
829 SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
830 DeviceInfoSet,
831 DevInfoData))
832 {
833 dp.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
834 if (SetupDiGetDeviceInstallParams(DeviceInfoSet,
835 DevInfoData,
836 &dp))
837 {
838 if (bNeedReboot != NULL)
839 {
840 *bNeedReboot = ((dp.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)) != 0);
841 }
842
843 Ret = TRUE;
844 }
845 }
846 return Ret;
847 }
848
849
850 BOOL
851 GetDeviceTypeString(IN PSP_DEVINFO_DATA DeviceInfoData,
852 OUT LPWSTR szBuffer,
853 IN DWORD BufferSize)
854 {
855 BOOL Ret = FALSE;
856
857 if (!SetupDiGetClassDescription(&DeviceInfoData->ClassGuid,
858 szBuffer,
859 BufferSize,
860 NULL))
861 {
862 szBuffer[0] = L'\0';
863 if (LoadString(hDllInstance,
864 IDS_UNKNOWN,
865 szBuffer,
866 BufferSize))
867 {
868 Ret = TRUE;
869 }
870 }
871 else
872 {
873 /* FIXME - check string for NULL termination! */
874 Ret = TRUE;
875 }
876
877 return Ret;
878 }
879
880
881 BOOL
882 GetDeviceDescriptionString(IN HDEVINFO DeviceInfoSet,
883 IN PSP_DEVINFO_DATA DeviceInfoData,
884 OUT LPWSTR szBuffer,
885 IN DWORD BufferSize)
886 {
887 DWORD RegDataType;
888 BOOL Ret = FALSE;
889
890 if ((SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
891 DeviceInfoData,
892 SPDRP_FRIENDLYNAME,
893 &RegDataType,
894 (PBYTE)szBuffer,
895 BufferSize * sizeof(WCHAR),
896 NULL) ||
897 SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
898 DeviceInfoData,
899 SPDRP_DEVICEDESC,
900 &RegDataType,
901 (PBYTE)szBuffer,
902 BufferSize * sizeof(WCHAR),
903 NULL)) &&
904 RegDataType == REG_SZ)
905 {
906 /* FIXME - check string for NULL termination! */
907 Ret = TRUE;
908 }
909 else
910 {
911 szBuffer[0] = L'\0';
912 if (LoadString(hDllInstance,
913 IDS_UNKNOWNDEVICE,
914 szBuffer,
915 BufferSize))
916 {
917 Ret = TRUE;
918 }
919 }
920
921 return Ret;
922 }
923
924
925 BOOL
926 FindCurrentDriver(IN HDEVINFO DeviceInfoSet,
927 IN PSP_DEVINFO_DATA DeviceInfoData,
928 OUT PSP_DRVINFO_DATA DriverInfoData)
929 {
930 HKEY hKey = (HKEY)INVALID_HANDLE_VALUE;
931 SP_DEVINSTALL_PARAMS InstallParams = {0};
932 SP_DRVINFO_DETAIL_DATA DriverInfoDetailData = {0};
933 WCHAR InfPath[MAX_PATH];
934 WCHAR InfSection[LINE_LEN];
935 DWORD dwType, dwLength;
936 DWORD i = 0;
937 LONG rc;
938 BOOL Ret = FALSE;
939
940 /* Steps to find the right driver:
941 * 1) Get the device install parameters
942 * 2) Open the driver registry key
943 * 3) Read the .inf file name
944 * 4) Update install params, by setting DI_ENUMSINGLEINF and .inf file name
945 * 5) Build class driver list
946 * 6) Read inf section and inf section extension from registry
947 * 7) Enumerate drivers
948 * 8) Find the one who is in the same section as current driver?
949 */
950
951 /* 1) Get the install params */
952 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
953 if (!SetupDiGetDeviceInstallParams(DeviceInfoSet,
954 DeviceInfoData,
955 &InstallParams))
956 {
957 ERR("SetupDiSetDeviceInstallParams() failed with error 0x%lx\n", GetLastError());
958 goto Cleanup;
959 }
960
961 #ifdef DI_FLAGSEX_INSTALLEDDRIVER
962 InstallParams.FlagsEx |= (DI_FLAGSEX_INSTALLEDDRIVER | DI_FLAGSEX_ALLOWEXCLUDEDDRVS);
963 if (SetupDiSetDeviceInstallParams(DeviceInfoSet,
964 DeviceInfoData,
965 &InstallParams))
966 {
967 if (SetupDiBuildDriverInfoList(DeviceInfoSet,
968 DeviceInfoData,
969 SPDIT_CLASSDRIVER) &&
970 SetupDiEnumDriverInfo(DeviceInfoSet,
971 DeviceInfoData,
972 SPDIT_CLASSDRIVER,
973 0,
974 DriverInfoData))
975 {
976 Ret = TRUE;
977 }
978
979 goto Cleanup;
980 }
981 InstallParams.FlagsEx &= ~(DI_FLAGSEX_INSTALLEDDRIVER | DI_FLAGSEX_ALLOWEXCLUDEDDRVS);
982 #endif
983
984 /* 2) Open the driver registry key */
985 hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
986 DeviceInfoData,
987 DICS_FLAG_GLOBAL,
988 0,
989 DIREG_DRV,
990 KEY_QUERY_VALUE);
991 if (hKey == INVALID_HANDLE_VALUE)
992 {
993 ERR("SetupDiOpenDevRegKey() failed with error 0x%lx\n", GetLastError());
994 goto Cleanup;
995 }
996
997 /* 3) Read the .inf file name */
998 dwLength = (sizeof(InfPath) / sizeof(InfPath[0])) - 1;
999 rc = RegQueryValueEx(hKey,
1000 REGSTR_VAL_INFPATH,
1001 0,
1002 &dwType,
1003 (LPBYTE)InfPath,
1004 &dwLength);
1005 if (rc != ERROR_SUCCESS)
1006 {
1007 ERR("RegQueryValueEx() failed with error 0x%lx\n", GetLastError());
1008 SetLastError(rc);
1009 goto Cleanup;
1010 }
1011 else if (dwType != REG_SZ)
1012 {
1013 ERR("Expected registry type REG_SZ (%lu), got %lu\n", REG_SZ, dwType);
1014 SetLastError(ERROR_GEN_FAILURE);
1015 goto Cleanup;
1016 }
1017 InfPath[(dwLength / sizeof(WCHAR)) - 1] = L'\0';
1018
1019 /* 4) Update install params, by setting DI_ENUMSINGLEINF and .inf file name */
1020 InstallParams.Flags |= DI_ENUMSINGLEINF;
1021 InstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
1022 wcscpy(InstallParams.DriverPath, InfPath);
1023 if (!SetupDiSetDeviceInstallParams(DeviceInfoSet,
1024 DeviceInfoData,
1025 &InstallParams))
1026 {
1027 ERR("SetupDiSetDeviceInstallParams() failed with error 0x%lx\n", GetLastError());
1028 goto Cleanup;
1029 }
1030
1031 /* 5) Build class driver list */
1032 if (!SetupDiBuildDriverInfoList(DeviceInfoSet,
1033 DeviceInfoData,
1034 SPDIT_CLASSDRIVER))
1035 {
1036 ERR("SetupDiBuildDriverInfoList() failed with error 0x%lx\n", GetLastError());
1037 goto Cleanup;
1038 }
1039
1040 /* 6) Read inf section and from registry */
1041 dwLength = (sizeof(InfSection) / sizeof(InfSection[0])) - 1;
1042 rc = RegQueryValueEx(hKey,
1043 REGSTR_VAL_INFSECTION,
1044 0,
1045 &dwType,
1046 (LPBYTE)InfSection,
1047 &dwLength);
1048 if (rc != ERROR_SUCCESS)
1049 {
1050 ERR("RegQueryValueEx() failed with error 0x%lx\n", GetLastError());
1051 SetLastError(rc);
1052 goto Cleanup;
1053 }
1054 else if (dwType != REG_SZ)
1055 {
1056 ERR("Expected registry type REG_SZ (%lu), got %lu\n", REG_SZ, dwType);
1057 SetLastError(ERROR_GEN_FAILURE);
1058 goto Cleanup;
1059 }
1060 InfPath[(dwLength / sizeof(WCHAR)) - 1] = L'\0';
1061
1062 /* 7) Enumerate drivers */
1063 DriverInfoData->cbSize = sizeof(SP_DRVINFO_DATA);
1064 DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
1065 while (SetupDiEnumDriverInfo(DeviceInfoSet,
1066 DeviceInfoData,
1067 SPDIT_CLASSDRIVER,
1068 i,
1069 DriverInfoData))
1070 {
1071 /* 8) Find the one who is in the same section as current driver */
1072 if (!SetupDiGetDriverInfoDetail(DeviceInfoSet,
1073 DeviceInfoData,
1074 DriverInfoData,
1075 &DriverInfoDetailData,
1076 DriverInfoDetailData.cbSize,
1077 NULL) &&
1078 GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1079 {
1080 ERR("SetupDiGetDriverInfoDetail() failed with error 0x%lx\n", GetLastError());
1081 goto Cleanup;
1082 }
1083 if (!_wcsicmp(DriverInfoDetailData.SectionName,
1084 InfSection) != 0)
1085 {
1086 /* We have found the right driver */
1087 Ret = TRUE;
1088 goto Cleanup;
1089 }
1090
1091 i++;
1092 }
1093 if (GetLastError() != ERROR_NO_MORE_ITEMS)
1094 {
1095 ERR("SetupDiEnumDriverInfo() failed with error 0x%lx\n", GetLastError());
1096 goto Cleanup;
1097 }
1098
1099 SetLastError(ERROR_NO_DRIVER_SELECTED);
1100
1101 Cleanup:
1102 if (hKey != INVALID_HANDLE_VALUE)
1103 RegCloseKey(hKey);
1104 return Ret;
1105 }
1106
1107
1108 HINSTANCE
1109 LoadAndInitComctl32(VOID)
1110 {
1111 typedef VOID (WINAPI *PINITCOMMONCONTROLS)(VOID);
1112 PINITCOMMONCONTROLS pInitCommonControls;
1113 HINSTANCE hComCtl32;
1114
1115 hComCtl32 = LoadLibrary(L"comctl32.dll");
1116 if (hComCtl32 != NULL)
1117 {
1118 /* initialize the common controls */
1119 pInitCommonControls = (PINITCOMMONCONTROLS)GetProcAddress(hComCtl32,
1120 "InitCommonControls");
1121 if (pInitCommonControls == NULL)
1122 {
1123 FreeLibrary(hComCtl32);
1124 return NULL;
1125 }
1126
1127 pInitCommonControls();
1128 }
1129
1130 return hComCtl32;
1131 }