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