Display the driver provider, date and version. Based on a patch by Herve.
[reactos.git] / reactos / lib / devmgr / misc.c
1 /*
2 * ReactOS Device Manager Applet
3 * Copyright (C) 2004 - 2005 ReactOS Team
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19 /* $Id: devmgr.c 12852 2005-01-06 13:58:04Z mf $
20 *
21 * PROJECT: ReactOS devmgr.dll
22 * FILE: lib/devmgr/misc.c
23 * PURPOSE: ReactOS Device Manager
24 * PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
25 * UPDATE HISTORY:
26 * 2005/11/24 Created
27 */
28 #include <precomp.h>
29
30 HINSTANCE hDllInstance = NULL;
31
32
33 INT
34 LengthOfStrResource(IN HINSTANCE hInst,
35 IN UINT uID)
36 {
37 HRSRC hrSrc;
38 HGLOBAL hRes;
39 LPWSTR lpName, lpStr;
40
41 if (hInst == NULL)
42 {
43 return -1;
44 }
45
46 /* There are always blocks of 16 strings */
47 lpName = (LPWSTR)MAKEINTRESOURCE((uID >> 4) + 1);
48
49 /* Find the string table block */
50 if ((hrSrc = FindResourceW(hInst, lpName, (LPWSTR)RT_STRING)) &&
51 (hRes = LoadResource(hInst, hrSrc)) &&
52 (lpStr = LockResource(hRes)))
53 {
54 UINT x;
55
56 /* Find the string we're looking for */
57 uID &= 0xF; /* position in the block, same as % 16 */
58 for (x = 0; x < uID; x++)
59 {
60 lpStr += (*lpStr) + 1;
61 }
62
63 /* Found the string */
64 return (int)(*lpStr);
65 }
66 return -1;
67 }
68
69
70 static INT
71 AllocAndLoadString(OUT LPWSTR *lpTarget,
72 IN HINSTANCE hInst,
73 IN UINT uID)
74 {
75 INT ln;
76
77 ln = LengthOfStrResource(hInst,
78 uID);
79 if (ln++ > 0)
80 {
81 (*lpTarget) = (LPWSTR)LocalAlloc(LMEM_FIXED,
82 ln * sizeof(WCHAR));
83 if ((*lpTarget) != NULL)
84 {
85 INT Ret;
86 if (!(Ret = LoadStringW(hInst, uID, *lpTarget, ln)))
87 {
88 LocalFree((HLOCAL)(*lpTarget));
89 }
90 return Ret;
91 }
92 }
93 return 0;
94 }
95
96
97 static INT
98 AllocAndLoadStringsCat(OUT LPWSTR *lpTarget,
99 IN HINSTANCE hInst,
100 IN UINT *uID,
101 IN UINT nIDs)
102 {
103 INT ln = 0;
104 UINT i;
105
106 for (i = 0;
107 i != nIDs;
108 i++)
109 {
110 ln += LengthOfStrResource(hInst,
111 uID[i]);
112 }
113
114 if (ln != 0)
115 {
116 (*lpTarget) = (LPWSTR)LocalAlloc(LMEM_FIXED,
117 (ln + 1) * sizeof(WCHAR));
118 if ((*lpTarget) != NULL)
119 {
120 LPWSTR s = *lpTarget;
121 INT Ret = 0;
122
123 for (i = 0;
124 i != nIDs;
125 i++)
126 {
127 if (!(Ret = LoadStringW(hInst, uID[i], s, ln)))
128 {
129 LocalFree((HLOCAL)(*lpTarget));
130 }
131
132 s += Ret;
133 }
134
135 return s - *lpTarget;
136 }
137 }
138 return 0;
139 }
140
141
142 DWORD
143 LoadAndFormatString(IN HINSTANCE hInstance,
144 IN UINT uID,
145 OUT LPWSTR *lpTarget,
146 ...)
147 {
148 DWORD Ret = 0;
149 LPWSTR lpFormat;
150 va_list lArgs;
151
152 if (AllocAndLoadString(&lpFormat,
153 hInstance,
154 uID) != 0)
155 {
156 va_start(lArgs, lpTarget);
157 /* let's use FormatMessage to format it because it has the ability to allocate
158 memory automatically */
159 Ret = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
160 lpFormat,
161 0,
162 0,
163 (LPWSTR)lpTarget,
164 0,
165 &lArgs);
166 va_end(lArgs);
167
168 LocalFree((HLOCAL)lpFormat);
169 }
170
171 return Ret;
172 }
173
174
175 DWORD
176 LoadAndFormatStringsCat(IN HINSTANCE hInstance,
177 IN UINT *uID,
178 IN UINT nIDs,
179 OUT LPWSTR *lpTarget,
180 ...)
181 {
182 DWORD Ret = 0;
183 LPWSTR lpFormat;
184 va_list lArgs;
185
186 if (AllocAndLoadStringsCat(&lpFormat,
187 hInstance,
188 uID,
189 nIDs) != 0)
190 {
191 va_start(lArgs, lpTarget);
192 /* let's use FormatMessage to format it because it has the ability to allocate
193 memory automatically */
194 Ret = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
195 lpFormat,
196 0,
197 0,
198 (LPWSTR)lpTarget,
199 0,
200 &lArgs);
201 va_end(lArgs);
202
203 LocalFree((HLOCAL)lpFormat);
204 }
205
206 return Ret;
207 }
208
209
210 LPARAM
211 ListViewGetSelectedItemData(IN HWND hwnd)
212 {
213 int Index;
214
215 Index = ListView_GetNextItem(hwnd,
216 -1,
217 LVNI_SELECTED);
218 if (Index != -1)
219 {
220 LVITEM li;
221
222 li.mask = LVIF_PARAM;
223 li.iItem = Index;
224 li.iSubItem = 0;
225
226 if (ListView_GetItem(hwnd,
227 &li))
228 {
229 return li.lParam;
230 }
231 }
232
233 return 0;
234 }
235
236
237 LPWSTR
238 ConvertMultiByteToUnicode(IN LPCSTR lpMultiByteStr,
239 IN UINT uCodePage)
240 {
241 LPWSTR lpUnicodeStr;
242 INT nLength;
243
244 nLength = MultiByteToWideChar(uCodePage,
245 0,
246 lpMultiByteStr,
247 -1,
248 NULL,
249 0);
250 if (nLength == 0)
251 return NULL;
252
253 lpUnicodeStr = HeapAlloc(GetProcessHeap(),
254 0,
255 nLength * sizeof(WCHAR));
256 if (lpUnicodeStr == NULL)
257 {
258 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
259 return NULL;
260 }
261
262 if (!MultiByteToWideChar(uCodePage,
263 0,
264 lpMultiByteStr,
265 nLength,
266 lpUnicodeStr,
267 nLength))
268 {
269 HeapFree(GetProcessHeap(),
270 0,
271 lpUnicodeStr);
272 return NULL;
273 }
274
275 return lpUnicodeStr;
276 }
277
278
279 BOOL
280 GetDeviceManufacturerString(IN HDEVINFO DeviceInfoSet,
281 IN PSP_DEVINFO_DATA DeviceInfoData,
282 OUT LPWSTR szBuffer,
283 IN DWORD BufferSize)
284 {
285 DWORD RegDataType;
286 BOOL Ret = FALSE;
287
288 if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
289 DeviceInfoData,
290 SPDRP_MFG,
291 &RegDataType,
292 (PBYTE)szBuffer,
293 BufferSize * sizeof(WCHAR),
294 NULL) ||
295 RegDataType != REG_SZ)
296 {
297 szBuffer[0] = L'\0';
298 if (LoadString(hDllInstance,
299 IDS_UNKNOWN,
300 szBuffer,
301 BufferSize))
302 {
303 Ret = TRUE;
304 }
305 }
306 else
307 {
308 /* FIXME - check string for NULL termination! */
309 Ret = TRUE;
310 }
311
312 return Ret;
313 }
314
315
316 BOOL
317 GetDeviceLocationString(IN DEVINST dnDevInst OPTIONAL,
318 IN DEVINST dnParentDevInst OPTIONAL,
319 OUT LPWSTR szBuffer,
320 IN DWORD BufferSize)
321 {
322 DWORD RegDataType;
323 ULONG DataSize;
324 CONFIGRET cRet;
325 LPWSTR szFormatted;
326 BOOL Ret = FALSE;
327
328 DataSize = BufferSize * sizeof(WCHAR);
329 szBuffer[0] = L'\0';
330 if (dnParentDevInst != 0)
331 {
332 /* query the parent node name */
333 if (CM_Get_DevNode_Registry_Property(dnParentDevInst,
334 CM_DRP_DEVICEDESC,
335 &RegDataType,
336 szBuffer,
337 &DataSize,
338 0) == CR_SUCCESS &&
339 RegDataType == REG_SZ &&
340 LoadAndFormatString(hDllInstance,
341 IDS_DEVONPARENT,
342 &szFormatted,
343 szBuffer) != 0)
344 {
345 wcsncpy(szBuffer,
346 szFormatted,
347 BufferSize - 1);
348 szBuffer[BufferSize - 1] = L'\0';
349 LocalFree((HLOCAL)szFormatted);
350 Ret = TRUE;
351 }
352 }
353 else if (dnDevInst != 0)
354 {
355 cRet = CM_Get_DevNode_Registry_Property(dnDevInst,
356 CM_DRP_LOCATION_INFORMATION,
357 &RegDataType,
358 szBuffer,
359 &DataSize,
360 0);
361 if (cRet == CR_SUCCESS && RegDataType == REG_SZ)
362 {
363 /* FIXME - check string for NULL termination! */
364 Ret = TRUE;
365 }
366
367 if (Ret && szBuffer[0] >= L'0' && szBuffer[0] <= L'9')
368 {
369 /* convert the string to an integer value and create a
370 formatted string */
371 ULONG ulLocation = (ULONG)wcstoul(szBuffer,
372 NULL,
373 10);
374 if (LoadAndFormatString(hDllInstance,
375 IDS_LOCATIONSTR,
376 &szFormatted,
377 ulLocation,
378 szBuffer) != 0)
379 {
380 wcsncpy(szBuffer,
381 szFormatted,
382 BufferSize - 1);
383 szBuffer[BufferSize - 1] = L'\0';
384 LocalFree((HLOCAL)szFormatted);
385 }
386 else
387 Ret = FALSE;
388 }
389 }
390
391 if (!Ret &&
392 LoadString(hDllInstance,
393 IDS_UNKNOWN,
394 szBuffer,
395 BufferSize))
396 {
397 Ret = TRUE;
398 }
399
400 return Ret;
401 }
402
403
404 BOOL
405 GetDeviceStatusString(IN DEVINST DevInst,
406 IN HMACHINE hMachine,
407 OUT LPWSTR szBuffer,
408 IN DWORD BufferSize)
409 {
410 CONFIGRET cr;
411 ULONG Status, ProblemNumber;
412 UINT MessageId = IDS_UNKNOWN;
413 BOOL Ret = FALSE;
414
415 szBuffer[0] = L'\0';
416 cr = CM_Get_DevNode_Status_Ex(&Status,
417 &ProblemNumber,
418 DevInst,
419 0,
420 hMachine);
421 if (cr == CR_SUCCESS)
422 {
423 if (Status & DN_HAS_PROBLEM)
424 {
425 UINT uRet;
426
427 uRet = DeviceProblemText(hMachine,
428 DevInst,
429 ProblemNumber,
430 szBuffer,
431 (BufferSize != 0 ? BufferSize : BufferSize - 1));
432
433 Ret = (uRet != 0 && uRet < BufferSize);
434 }
435 else
436 {
437 if (!(Status & (DN_DRIVER_LOADED | DN_STARTED)))
438 {
439 MessageId = IDS_NODRIVERLOADED;
440 }
441 else
442 {
443 MessageId = IDS_DEV_NO_PROBLEM;
444 }
445
446 goto GeneralMessage;
447 }
448 }
449 else
450 {
451 GeneralMessage:
452 if (LoadString(hDllInstance,
453 MessageId,
454 szBuffer,
455 (int)BufferSize))
456 {
457 Ret = TRUE;
458 }
459 }
460
461 return Ret;
462 }
463
464
465 BOOL
466 GetDriverProviderString(IN HDEVINFO DeviceInfoSet,
467 IN PSP_DEVINFO_DATA DeviceInfoData,
468 OUT LPWSTR szBuffer,
469 IN DWORD BufferSize)
470 {
471 HKEY hKey;
472 DWORD dwSize, dwType;
473 BOOL Ret = FALSE;
474
475 szBuffer[0] = L'\0';
476
477 /* get driver provider, date and version */
478 hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
479 DeviceInfoData,
480 DICS_FLAG_GLOBAL,
481 0,
482 DIREG_DRV,
483 KEY_QUERY_VALUE);
484 if (hKey != INVALID_HANDLE_VALUE)
485 {
486 /* query the driver provider */
487 dwSize = BufferSize;
488 if (RegQueryValueEx(hKey,
489 REGSTR_VAL_PROVIDER_NAME,
490 NULL,
491 &dwType,
492 (LPBYTE)szBuffer,
493 &dwSize) == ERROR_SUCCESS &&
494 dwType == REG_SZ &&
495 szBuffer[0] != L'\0')
496 {
497 Ret = TRUE;
498 }
499 else
500 {
501 szBuffer[0] = L'\0';
502 }
503
504 RegCloseKey(hKey);
505 }
506
507 if (szBuffer[0] == L'\0')
508 {
509 /* unable to query the information */
510 if (LoadString(hDllInstance,
511 IDS_UNKNOWN,
512 szBuffer,
513 BufferSize))
514 {
515 Ret = TRUE;
516 }
517 }
518
519 return Ret;
520 }
521
522
523 BOOL
524 GetDriverVersionString(IN HDEVINFO DeviceInfoSet,
525 IN PSP_DEVINFO_DATA DeviceInfoData,
526 OUT LPWSTR szBuffer,
527 IN DWORD BufferSize)
528 {
529 HKEY hKey;
530 DWORD dwSize, dwType;
531 BOOL Ret = FALSE;
532
533 szBuffer[0] = L'\0';
534
535 /* get driver provider, date and version */
536 hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
537 DeviceInfoData,
538 DICS_FLAG_GLOBAL,
539 0,
540 DIREG_DRV,
541 KEY_QUERY_VALUE);
542 if (hKey != INVALID_HANDLE_VALUE)
543 {
544 /* query the driver provider */
545 dwSize = BufferSize;
546 if (RegQueryValueEx(hKey,
547 L"DriverVersion",
548 NULL,
549 &dwType,
550 (LPBYTE)szBuffer,
551 &dwSize) == ERROR_SUCCESS &&
552 dwType == REG_SZ &&
553 szBuffer[0] != L'\0')
554 {
555 Ret = TRUE;
556 }
557 else
558 {
559 szBuffer[0] = L'\0';
560 }
561
562 RegCloseKey(hKey);
563 }
564
565 if (szBuffer[0] == L'\0')
566 {
567 /* unable to query the information */
568 if (LoadString(hDllInstance,
569 IDS_UNKNOWN,
570 szBuffer,
571 BufferSize))
572 {
573 Ret = TRUE;
574 }
575 }
576
577 return Ret;
578 }
579
580 BOOL
581 GetDriverDateString(IN HDEVINFO DeviceInfoSet,
582 IN PSP_DEVINFO_DATA DeviceInfoData,
583 OUT LPWSTR szBuffer,
584 IN DWORD BufferSize)
585 {
586 HKEY hKey;
587 FILETIME DriverDate;
588 SYSTEMTIME SystemTime, LocalTime;
589 DWORD dwSize, dwType;
590 BOOL Ret = FALSE;
591
592 szBuffer[0] = L'\0';
593
594 /* get driver provider, date and version */
595 hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
596 DeviceInfoData,
597 DICS_FLAG_GLOBAL,
598 0,
599 DIREG_DRV,
600 KEY_QUERY_VALUE);
601 if (hKey != INVALID_HANDLE_VALUE)
602 {
603 /* query the driver provider */
604 dwSize = sizeof(FILETIME);
605 if (RegQueryValueEx(hKey,
606 L"DriverDateData",
607 NULL,
608 &dwType,
609 (LPBYTE)&DriverDate,
610 &dwSize) == ERROR_SUCCESS &&
611 dwType == REG_BINARY &&
612 dwSize == sizeof(FILETIME) &&
613 FileTimeToSystemTime(&DriverDate,
614 &SystemTime) &&
615 SystemTimeToTzSpecificLocalTime(NULL,
616 &SystemTime,
617 &LocalTime) &&
618 GetDateFormat(LOCALE_USER_DEFAULT,
619 DATE_SHORTDATE,
620 &LocalTime,
621 NULL,
622 szBuffer,
623 BufferSize) != 0)
624 {
625 Ret = TRUE;
626 }
627
628 RegCloseKey(hKey);
629 }
630
631 if (!Ret)
632 {
633 /* unable to query the information */
634 if (LoadString(hDllInstance,
635 IDS_UNKNOWN,
636 szBuffer,
637 BufferSize))
638 {
639 Ret = TRUE;
640 }
641 }
642
643 return Ret;
644 }
645
646
647
648 BOOL
649 IsDeviceHidden(IN DEVINST DevInst,
650 IN HMACHINE hMachine,
651 OUT BOOL *IsHidden)
652 {
653 CONFIGRET cr;
654 ULONG Status, ProblemNumber;
655 BOOL Ret = FALSE;
656
657 cr = CM_Get_DevNode_Status_Ex(&Status,
658 &ProblemNumber,
659 DevInst,
660 0,
661 hMachine);
662 if (cr == CR_SUCCESS)
663 {
664 *IsHidden = ((Status & DN_NO_SHOW_IN_DM) != 0);
665 Ret = TRUE;
666 }
667
668 return Ret;
669 }
670
671
672 BOOL
673 CanDisableDevice(IN DEVINST DevInst,
674 IN HMACHINE hMachine,
675 OUT BOOL *CanDisable)
676 {
677 CONFIGRET cr;
678 ULONG Status, ProblemNumber;
679 BOOL Ret = FALSE;
680
681 cr = CM_Get_DevNode_Status_Ex(&Status,
682 &ProblemNumber,
683 DevInst,
684 0,
685 hMachine);
686 if (cr == CR_SUCCESS)
687 {
688 *CanDisable = ((Status & DN_DISABLEABLE) != 0);
689 Ret = TRUE;
690 }
691
692 return Ret;
693 }
694
695
696 BOOL
697 IsDeviceStarted(IN DEVINST DevInst,
698 IN HMACHINE hMachine,
699 OUT BOOL *IsStarted)
700 {
701 CONFIGRET cr;
702 ULONG Status, ProblemNumber;
703 BOOL Ret = FALSE;
704
705 cr = CM_Get_DevNode_Status_Ex(&Status,
706 &ProblemNumber,
707 DevInst,
708 0,
709 hMachine);
710 if (cr == CR_SUCCESS)
711 {
712 *IsStarted = ((Status & DN_STARTED) != 0);
713 Ret = TRUE;
714 }
715
716 return Ret;
717 }
718
719
720 BOOL
721 IsDriverInstalled(IN DEVINST DevInst,
722 IN HMACHINE hMachine,
723 OUT BOOL *Installed)
724 {
725 CONFIGRET cr;
726 ULONG Status, ProblemNumber;
727 BOOL Ret = FALSE;
728
729 cr = CM_Get_DevNode_Status_Ex(&Status,
730 &ProblemNumber,
731 DevInst,
732 0,
733 hMachine);
734 if (cr == CR_SUCCESS)
735 {
736 *Installed = ((Status & DN_HAS_PROBLEM) != 0 ||
737 (Status & (DN_DRIVER_LOADED | DN_STARTED)) != 0);
738 Ret = TRUE;
739 }
740
741 return Ret;
742 }
743
744
745 BOOL
746 EnableDevice(IN HDEVINFO DeviceInfoSet,
747 IN PSP_DEVINFO_DATA DevInfoData OPTIONAL,
748 IN BOOL bEnable,
749 IN DWORD HardwareProfile OPTIONAL,
750 OUT BOOL *bNeedReboot OPTIONAL)
751 {
752 SP_PROPCHANGE_PARAMS pcp;
753 SP_DEVINSTALL_PARAMS dp;
754 DWORD LastErr;
755 BOOL Ret = FALSE;
756
757 pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
758 pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
759 pcp.HwProfile = HardwareProfile;
760
761 if (bEnable)
762 {
763 /* try to enable the device on the global profile */
764 pcp.StateChange = DICS_ENABLE;
765 pcp.Scope = DICS_FLAG_GLOBAL;
766
767 /* ignore errors */
768 LastErr = GetLastError();
769 if (SetupDiSetClassInstallParams(DeviceInfoSet,
770 DevInfoData,
771 &pcp.ClassInstallHeader,
772 sizeof(SP_PROPCHANGE_PARAMS)))
773 {
774 SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
775 DeviceInfoSet,
776 DevInfoData);
777 }
778 SetLastError(LastErr);
779 }
780
781 /* try config-specific */
782 pcp.StateChange = (bEnable ? DICS_ENABLE : DICS_DISABLE);
783 pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
784
785 if (SetupDiSetClassInstallParams(DeviceInfoSet,
786 DevInfoData,
787 &pcp.ClassInstallHeader,
788 sizeof(SP_PROPCHANGE_PARAMS)) &&
789 SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
790 DeviceInfoSet,
791 DevInfoData))
792 {
793 dp.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
794 if (SetupDiGetDeviceInstallParams(DeviceInfoSet,
795 DevInfoData,
796 &dp))
797 {
798 if (bNeedReboot != NULL)
799 {
800 *bNeedReboot = ((dp.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)) != 0);
801 }
802
803 Ret = TRUE;
804 }
805 }
806 return Ret;
807 }
808
809
810 BOOL
811 GetDeviceTypeString(IN PSP_DEVINFO_DATA DeviceInfoData,
812 OUT LPWSTR szBuffer,
813 IN DWORD BufferSize)
814 {
815 BOOL Ret = FALSE;
816
817 if (!SetupDiGetClassDescription(&DeviceInfoData->ClassGuid,
818 szBuffer,
819 BufferSize,
820 NULL))
821 {
822 szBuffer[0] = L'\0';
823 if (LoadString(hDllInstance,
824 IDS_UNKNOWN,
825 szBuffer,
826 BufferSize))
827 {
828 Ret = TRUE;
829 }
830 }
831 else
832 {
833 /* FIXME - check string for NULL termination! */
834 Ret = TRUE;
835 }
836
837 return Ret;
838 }
839
840
841 BOOL
842 GetDeviceDescriptionString(IN HDEVINFO DeviceInfoSet,
843 IN PSP_DEVINFO_DATA DeviceInfoData,
844 OUT LPWSTR szBuffer,
845 IN DWORD BufferSize)
846 {
847 DWORD RegDataType;
848 BOOL Ret = FALSE;
849
850 if ((SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
851 DeviceInfoData,
852 SPDRP_FRIENDLYNAME,
853 &RegDataType,
854 (PBYTE)szBuffer,
855 BufferSize * sizeof(WCHAR),
856 NULL) ||
857 SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
858 DeviceInfoData,
859 SPDRP_DEVICEDESC,
860 &RegDataType,
861 (PBYTE)szBuffer,
862 BufferSize * sizeof(WCHAR),
863 NULL)) &&
864 RegDataType == REG_SZ)
865 {
866 /* FIXME - check string for NULL termination! */
867 Ret = TRUE;
868 }
869 else
870 {
871 szBuffer[0] = L'\0';
872 if (LoadString(hDllInstance,
873 IDS_UNKNOWNDEVICE,
874 szBuffer,
875 BufferSize))
876 {
877 Ret = TRUE;
878 }
879 }
880
881 return Ret;
882 }
883
884
885 HINSTANCE
886 LoadAndInitComctl32(VOID)
887 {
888 typedef VOID (WINAPI *PINITCOMMONCONTROLS)(VOID);
889 PINITCOMMONCONTROLS pInitCommonControls;
890 HINSTANCE hComCtl32;
891
892 hComCtl32 = LoadLibrary(L"comctl32.dll");
893 if (hComCtl32 != NULL)
894 {
895 /* initialize the common controls */
896 pInitCommonControls = (PINITCOMMONCONTROLS)GetProcAddress(hComCtl32,
897 "InitCommonControls");
898 if (pInitCommonControls == NULL)
899 {
900 FreeLibrary(hComCtl32);
901 return NULL;
902 }
903
904 pInitCommonControls();
905 }
906
907 return hComCtl32;
908 }
909
910
911 BOOL
912 STDCALL
913 DllMain(IN HINSTANCE hinstDLL,
914 IN DWORD dwReason,
915 IN LPVOID lpvReserved)
916 {
917 switch (dwReason)
918 {
919 case DLL_PROCESS_ATTACH:
920 DisableThreadLibraryCalls(hinstDLL);
921 hDllInstance = hinstDLL;
922 break;
923 }
924
925 return TRUE;
926 }