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