use a .spec file and fix the export ordinals
[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 #define NDEBUG
31 #include <debug.h>
32
33 HINSTANCE hDllInstance = NULL;
34
35
36 INT
37 LengthOfStrResource(IN HINSTANCE hInst,
38 IN UINT uID)
39 {
40 HRSRC hrSrc;
41 HGLOBAL hRes;
42 LPWSTR lpName, lpStr;
43
44 if (hInst == NULL)
45 {
46 return -1;
47 }
48
49 /* There are always blocks of 16 strings */
50 lpName = (LPWSTR)MAKEINTRESOURCE((uID >> 4) + 1);
51
52 /* Find the string table block */
53 if ((hrSrc = FindResourceW(hInst, lpName, (LPWSTR)RT_STRING)) &&
54 (hRes = LoadResource(hInst, hrSrc)) &&
55 (lpStr = LockResource(hRes)))
56 {
57 UINT x;
58
59 /* Find the string we're looking for */
60 uID &= 0xF; /* position in the block, same as % 16 */
61 for (x = 0; x < uID; x++)
62 {
63 lpStr += (*lpStr) + 1;
64 }
65
66 /* Found the string */
67 return (int)(*lpStr);
68 }
69 return -1;
70 }
71
72
73 static INT
74 AllocAndLoadString(OUT LPWSTR *lpTarget,
75 IN HINSTANCE hInst,
76 IN UINT uID)
77 {
78 INT ln;
79
80 ln = LengthOfStrResource(hInst,
81 uID);
82 if (ln++ > 0)
83 {
84 (*lpTarget) = (LPWSTR)LocalAlloc(LMEM_FIXED,
85 ln * sizeof(WCHAR));
86 if ((*lpTarget) != NULL)
87 {
88 INT Ret;
89 if (!(Ret = LoadStringW(hInst, uID, *lpTarget, ln)))
90 {
91 LocalFree((HLOCAL)(*lpTarget));
92 }
93 return Ret;
94 }
95 }
96 return 0;
97 }
98
99
100 static INT
101 AllocAndLoadStringsCat(OUT LPWSTR *lpTarget,
102 IN HINSTANCE hInst,
103 IN UINT *uID,
104 IN UINT nIDs)
105 {
106 INT ln = 0;
107 UINT i;
108
109 for (i = 0;
110 i != nIDs;
111 i++)
112 {
113 ln += LengthOfStrResource(hInst,
114 uID[i]);
115 }
116
117 if (ln != 0)
118 {
119 (*lpTarget) = (LPWSTR)LocalAlloc(LMEM_FIXED,
120 (ln + 1) * sizeof(WCHAR));
121 if ((*lpTarget) != NULL)
122 {
123 LPWSTR s = *lpTarget;
124 INT Ret = 0;
125
126 for (i = 0;
127 i != nIDs;
128 i++)
129 {
130 if (!(Ret = LoadStringW(hInst, uID[i], s, ln)))
131 {
132 LocalFree((HLOCAL)(*lpTarget));
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 = 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 DEVINST dnDevInst OPTIONAL,
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 BOOL Ret = FALSE;
330
331 DataSize = BufferSize * sizeof(WCHAR);
332 szBuffer[0] = L'\0';
333 if (dnParentDevInst != 0)
334 {
335 /* query the parent node name */
336 if (CM_Get_DevNode_Registry_Property(dnParentDevInst,
337 CM_DRP_DEVICEDESC,
338 &RegDataType,
339 szBuffer,
340 &DataSize,
341 0) == CR_SUCCESS &&
342 RegDataType == REG_SZ &&
343 LoadAndFormatString(hDllInstance,
344 IDS_DEVONPARENT,
345 &szFormatted,
346 szBuffer) != 0)
347 {
348 wcsncpy(szBuffer,
349 szFormatted,
350 BufferSize - 1);
351 szBuffer[BufferSize - 1] = L'\0';
352 LocalFree((HLOCAL)szFormatted);
353 Ret = TRUE;
354 }
355 }
356 else if (dnDevInst != 0)
357 {
358 cRet = CM_Get_DevNode_Registry_Property(dnDevInst,
359 CM_DRP_LOCATION_INFORMATION,
360 &RegDataType,
361 szBuffer,
362 &DataSize,
363 0);
364 if (cRet == CR_SUCCESS && RegDataType == REG_SZ)
365 {
366 /* FIXME - check string for NULL termination! */
367 Ret = TRUE;
368 }
369
370 if (Ret && szBuffer[0] >= L'0' && szBuffer[0] <= L'9')
371 {
372 /* convert the string to an integer value and create a
373 formatted string */
374 ULONG ulLocation = (ULONG)wcstoul(szBuffer,
375 NULL,
376 10);
377 if (LoadAndFormatString(hDllInstance,
378 IDS_LOCATIONSTR,
379 &szFormatted,
380 ulLocation,
381 szBuffer) != 0)
382 {
383 wcsncpy(szBuffer,
384 szFormatted,
385 BufferSize - 1);
386 szBuffer[BufferSize - 1] = L'\0';
387 LocalFree((HLOCAL)szFormatted);
388 }
389 else
390 Ret = FALSE;
391 }
392 }
393
394 if (!Ret &&
395 LoadString(hDllInstance,
396 IDS_UNKNOWN,
397 szBuffer,
398 BufferSize))
399 {
400 Ret = TRUE;
401 }
402
403 return Ret;
404 }
405
406
407 BOOL
408 GetDeviceStatusString(IN DEVINST DevInst,
409 IN HMACHINE hMachine,
410 OUT LPWSTR szBuffer,
411 IN DWORD BufferSize)
412 {
413 CONFIGRET cr;
414 ULONG Status, ProblemNumber;
415 UINT MessageId = IDS_UNKNOWN;
416 BOOL Ret = FALSE;
417
418 szBuffer[0] = L'\0';
419 cr = CM_Get_DevNode_Status_Ex(&Status,
420 &ProblemNumber,
421 DevInst,
422 0,
423 hMachine);
424 if (cr == CR_SUCCESS)
425 {
426 if (Status & DN_HAS_PROBLEM)
427 {
428 UINT uRet;
429
430 uRet = DeviceProblemText(hMachine,
431 DevInst,
432 ProblemNumber,
433 szBuffer,
434 (BufferSize != 0 ? BufferSize : BufferSize - 1));
435
436 Ret = (uRet != 0 && uRet < BufferSize);
437 }
438 else
439 {
440 if (!(Status & (DN_DRIVER_LOADED | DN_STARTED)))
441 {
442 MessageId = IDS_NODRIVERLOADED;
443 }
444 else
445 {
446 MessageId = IDS_DEV_NO_PROBLEM;
447 }
448
449 goto GeneralMessage;
450 }
451 }
452 else
453 {
454 GeneralMessage:
455 if (LoadString(hDllInstance,
456 MessageId,
457 szBuffer,
458 (int)BufferSize))
459 {
460 Ret = TRUE;
461 }
462 }
463
464 return Ret;
465 }
466
467
468 BOOL
469 GetDriverProviderString(IN HDEVINFO DeviceInfoSet,
470 IN PSP_DEVINFO_DATA DeviceInfoData,
471 OUT LPWSTR szBuffer,
472 IN DWORD BufferSize)
473 {
474 HKEY hKey;
475 DWORD dwSize, dwType;
476 BOOL Ret = FALSE;
477
478 szBuffer[0] = L'\0';
479
480 /* get driver provider, date and version */
481 hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
482 DeviceInfoData,
483 DICS_FLAG_GLOBAL,
484 0,
485 DIREG_DRV,
486 KEY_QUERY_VALUE);
487 if (hKey != INVALID_HANDLE_VALUE)
488 {
489 /* query the driver provider */
490 dwSize = BufferSize;
491 if (RegQueryValueEx(hKey,
492 REGSTR_VAL_PROVIDER_NAME,
493 NULL,
494 &dwType,
495 (LPBYTE)szBuffer,
496 &dwSize) == ERROR_SUCCESS &&
497 dwType == REG_SZ &&
498 szBuffer[0] != L'\0')
499 {
500 Ret = TRUE;
501 }
502 else
503 {
504 szBuffer[0] = L'\0';
505 }
506
507 RegCloseKey(hKey);
508 }
509
510 if (szBuffer[0] == L'\0')
511 {
512 /* unable to query the information */
513 if (LoadString(hDllInstance,
514 IDS_UNKNOWN,
515 szBuffer,
516 BufferSize))
517 {
518 Ret = TRUE;
519 }
520 }
521
522 return Ret;
523 }
524
525
526 BOOL
527 GetDriverVersionString(IN HDEVINFO DeviceInfoSet,
528 IN PSP_DEVINFO_DATA DeviceInfoData,
529 OUT LPWSTR szBuffer,
530 IN DWORD BufferSize)
531 {
532 HKEY hKey;
533 DWORD dwSize, dwType;
534 BOOL Ret = FALSE;
535
536 szBuffer[0] = L'\0';
537
538 /* get driver provider, date and version */
539 hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
540 DeviceInfoData,
541 DICS_FLAG_GLOBAL,
542 0,
543 DIREG_DRV,
544 KEY_QUERY_VALUE);
545 if (hKey != INVALID_HANDLE_VALUE)
546 {
547 /* query the driver provider */
548 dwSize = BufferSize;
549 if (RegQueryValueEx(hKey,
550 L"DriverVersion",
551 NULL,
552 &dwType,
553 (LPBYTE)szBuffer,
554 &dwSize) == ERROR_SUCCESS &&
555 dwType == REG_SZ &&
556 szBuffer[0] != L'\0')
557 {
558 Ret = TRUE;
559 }
560 else
561 {
562 szBuffer[0] = L'\0';
563 }
564
565 RegCloseKey(hKey);
566 }
567
568 if (szBuffer[0] == L'\0')
569 {
570 /* unable to query the information */
571 if (LoadString(hDllInstance,
572 IDS_NOTAVAILABLE,
573 szBuffer,
574 BufferSize))
575 {
576 Ret = TRUE;
577 }
578 }
579
580 return Ret;
581 }
582
583 BOOL
584 GetDriverDateString(IN HDEVINFO DeviceInfoSet,
585 IN PSP_DEVINFO_DATA DeviceInfoData,
586 OUT LPWSTR szBuffer,
587 IN DWORD BufferSize)
588 {
589 HKEY hKey;
590 FILETIME DriverDate;
591 SYSTEMTIME SystemTime, LocalTime;
592 DWORD dwSize, dwType;
593 BOOL Ret = FALSE;
594
595 szBuffer[0] = L'\0';
596
597 /* get driver provider, date and version */
598 hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
599 DeviceInfoData,
600 DICS_FLAG_GLOBAL,
601 0,
602 DIREG_DRV,
603 KEY_QUERY_VALUE);
604 if (hKey != INVALID_HANDLE_VALUE)
605 {
606 /* query the driver provider */
607 dwSize = sizeof(FILETIME);
608 if (RegQueryValueEx(hKey,
609 L"DriverDateData",
610 NULL,
611 &dwType,
612 (LPBYTE)&DriverDate,
613 &dwSize) == ERROR_SUCCESS &&
614 dwType == REG_BINARY &&
615 dwSize == sizeof(FILETIME) &&
616 FileTimeToSystemTime(&DriverDate,
617 &SystemTime) &&
618 SystemTimeToTzSpecificLocalTime(NULL,
619 &SystemTime,
620 &LocalTime) &&
621 GetDateFormat(LOCALE_USER_DEFAULT,
622 DATE_SHORTDATE,
623 &LocalTime,
624 NULL,
625 szBuffer,
626 BufferSize) != 0)
627 {
628 Ret = TRUE;
629 }
630
631 RegCloseKey(hKey);
632 }
633
634 if (!Ret)
635 {
636 /* unable to query the information */
637 if (LoadString(hDllInstance,
638 IDS_NOTAVAILABLE,
639 szBuffer,
640 BufferSize))
641 {
642 Ret = TRUE;
643 }
644 }
645
646 return Ret;
647 }
648
649
650
651 BOOL
652 IsDeviceHidden(IN DEVINST DevInst,
653 IN HMACHINE hMachine,
654 OUT BOOL *IsHidden)
655 {
656 CONFIGRET cr;
657 ULONG Status, ProblemNumber;
658 BOOL Ret = FALSE;
659
660 cr = CM_Get_DevNode_Status_Ex(&Status,
661 &ProblemNumber,
662 DevInst,
663 0,
664 hMachine);
665 if (cr == CR_SUCCESS)
666 {
667 *IsHidden = ((Status & DN_NO_SHOW_IN_DM) != 0);
668 Ret = TRUE;
669 }
670
671 return Ret;
672 }
673
674
675 BOOL
676 CanDisableDevice(IN DEVINST DevInst,
677 IN HMACHINE hMachine,
678 OUT BOOL *CanDisable)
679 {
680 CONFIGRET cr;
681 ULONG Status, ProblemNumber;
682 BOOL Ret = FALSE;
683
684 cr = CM_Get_DevNode_Status_Ex(&Status,
685 &ProblemNumber,
686 DevInst,
687 0,
688 hMachine);
689 if (cr == CR_SUCCESS)
690 {
691 *CanDisable = ((Status & DN_DISABLEABLE) != 0);
692 Ret = TRUE;
693 }
694
695 return Ret;
696 }
697
698
699 BOOL
700 IsDeviceStarted(IN DEVINST DevInst,
701 IN HMACHINE hMachine,
702 OUT BOOL *IsStarted)
703 {
704 CONFIGRET cr;
705 ULONG Status, ProblemNumber;
706 BOOL Ret = FALSE;
707
708 cr = CM_Get_DevNode_Status_Ex(&Status,
709 &ProblemNumber,
710 DevInst,
711 0,
712 hMachine);
713 if (cr == CR_SUCCESS)
714 {
715 *IsStarted = ((Status & DN_STARTED) != 0);
716 Ret = TRUE;
717 }
718
719 return Ret;
720 }
721
722
723 BOOL
724 IsDriverInstalled(IN DEVINST DevInst,
725 IN HMACHINE hMachine,
726 OUT BOOL *Installed)
727 {
728 CONFIGRET cr;
729 ULONG Status, ProblemNumber;
730 BOOL Ret = FALSE;
731
732 cr = CM_Get_DevNode_Status_Ex(&Status,
733 &ProblemNumber,
734 DevInst,
735 0,
736 hMachine);
737 if (cr == CR_SUCCESS)
738 {
739 *Installed = ((Status & DN_HAS_PROBLEM) != 0 ||
740 (Status & (DN_DRIVER_LOADED | DN_STARTED)) != 0);
741 Ret = TRUE;
742 }
743
744 return Ret;
745 }
746
747
748 BOOL
749 EnableDevice(IN HDEVINFO DeviceInfoSet,
750 IN PSP_DEVINFO_DATA DevInfoData OPTIONAL,
751 IN BOOL bEnable,
752 IN DWORD HardwareProfile OPTIONAL,
753 OUT BOOL *bNeedReboot OPTIONAL)
754 {
755 SP_PROPCHANGE_PARAMS pcp;
756 SP_DEVINSTALL_PARAMS dp;
757 DWORD LastErr;
758 BOOL Ret = FALSE;
759
760 pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
761 pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
762 pcp.HwProfile = HardwareProfile;
763
764 if (bEnable)
765 {
766 /* try to enable the device on the global profile */
767 pcp.StateChange = DICS_ENABLE;
768 pcp.Scope = DICS_FLAG_GLOBAL;
769
770 /* ignore errors */
771 LastErr = GetLastError();
772 if (SetupDiSetClassInstallParams(DeviceInfoSet,
773 DevInfoData,
774 &pcp.ClassInstallHeader,
775 sizeof(SP_PROPCHANGE_PARAMS)))
776 {
777 SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
778 DeviceInfoSet,
779 DevInfoData);
780 }
781 SetLastError(LastErr);
782 }
783
784 /* try config-specific */
785 pcp.StateChange = (bEnable ? DICS_ENABLE : DICS_DISABLE);
786 pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
787
788 if (SetupDiSetClassInstallParams(DeviceInfoSet,
789 DevInfoData,
790 &pcp.ClassInstallHeader,
791 sizeof(SP_PROPCHANGE_PARAMS)) &&
792 SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
793 DeviceInfoSet,
794 DevInfoData))
795 {
796 dp.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
797 if (SetupDiGetDeviceInstallParams(DeviceInfoSet,
798 DevInfoData,
799 &dp))
800 {
801 if (bNeedReboot != NULL)
802 {
803 *bNeedReboot = ((dp.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)) != 0);
804 }
805
806 Ret = TRUE;
807 }
808 }
809 return Ret;
810 }
811
812
813 BOOL
814 GetDeviceTypeString(IN PSP_DEVINFO_DATA DeviceInfoData,
815 OUT LPWSTR szBuffer,
816 IN DWORD BufferSize)
817 {
818 BOOL Ret = FALSE;
819
820 if (!SetupDiGetClassDescription(&DeviceInfoData->ClassGuid,
821 szBuffer,
822 BufferSize,
823 NULL))
824 {
825 szBuffer[0] = L'\0';
826 if (LoadString(hDllInstance,
827 IDS_UNKNOWN,
828 szBuffer,
829 BufferSize))
830 {
831 Ret = TRUE;
832 }
833 }
834 else
835 {
836 /* FIXME - check string for NULL termination! */
837 Ret = TRUE;
838 }
839
840 return Ret;
841 }
842
843
844 BOOL
845 GetDeviceDescriptionString(IN HDEVINFO DeviceInfoSet,
846 IN PSP_DEVINFO_DATA DeviceInfoData,
847 OUT LPWSTR szBuffer,
848 IN DWORD BufferSize)
849 {
850 DWORD RegDataType;
851 BOOL Ret = FALSE;
852
853 if ((SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
854 DeviceInfoData,
855 SPDRP_FRIENDLYNAME,
856 &RegDataType,
857 (PBYTE)szBuffer,
858 BufferSize * sizeof(WCHAR),
859 NULL) ||
860 SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
861 DeviceInfoData,
862 SPDRP_DEVICEDESC,
863 &RegDataType,
864 (PBYTE)szBuffer,
865 BufferSize * sizeof(WCHAR),
866 NULL)) &&
867 RegDataType == REG_SZ)
868 {
869 /* FIXME - check string for NULL termination! */
870 Ret = TRUE;
871 }
872 else
873 {
874 szBuffer[0] = L'\0';
875 if (LoadString(hDllInstance,
876 IDS_UNKNOWNDEVICE,
877 szBuffer,
878 BufferSize))
879 {
880 Ret = TRUE;
881 }
882 }
883
884 return Ret;
885 }
886
887
888 BOOL
889 FindCurrentDriver(IN HDEVINFO DeviceInfoSet,
890 IN PSP_DEVINFO_DATA DeviceInfoData,
891 OUT PSP_DRVINFO_DATA DriverInfoData)
892 {
893 HKEY hKey = INVALID_HANDLE_VALUE;
894 SP_DEVINSTALL_PARAMS InstallParams = {0};
895 SP_DRVINFO_DETAIL_DATA DriverInfoDetailData = {0};
896 WCHAR InfPath[MAX_PATH];
897 WCHAR InfSection[LINE_LEN];
898 DWORD dwType, dwLength;
899 DWORD i = 0;
900 LONG rc;
901 BOOL Ret = FALSE;
902
903 /* Steps to find the right driver:
904 * 1) Get the device install parameters
905 * 2) Open the driver registry key
906 * 3) Read the .inf file name
907 * 4) Update install params, by setting DI_ENUMSINGLEINF and .inf file name
908 * 5) Build class driver list
909 * 6) Read inf section and inf section extension from registry
910 * 7) Enumerate drivers
911 * 8) Find the one who is in the same section as current driver?
912 */
913
914 /* 1) Get the install params */
915 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
916 if (!SetupDiGetDeviceInstallParams(DeviceInfoSet,
917 DeviceInfoData,
918 &InstallParams))
919 {
920 DPRINT1("SetupDiSetDeviceInstallParams() failed with error 0x%lx\n", GetLastError());
921 goto Cleanup;
922 }
923
924 #ifdef DI_FLAGSEX_INSTALLEDDRIVER
925 InstallParams.FlagsEx |= (DI_FLAGSEX_INSTALLEDDRIVER | DI_FLAGSEX_ALLOWEXCLUDEDDRVS);
926 if (SetupDiSetDeviceInstallParams(DeviceInfoSet,
927 DeviceInfoData,
928 &InstallParams))
929 {
930 if (SetupDiBuildDriverInfoList(DeviceInfoSet,
931 DeviceInfoData,
932 SPDIT_CLASSDRIVER) &&
933 SetupDiEnumDriverInfo(DeviceInfoSet,
934 DeviceInfoData,
935 SPDIT_CLASSDRIVER,
936 0,
937 DriverInfoData))
938 {
939 Ret = TRUE;
940 }
941
942 goto Cleanup;
943 }
944 InstallParams.FlagsEx &= ~(DI_FLAGSEX_INSTALLEDDRIVER | DI_FLAGSEX_ALLOWEXCLUDEDDRVS);
945 #endif
946
947 /* 2) Open the driver registry key */
948 hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
949 DeviceInfoData,
950 DICS_FLAG_GLOBAL,
951 0,
952 DIREG_DRV,
953 KEY_QUERY_VALUE);
954 if (hKey == INVALID_HANDLE_VALUE)
955 {
956 DPRINT1("SetupDiOpenDevRegKey() failed with error 0x%lx\n", GetLastError());
957 goto Cleanup;
958 }
959
960 /* 3) Read the .inf file name */
961 dwLength = (sizeof(InfPath) / sizeof(InfPath[0])) - 1;
962 rc = RegQueryValueEx(hKey,
963 REGSTR_VAL_INFPATH,
964 0,
965 &dwType,
966 (LPBYTE)InfPath,
967 &dwLength);
968 if (rc != ERROR_SUCCESS)
969 {
970 SetLastError(rc);
971 DPRINT1("RegQueryValueEx() failed with error 0x%lx\n", GetLastError());
972 goto Cleanup;
973 }
974 else if (dwType != REG_SZ)
975 {
976 SetLastError(ERROR_GEN_FAILURE);
977 DPRINT1("Expected registry type REG_SZ (%lu), got %lu\n", REG_SZ, dwType);
978 goto Cleanup;
979 }
980 InfPath[(dwLength / sizeof(WCHAR)) - 1] = L'\0';
981
982 /* 4) Update install params, by setting DI_ENUMSINGLEINF and .inf file name */
983 InstallParams.Flags |= DI_ENUMSINGLEINF;
984 InstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
985 wcscpy(InstallParams.DriverPath, InfPath);
986 if (!SetupDiSetDeviceInstallParams(DeviceInfoSet,
987 DeviceInfoData,
988 &InstallParams))
989 {
990 DPRINT1("SetupDiSetDeviceInstallParams() failed with error 0x%lx\n", GetLastError());
991 goto Cleanup;
992 }
993
994 /* 5) Build class driver list */
995 if (!SetupDiBuildDriverInfoList(DeviceInfoSet,
996 DeviceInfoData,
997 SPDIT_CLASSDRIVER))
998 {
999 DPRINT1("SetupDiBuildDriverInfoList() failed with error 0x%lx\n", GetLastError());
1000 goto Cleanup;
1001 }
1002
1003 /* 6) Read inf section and from registry */
1004 dwLength = (sizeof(InfSection) / sizeof(InfSection[0])) - 1;
1005 rc = RegQueryValueEx(hKey,
1006 REGSTR_VAL_INFSECTION,
1007 0,
1008 &dwType,
1009 (LPBYTE)InfSection,
1010 &dwLength);
1011 if (rc != ERROR_SUCCESS)
1012 {
1013 SetLastError(rc);
1014 DPRINT1("RegQueryValueEx() failed with error 0x%lx\n", GetLastError());
1015 goto Cleanup;
1016 }
1017 else if (dwType != REG_SZ)
1018 {
1019 SetLastError(ERROR_GEN_FAILURE);
1020 DPRINT1("Expected registry type REG_SZ (%lu), got %lu\n", REG_SZ, dwType);
1021 goto Cleanup;
1022 }
1023 InfPath[(dwLength / sizeof(WCHAR)) - 1] = L'\0';
1024
1025 /* 7) Enumerate drivers */
1026 DriverInfoData->cbSize = sizeof(SP_DRVINFO_DATA);
1027 DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
1028 while (SetupDiEnumDriverInfo(DeviceInfoSet,
1029 DeviceInfoData,
1030 SPDIT_CLASSDRIVER,
1031 i,
1032 DriverInfoData))
1033 {
1034 /* 8) Find the one who is in the same section as current driver */
1035 if (!SetupDiGetDriverInfoDetail(DeviceInfoSet,
1036 DeviceInfoData,
1037 DriverInfoData,
1038 &DriverInfoDetailData,
1039 DriverInfoDetailData.cbSize,
1040 NULL) &&
1041 GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1042 {
1043 DPRINT1("SetupDiGetDriverInfoDetail() failed with error 0x%lx\n", GetLastError());
1044 goto Cleanup;
1045 }
1046 if (!wcsicmp(DriverInfoDetailData.SectionName,
1047 InfSection) != 0)
1048 {
1049 /* We have found the right driver */
1050 Ret = TRUE;
1051 goto Cleanup;
1052 }
1053
1054 i++;
1055 }
1056 if (GetLastError() != ERROR_NO_MORE_ITEMS)
1057 {
1058 DPRINT1("SetupDiEnumDriverInfo() failed with error 0x%lx\n", GetLastError());
1059 goto Cleanup;
1060 }
1061
1062 SetLastError(ERROR_NO_DRIVER_SELECTED);
1063
1064 Cleanup:
1065 if (hKey != INVALID_HANDLE_VALUE)
1066 RegCloseKey(hKey);
1067 return Ret;
1068 }
1069
1070
1071 HINSTANCE
1072 LoadAndInitComctl32(VOID)
1073 {
1074 typedef VOID (WINAPI *PINITCOMMONCONTROLS)(VOID);
1075 PINITCOMMONCONTROLS pInitCommonControls;
1076 HINSTANCE hComCtl32;
1077
1078 hComCtl32 = LoadLibrary(L"comctl32.dll");
1079 if (hComCtl32 != NULL)
1080 {
1081 /* initialize the common controls */
1082 pInitCommonControls = (PINITCOMMONCONTROLS)GetProcAddress(hComCtl32,
1083 "InitCommonControls");
1084 if (pInitCommonControls == NULL)
1085 {
1086 FreeLibrary(hComCtl32);
1087 return NULL;
1088 }
1089
1090 pInitCommonControls();
1091 }
1092
1093 return hComCtl32;
1094 }
1095
1096
1097 BOOL
1098 STDCALL
1099 DllMain(IN HINSTANCE hinstDLL,
1100 IN DWORD dwReason,
1101 IN LPVOID lpvReserved)
1102 {
1103 switch (dwReason)
1104 {
1105 case DLL_PROCESS_ATTACH:
1106 DisableThreadLibraryCalls(hinstDLL);
1107 hDllInstance = hinstDLL;
1108 break;
1109 }
1110
1111 return TRUE;
1112 }