2 * SetupAPI device class-related functions
4 * Copyright 2000 Andreas Mohr for CodeWeavers
5 * 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "setupapi_private.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(setupapi
);
26 /* Unicode constants */
27 static const WCHAR BackSlash
[] = {'\\',0};
28 static const WCHAR Class
[] = {'C','l','a','s','s',0};
29 static const WCHAR ClassGUID
[] = {'C','l','a','s','s','G','U','I','D',0};
30 static const WCHAR ClassInstall32
[] = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
31 static const WCHAR DotServices
[] = {'.','S','e','r','v','i','c','e','s',0};
32 static const WCHAR InterfaceInstall32
[] = {'I','n','t','e','r','f','a','c','e','I','n','s','t','a','l','l','3','2',0};
33 static const WCHAR Version
[] = {'V','e','r','s','i','o','n',0};
36 (WINAPI
* PROPERTY_PAGE_PROVIDER
) (
37 IN PSP_PROPSHEETPAGE_REQUEST PropPageRequest
,
38 IN LPFNADDPROPSHEETPAGE fAddFunc
,
41 (*UPDATE_CLASS_PARAM_HANDLER
) (
42 IN HDEVINFO DeviceInfoSet
,
43 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
44 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
45 IN DWORD ClassInstallParamsSize
);
48 SETUP_PropertyChangeHandler(
49 IN HDEVINFO DeviceInfoSet
,
50 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
51 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
52 IN DWORD ClassInstallParamsSize
);
54 static const UPDATE_CLASS_PARAM_HANDLER UpdateClassInstallParamHandlers
[] = {
55 NULL
, /* DIF_SELECTDEVICE */
56 NULL
, /* DIF_INSTALLDEVICE */
57 NULL
, /* DIF_ASSIGNRESOURCES */
58 NULL
, /* DIF_PROPERTIES */
59 NULL
, /* DIF_REMOVE */
60 NULL
, /* DIF_FIRSTTIMESETUP */
61 NULL
, /* DIF_FOUNDDEVICE */
62 NULL
, /* DIF_SELECTCLASSDRIVERS */
63 NULL
, /* DIF_VALIDATECLASSDRIVERS */
64 NULL
, /* DIF_INSTALLCLASSDRIVERS */
65 NULL
, /* DIF_CALCDISKSPACE */
66 NULL
, /* DIF_DESTROYPRIVATEDATA */
67 NULL
, /* DIF_VALIDATEDRIVER */
68 NULL
, /* DIF_MOVEDEVICE */
69 NULL
, /* DIF_DETECT */
70 NULL
, /* DIF_INSTALLWIZARD */
71 NULL
, /* DIF_DESTROYWIZARDDATA */
72 SETUP_PropertyChangeHandler
, /* DIF_PROPERTYCHANGE */
73 NULL
, /* DIF_ENABLECLASS */
74 NULL
, /* DIF_DETECTVERIFY */
75 NULL
, /* DIF_INSTALLDEVICEFILES */
76 NULL
, /* DIF_UNREMOVE */
77 NULL
, /* DIF_SELECTBESTCOMPATDRV */
78 NULL
, /* DIF_ALLOW_INSTALL */
79 NULL
, /* DIF_REGISTERDEVICE */
80 NULL
, /* DIF_NEWDEVICEWIZARD_PRESELECT */
81 NULL
, /* DIF_NEWDEVICEWIZARD_SELECT */
82 NULL
, /* DIF_NEWDEVICEWIZARD_PREANALYZE */
83 NULL
, /* DIF_NEWDEVICEWIZARD_POSTANALYZE */
84 NULL
, /* DIF_NEWDEVICEWIZARD_FINISHINSTALL */
85 NULL
, /* DIF_UNUSED1 */
86 NULL
, /* DIF_INSTALLINTERFACES */
87 NULL
, /* DIF_DETECTCANCEL */
88 NULL
, /* DIF_REGISTER_COINSTALLERS */
89 NULL
, /* DIF_ADDPROPERTYPAGE_ADVANCED */
90 NULL
, /* DIF_ADDPROPERTYPAGE_BASIC */
91 NULL
, /* DIF_RESERVED1 */
92 NULL
, /* DIF_TROUBLESHOOTER */
93 NULL
, /* DIF_POWERMESSAGEWAKE */
94 NULL
, /* DIF_ADDREMOTEPROPERTYPAGE_ADVANCED */
95 NULL
, /* DIF_UPDATEDRIVER_UI */
96 NULL
/* DIF_RESERVED2 */
100 /***********************************************************************
101 * SetupDiBuildClassInfoList (SETUPAPI.@)
103 * Returns a list of setup class GUIDs that identify the classes
104 * that are installed on a local machine.
107 * Flags [I] control exclusion of classes from the list.
108 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
109 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
110 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
117 SetupDiBuildClassInfoList(
119 OUT LPGUID ClassGuidList OPTIONAL
,
120 IN DWORD ClassGuidListSize
,
121 OUT PDWORD RequiredSize
)
124 return SetupDiBuildClassInfoListExW(Flags
, ClassGuidList
,
125 ClassGuidListSize
, RequiredSize
,
129 /***********************************************************************
130 * SetupDiBuildClassInfoListExA (SETUPAPI.@)
132 * Returns a list of setup class GUIDs that identify the classes
133 * that are installed on a local or remote macine.
136 * Flags [I] control exclusion of classes from the list.
137 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
138 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
139 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
140 * MachineName [I] name of a remote machine.
141 * Reserved [I] must be NULL.
148 SetupDiBuildClassInfoListExA(
150 OUT LPGUID ClassGuidList OPTIONAL
,
151 IN DWORD ClassGuidListSize
,
152 OUT PDWORD RequiredSize
,
153 IN PCSTR MachineName OPTIONAL
,
156 LPWSTR MachineNameW
= NULL
;
159 TRACE("0x%lx %p %lu %p %s %p\n", Flags
, ClassGuidList
,
160 ClassGuidListSize
, RequiredSize
, debugstr_a(MachineName
), Reserved
);
164 MachineNameW
= MultiByteToUnicode(MachineName
, CP_ACP
);
165 if (MachineNameW
== NULL
) return FALSE
;
168 bResult
= SetupDiBuildClassInfoListExW(Flags
, ClassGuidList
,
169 ClassGuidListSize
, RequiredSize
,
170 MachineNameW
, Reserved
);
172 MyFree(MachineNameW
);
177 /***********************************************************************
178 * SetupDiBuildClassInfoListExW (SETUPAPI.@)
180 * Returns a list of setup class GUIDs that identify the classes
181 * that are installed on a local or remote macine.
184 * Flags [I] control exclusion of classes from the list.
185 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
186 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
187 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
188 * MachineName [I] name of a remote machine.
189 * Reserved [I] must be NULL.
196 SetupDiBuildClassInfoListExW(
198 OUT LPGUID ClassGuidList OPTIONAL
,
199 IN DWORD ClassGuidListSize
,
200 OUT PDWORD RequiredSize
,
201 IN PCWSTR MachineName OPTIONAL
,
204 WCHAR szKeyName
[MAX_GUID_STRING_LEN
+ 1];
205 HKEY hClassesKey
= INVALID_HANDLE_VALUE
;
206 HKEY hClassKey
= NULL
;
210 DWORD dwGuidListIndex
= 0;
213 TRACE("0x%lx %p %lu %p %s %p\n", Flags
, ClassGuidList
,
214 ClassGuidListSize
, RequiredSize
, debugstr_w(MachineName
), Reserved
);
218 SetLastError(ERROR_INVALID_PARAMETER
);
221 else if (!ClassGuidList
&& ClassGuidListSize
> 0)
223 SetLastError(ERROR_INVALID_PARAMETER
);
227 hClassesKey
= SetupDiOpenClassRegKeyExW(NULL
,
228 KEY_ENUMERATE_SUB_KEYS
,
232 if (hClassesKey
== INVALID_HANDLE_VALUE
)
235 for (dwIndex
= 0; ; dwIndex
++)
237 dwLength
= MAX_GUID_STRING_LEN
+ 1;
238 lError
= RegEnumKeyExW(hClassesKey
,
246 if (lError
== ERROR_SUCCESS
|| lError
== ERROR_MORE_DATA
)
248 TRACE("Key name: %s\n", debugstr_w(szKeyName
));
250 if (hClassKey
!= NULL
)
251 RegCloseKey(hClassKey
);
252 if (RegOpenKeyExW(hClassesKey
,
256 &hClassKey
) != ERROR_SUCCESS
)
261 if (RegQueryValueExW(hClassKey
,
262 REGSTR_VAL_NOUSECLASS
,
266 NULL
) == ERROR_SUCCESS
)
268 TRACE("'NoUseClass' value found!\n");
272 if ((Flags
& DIBCI_NOINSTALLCLASS
) &&
273 (!RegQueryValueExW(hClassKey
,
274 REGSTR_VAL_NOINSTALLCLASS
,
280 TRACE("'NoInstallClass' value found!\n");
284 if ((Flags
& DIBCI_NODISPLAYCLASS
) &&
285 (!RegQueryValueExW(hClassKey
,
286 REGSTR_VAL_NODISPLAYCLASS
,
292 TRACE("'NoDisplayClass' value found!\n");
296 TRACE("Guid: %s\n", debugstr_w(szKeyName
));
297 if (dwGuidListIndex
< ClassGuidListSize
)
299 if (szKeyName
[0] == L
'{' && szKeyName
[37] == L
'}')
302 UuidFromStringW(&szKeyName
[1],
303 &ClassGuidList
[dwGuidListIndex
]);
309 TRACE("RegEnumKeyExW() returns 0x%lx\n", lError
);
311 if (lError
!= ERROR_SUCCESS
)
315 if (RequiredSize
!= NULL
)
316 *RequiredSize
= dwGuidListIndex
;
318 if (ClassGuidListSize
< dwGuidListIndex
)
319 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
324 if (hClassesKey
!= INVALID_HANDLE_VALUE
)
325 RegCloseKey(hClassesKey
);
326 if (hClassKey
!= NULL
)
327 RegCloseKey(hClassKey
);
331 /***********************************************************************
332 * SetupDiClassGuidsFromNameA (SETUPAPI.@)
335 SetupDiClassGuidsFromNameA(
337 OUT LPGUID ClassGuidList
,
338 IN DWORD ClassGuidListSize
,
339 OUT PDWORD RequiredSize
)
341 return SetupDiClassGuidsFromNameExA(ClassName
, ClassGuidList
,
342 ClassGuidListSize
, RequiredSize
,
346 /***********************************************************************
347 * SetupDiClassGuidsFromNameW (SETUPAPI.@)
349 BOOL WINAPI
SetupDiClassGuidsFromNameW(
351 OUT LPGUID ClassGuidList
,
352 IN DWORD ClassGuidListSize
,
353 OUT PDWORD RequiredSize
)
355 return SetupDiClassGuidsFromNameExW(ClassName
, ClassGuidList
,
356 ClassGuidListSize
, RequiredSize
,
360 /***********************************************************************
361 * SetupDiClassGuidsFromNameExA (SETUPAPI.@)
364 SetupDiClassGuidsFromNameExA(
366 OUT LPGUID ClassGuidList
,
367 IN DWORD ClassGuidListSize
,
368 OUT PDWORD RequiredSize
,
369 IN PCSTR MachineName OPTIONAL
,
372 LPWSTR ClassNameW
= NULL
;
373 LPWSTR MachineNameW
= NULL
;
374 BOOL bResult
= FALSE
;
376 TRACE("%s %p %lu %p %s %p\n", debugstr_a(ClassName
), ClassGuidList
,
377 ClassGuidListSize
, RequiredSize
, debugstr_a(MachineName
), Reserved
);
381 SetLastError(ERROR_INVALID_PARAMETER
);
385 ClassNameW
= MultiByteToUnicode(ClassName
, CP_ACP
);
386 if (ClassNameW
== NULL
)
391 MachineNameW
= MultiByteToUnicode(MachineName
, CP_ACP
);
392 if (MachineNameW
== NULL
)
396 bResult
= SetupDiClassGuidsFromNameExW(ClassNameW
, ClassGuidList
,
397 ClassGuidListSize
, RequiredSize
,
398 MachineNameW
, Reserved
);
401 MyFree(MachineNameW
);
407 /***********************************************************************
408 * SetupDiClassGuidsFromNameExW (SETUPAPI.@)
411 SetupDiClassGuidsFromNameExW(
413 OUT LPGUID ClassGuidList
,
414 IN DWORD ClassGuidListSize
,
415 OUT PDWORD RequiredSize
,
416 IN PCWSTR MachineName OPTIONAL
,
419 WCHAR szKeyName
[MAX_GUID_STRING_LEN
+ 1];
420 WCHAR szClassName
[MAX_CLASS_NAME_LEN
];
421 HKEY hClassesKey
= INVALID_HANDLE_VALUE
;
422 HKEY hClassKey
= NULL
;
426 DWORD dwGuidListIndex
= 0;
429 TRACE("%s %p %lu %p %s %p\n", debugstr_w(ClassName
), ClassGuidList
,
430 ClassGuidListSize
, RequiredSize
, debugstr_w(MachineName
), Reserved
);
432 if (!ClassName
|| !RequiredSize
)
434 SetLastError(ERROR_INVALID_PARAMETER
);
437 else if (!ClassGuidList
&& ClassGuidListSize
> 0)
439 SetLastError(ERROR_INVALID_PARAMETER
);
444 hClassesKey
= SetupDiOpenClassRegKeyExW(NULL
,
445 KEY_ENUMERATE_SUB_KEYS
,
449 if (hClassesKey
== INVALID_HANDLE_VALUE
)
452 for (dwIndex
= 0; ; dwIndex
++)
454 dwLength
= MAX_GUID_STRING_LEN
+ 1;
455 lError
= RegEnumKeyExW(hClassesKey
,
463 if (lError
== ERROR_SUCCESS
|| lError
== ERROR_MORE_DATA
)
465 TRACE("Key name: %s\n", debugstr_w(szKeyName
));
467 if (hClassKey
!= NULL
)
468 RegCloseKey(hClassKey
);
469 if (RegOpenKeyExW(hClassesKey
,
473 &hClassKey
) != ERROR_SUCCESS
)
478 dwLength
= MAX_CLASS_NAME_LEN
* sizeof(WCHAR
);
479 if (RegQueryValueExW(hClassKey
,
484 &dwLength
) == ERROR_SUCCESS
)
486 TRACE("Class name: %s\n", debugstr_w(szClassName
));
488 if (strcmpiW(szClassName
, ClassName
) == 0)
490 TRACE("Found matching class name\n");
492 TRACE("Guid: %s\n", debugstr_w(szKeyName
));
493 if (dwGuidListIndex
< ClassGuidListSize
)
495 if (szKeyName
[0] == L
'{' && szKeyName
[37] == L
'}')
498 UuidFromStringW(&szKeyName
[1],
499 &ClassGuidList
[dwGuidListIndex
]);
507 TRACE("RegEnumKeyExW() returns 0x%lx\n", lError
);
509 if (lError
!= ERROR_SUCCESS
)
513 if (RequiredSize
!= NULL
)
514 *RequiredSize
= dwGuidListIndex
;
516 if (ClassGuidListSize
< dwGuidListIndex
)
517 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
522 if (hClassesKey
!= INVALID_HANDLE_VALUE
)
523 RegCloseKey(hClassesKey
);
524 if (hClassKey
!= NULL
)
525 RegCloseKey(hClassKey
);
529 /***********************************************************************
530 * SetupDiClassNameFromGuidA (SETUPAPI.@)
533 SetupDiClassNameFromGuidA(
534 IN CONST GUID
* ClassGuid
,
536 IN DWORD ClassNameSize
,
537 OUT PDWORD RequiredSize OPTIONAL
)
539 return SetupDiClassNameFromGuidExA(ClassGuid
, ClassName
,
540 ClassNameSize
, RequiredSize
,
544 /***********************************************************************
545 * SetupDiClassNameFromGuidW (SETUPAPI.@)
548 SetupDiClassNameFromGuidW(
549 IN CONST GUID
* ClassGuid
,
551 IN DWORD ClassNameSize
,
552 OUT PDWORD RequiredSize OPTIONAL
)
554 return SetupDiClassNameFromGuidExW(ClassGuid
, ClassName
,
555 ClassNameSize
, RequiredSize
,
559 /***********************************************************************
560 * SetupDiClassNameFromGuidExA (SETUPAPI.@)
563 SetupDiClassNameFromGuidExA(
564 IN CONST GUID
* ClassGuid
,
566 IN DWORD ClassNameSize
,
567 OUT PDWORD RequiredSize OPTIONAL
,
568 IN PCSTR MachineName OPTIONAL
,
571 WCHAR ClassNameW
[MAX_CLASS_NAME_LEN
];
572 LPWSTR MachineNameW
= NULL
;
576 MachineNameW
= MultiByteToUnicode(MachineName
, CP_ACP
);
577 ret
= SetupDiClassNameFromGuidExW(ClassGuid
, ClassNameW
, MAX_CLASS_NAME_LEN
,
578 RequiredSize
, MachineNameW
, Reserved
);
581 int len
= WideCharToMultiByte(CP_ACP
, 0, ClassNameW
, -1, ClassName
,
582 ClassNameSize
, NULL
, NULL
);
583 if (len
> ClassNameSize
)
585 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
589 MyFree(MachineNameW
);
593 /***********************************************************************
594 * SetupDiClassNameFromGuidExW (SETUPAPI.@)
597 SetupDiClassNameFromGuidExW(
598 IN CONST GUID
* ClassGuid
,
600 IN DWORD ClassNameSize
,
601 OUT PDWORD RequiredSize OPTIONAL
,
602 IN PCWSTR MachineName OPTIONAL
,
605 HKEY hKey
= INVALID_HANDLE_VALUE
;
606 DWORD dwLength
, dwRegType
;
610 TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid
), ClassName
,
611 ClassNameSize
, RequiredSize
, debugstr_w(MachineName
), Reserved
);
615 SetLastError(ERROR_INVALID_CLASS
);
618 else if (!ClassName
&& ClassNameSize
> 0)
620 SetLastError(ERROR_INVALID_PARAMETER
);
624 hKey
= SetupDiOpenClassRegKeyExW(ClassGuid
,
629 if (hKey
== INVALID_HANDLE_VALUE
)
632 if (ClassNameSize
< sizeof(UNICODE_NULL
) || !ClassName
)
635 dwLength
= ClassNameSize
* sizeof(WCHAR
) - sizeof(UNICODE_NULL
);
637 rc
= RegQueryValueExW(hKey
,
643 if (rc
!= ERROR_MORE_DATA
&& rc
!= ERROR_SUCCESS
)
648 else if (dwRegType
!= REG_SZ
)
650 SetLastError(ERROR_GEN_FAILURE
);
655 *RequiredSize
= dwLength
/ sizeof(WCHAR
) + 1;
657 if (ClassNameSize
* sizeof(WCHAR
) >= dwLength
+ sizeof(UNICODE_STRING
))
659 if (ClassNameSize
> sizeof(UNICODE_NULL
))
660 ClassName
[ClassNameSize
/ sizeof(WCHAR
)] = UNICODE_NULL
;
664 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
667 if (hKey
!= INVALID_HANDLE_VALUE
)
672 /***********************************************************************
673 * SetupDiDestroyClassImageList(SETUPAPI.@)
676 SetupDiDestroyClassImageList(
677 IN PSP_CLASSIMAGELIST_DATA ClassImageListData
)
679 struct ClassImageList
*list
;
682 TRACE("%p\n", ClassImageListData
);
684 if (!ClassImageListData
)
685 SetLastError(ERROR_INVALID_PARAMETER
);
686 else if (ClassImageListData
->cbSize
!= sizeof(SP_CLASSIMAGELIST_DATA
))
687 SetLastError(ERROR_INVALID_USER_BUFFER
);
688 else if ((list
= (struct ClassImageList
*)ClassImageListData
->Reserved
) == NULL
)
689 SetLastError(ERROR_INVALID_USER_BUFFER
);
690 else if (list
->magic
!= SETUP_CLASS_IMAGE_LIST_MAGIC
)
691 SetLastError(ERROR_INVALID_USER_BUFFER
);
695 //ImageList_Destroy();
696 FIXME("Stub %p\n", ClassImageListData
);
697 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
700 TRACE("Returning %d\n", ret
);
704 /***********************************************************************
705 * SetupDiGetClassDescriptionA (SETUPAPI.@)
708 SetupDiGetClassDescriptionA(
709 IN CONST GUID
*ClassGuid
,
710 OUT PSTR ClassDescription
,
711 IN DWORD ClassDescriptionSize
,
712 OUT PDWORD RequiredSize OPTIONAL
)
714 return SetupDiGetClassDescriptionExA(ClassGuid
, ClassDescription
,
715 ClassDescriptionSize
,
716 RequiredSize
, NULL
, NULL
);
719 /***********************************************************************
720 * SetupDiGetClassDescriptionW (SETUPAPI.@)
723 SetupDiGetClassDescriptionW(
724 IN CONST GUID
*ClassGuid
,
725 OUT PWSTR ClassDescription
,
726 IN DWORD ClassDescriptionSize
,
727 OUT PDWORD RequiredSize OPTIONAL
)
729 return SetupDiGetClassDescriptionExW(ClassGuid
, ClassDescription
,
730 ClassDescriptionSize
,
731 RequiredSize
, NULL
, NULL
);
734 /***********************************************************************
735 * SetupDiGetClassDescriptionExA (SETUPAPI.@)
738 SetupDiGetClassDescriptionExA(
739 IN CONST GUID
*ClassGuid
,
740 OUT PSTR ClassDescription
,
741 IN DWORD ClassDescriptionSize
,
742 OUT PDWORD RequiredSize OPTIONAL
,
743 IN PCSTR MachineName OPTIONAL
,
746 PWCHAR ClassDescriptionW
= NULL
;
747 LPWSTR MachineNameW
= NULL
;
750 TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid
), ClassDescription
,
751 ClassDescriptionSize
, RequiredSize
, debugstr_a(MachineName
), Reserved
);
753 if (ClassDescriptionSize
> 0)
755 ClassDescriptionW
= MyMalloc(ClassDescriptionSize
* sizeof(WCHAR
));
756 if (!ClassDescriptionW
)
758 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
765 MachineNameW
= MultiByteToUnicode(MachineName
, CP_ACP
);
768 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
773 ret
= SetupDiGetClassDescriptionExW(ClassGuid
, ClassDescriptionW
,
774 ClassDescriptionSize
* sizeof(WCHAR
), RequiredSize
, MachineNameW
, Reserved
);
777 int len
= WideCharToMultiByte(CP_ACP
, 0, ClassDescriptionW
, -1, ClassDescription
,
778 ClassDescriptionSize
, NULL
, NULL
);
779 if (len
> ClassDescriptionSize
)
781 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
787 MyFree(ClassDescriptionW
);
788 MyFree(MachineNameW
);
792 /***********************************************************************
793 * SetupDiGetClassDescriptionExW (SETUPAPI.@)
796 SetupDiGetClassDescriptionExW(
797 IN CONST GUID
*ClassGuid
,
798 OUT PWSTR ClassDescription
,
799 IN DWORD ClassDescriptionSize
,
800 OUT PDWORD RequiredSize OPTIONAL
,
801 IN PCWSTR MachineName OPTIONAL
,
804 HKEY hKey
= INVALID_HANDLE_VALUE
;
805 DWORD dwLength
, dwRegType
;
809 TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid
), ClassDescription
,
810 ClassDescriptionSize
, RequiredSize
, debugstr_w(MachineName
), Reserved
);
814 SetLastError(ERROR_INVALID_PARAMETER
);
817 else if (!ClassDescription
&& ClassDescriptionSize
> 0)
819 SetLastError(ERROR_INVALID_PARAMETER
);
823 hKey
= SetupDiOpenClassRegKeyExW(ClassGuid
,
828 if (hKey
== INVALID_HANDLE_VALUE
)
830 WARN("SetupDiOpenClassRegKeyExW() failed (Error %lu)\n", GetLastError());
834 if (ClassDescriptionSize
< sizeof(UNICODE_NULL
) || !ClassDescription
)
837 dwLength
= ClassDescriptionSize
* sizeof(WCHAR
) - sizeof(UNICODE_NULL
);
839 rc
= RegQueryValueExW(hKey
,
843 (LPBYTE
)ClassDescription
,
845 if (rc
!= ERROR_MORE_DATA
&& rc
!= ERROR_SUCCESS
)
850 else if (dwRegType
!= REG_SZ
)
852 SetLastError(ERROR_GEN_FAILURE
);
857 *RequiredSize
= dwLength
/ sizeof(WCHAR
) + 1;
859 if (ClassDescriptionSize
* sizeof(WCHAR
) >= dwLength
+ sizeof(UNICODE_STRING
))
861 if (ClassDescriptionSize
> sizeof(UNICODE_NULL
))
862 ClassDescription
[ClassDescriptionSize
/ sizeof(WCHAR
)] = UNICODE_NULL
;
866 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
869 if (hKey
!= INVALID_HANDLE_VALUE
)
874 /***********************************************************************
875 * SetupDiGetClassDevsA (SETUPAPI.@)
878 SetupDiGetClassDevsA(
879 IN CONST GUID
*ClassGuid OPTIONAL
,
880 IN PCSTR Enumerator OPTIONAL
,
881 IN HWND hwndParent OPTIONAL
,
884 return SetupDiGetClassDevsExA(ClassGuid
, Enumerator
, hwndParent
,
885 Flags
, NULL
, NULL
, NULL
);
888 /***********************************************************************
889 * SetupDiGetClassDevsW (SETUPAPI.@)
892 SetupDiGetClassDevsW(
893 IN CONST GUID
*ClassGuid OPTIONAL
,
894 IN PCWSTR Enumerator OPTIONAL
,
895 IN HWND hwndParent OPTIONAL
,
898 return SetupDiGetClassDevsExW(ClassGuid
, Enumerator
, hwndParent
,
899 Flags
, NULL
, NULL
, NULL
);
902 /***********************************************************************
903 * SetupDiGetClassDevsExA (SETUPAPI.@)
906 SetupDiGetClassDevsExA(
907 IN CONST GUID
*ClassGuid OPTIONAL
,
908 IN PCSTR Enumerator OPTIONAL
,
909 IN HWND hwndParent OPTIONAL
,
911 IN HDEVINFO DeviceInfoSet OPTIONAL
,
912 IN PCSTR MachineName OPTIONAL
,
915 LPWSTR EnumeratorW
= NULL
;
916 LPWSTR MachineNameW
= NULL
;
917 HDEVINFO ret
= (HDEVINFO
)INVALID_HANDLE_VALUE
;
921 EnumeratorW
= MultiByteToUnicode(Enumerator
, CP_ACP
);
927 MachineNameW
= MultiByteToUnicode(MachineName
, CP_ACP
);
931 ret
= SetupDiGetClassDevsExW(ClassGuid
, EnumeratorW
, hwndParent
,
932 Flags
, DeviceInfoSet
, MachineNameW
, Reserved
);
936 MyFree(MachineNameW
);
940 /***********************************************************************
941 * SETUP_CreateDevicesListFromEnumerator
944 * list [IO] Device info set to fill with discovered devices.
945 * pClassGuid [I] If specified, only devices which belong to this class will be added.
946 * Enumerator [I] Location to search devices to add.
947 * hEnumeratorKey [I] Registry key corresponding to Enumerator key. Must have KEY_ENUMERATE_SUB_KEYS right.
950 * Success: ERROR_SUCCESS.
951 * Failure: an error code.
954 SETUP_CreateDevicesListFromEnumerator(
955 IN OUT
struct DeviceInfoSet
*list
,
956 IN CONST GUID
*pClassGuid OPTIONAL
,
957 IN LPCWSTR Enumerator
,
958 IN HKEY hEnumeratorKey
) /* handle to Enumerator registry key */
960 HKEY hDeviceIdKey
= NULL
, hInstanceIdKey
;
961 WCHAR KeyBuffer
[MAX_PATH
];
962 WCHAR InstancePath
[MAX_PATH
];
963 LPWSTR pEndOfInstancePath
; /* Pointer into InstancePath buffer */
964 struct DeviceInfoElement
*deviceInfo
;
966 DWORD dwLength
, dwRegType
;
969 /* Enumerate device IDs (subkeys of hEnumeratorKey) */
972 dwLength
= sizeof(KeyBuffer
) / sizeof(KeyBuffer
[0]);
973 rc
= RegEnumKeyExW(hEnumeratorKey
, i
, KeyBuffer
, &dwLength
, NULL
, NULL
, NULL
, NULL
);
974 if (rc
== ERROR_NO_MORE_ITEMS
)
976 if (rc
!= ERROR_SUCCESS
)
980 /* Open device id sub key */
981 if (hDeviceIdKey
!= NULL
)
982 RegCloseKey(hDeviceIdKey
);
983 rc
= RegOpenKeyExW(hEnumeratorKey
, KeyBuffer
, 0, KEY_ENUMERATE_SUB_KEYS
, &hDeviceIdKey
);
984 if (rc
!= ERROR_SUCCESS
)
986 strcpyW(InstancePath
, Enumerator
);
987 strcatW(InstancePath
, BackSlash
);
988 strcatW(InstancePath
, KeyBuffer
);
989 strcatW(InstancePath
, BackSlash
);
990 pEndOfInstancePath
= &InstancePath
[strlenW(InstancePath
)];
992 /* Enumerate instance IDs (subkeys of hDeviceIdKey) */
998 dwLength
= sizeof(KeyBuffer
) / sizeof(KeyBuffer
[0]);
999 rc
= RegEnumKeyExW(hDeviceIdKey
, j
, KeyBuffer
, &dwLength
, NULL
, NULL
, NULL
, NULL
);
1000 if (rc
== ERROR_NO_MORE_ITEMS
)
1002 if (rc
!= ERROR_SUCCESS
)
1006 /* Open instance id sub key */
1007 rc
= RegOpenKeyExW(hDeviceIdKey
, KeyBuffer
, 0, KEY_QUERY_VALUE
, &hInstanceIdKey
);
1008 if (rc
!= ERROR_SUCCESS
)
1010 *pEndOfInstancePath
= '\0';
1011 strcatW(InstancePath
, KeyBuffer
);
1013 /* Read ClassGUID value */
1014 dwLength
= sizeof(KeyBuffer
) - sizeof(WCHAR
);
1015 rc
= RegQueryValueExW(hInstanceIdKey
, ClassGUID
, NULL
, &dwRegType
, (LPBYTE
)KeyBuffer
, &dwLength
);
1016 RegCloseKey(hInstanceIdKey
);
1017 if (rc
== ERROR_FILE_NOT_FOUND
)
1020 /* Skip this bad entry as we can't verify it */
1022 /* Set a default GUID for this device */
1023 memcpy(&KeyGuid
, &GUID_NULL
, sizeof(GUID
));
1025 else if (rc
!= ERROR_SUCCESS
)
1029 else if (dwRegType
!= REG_SZ
|| dwLength
< MAX_GUID_STRING_LEN
* sizeof(WCHAR
))
1031 rc
= ERROR_GEN_FAILURE
;
1036 KeyBuffer
[MAX_GUID_STRING_LEN
- 2] = '\0'; /* Replace the } by a NULL character */
1037 if (UuidFromStringW(&KeyBuffer
[1], &KeyGuid
) != RPC_S_OK
)
1038 /* Bad GUID, skip the entry */
1042 if (pClassGuid
&& !IsEqualIID(&KeyGuid
, pClassGuid
))
1044 /* Skip this entry as it is not the right device class */
1048 /* Add the entry to the list */
1049 if (!CreateDeviceInfoElement(list
, InstancePath
, &KeyGuid
, &deviceInfo
))
1051 rc
= GetLastError();
1054 TRACE("Adding '%s' to device info set %p\n", debugstr_w(InstancePath
), list
);
1055 InsertTailList(&list
->ListHead
, &deviceInfo
->ListEntry
);
1062 if (hDeviceIdKey
!= NULL
)
1063 RegCloseKey(hDeviceIdKey
);
1068 SETUP_CreateDevicesList(
1069 IN OUT
struct DeviceInfoSet
*list
,
1070 IN PCWSTR MachineName OPTIONAL
,
1071 IN CONST GUID
*Class OPTIONAL
,
1072 IN PCWSTR Enumerator OPTIONAL
)
1074 HKEY HKLM
= HKEY_LOCAL_MACHINE
;
1075 HKEY hEnumKey
= NULL
;
1076 HKEY hEnumeratorKey
= NULL
;
1077 WCHAR KeyBuffer
[MAX_PATH
];
1082 if (Class
&& IsEqualIID(Class
, &GUID_NULL
))
1085 /* Open Enum key (if applicable) */
1086 if (MachineName
!= NULL
)
1088 rc
= RegConnectRegistryW(MachineName
, HKEY_LOCAL_MACHINE
, &HKLM
);
1089 if (rc
!= ERROR_SUCCESS
)
1095 REGSTR_PATH_SYSTEMENUM
,
1097 KEY_ENUMERATE_SUB_KEYS
,
1099 if (rc
!= ERROR_SUCCESS
)
1102 /* If enumerator is provided, call directly SETUP_CreateDevicesListFromEnumerator.
1103 * Else, enumerate all enumerators and call SETUP_CreateDevicesListFromEnumerator
1112 KEY_ENUMERATE_SUB_KEYS
,
1114 if (rc
!= ERROR_SUCCESS
)
1116 if (rc
== ERROR_FILE_NOT_FOUND
)
1117 rc
= ERROR_INVALID_DATA
;
1120 rc
= SETUP_CreateDevicesListFromEnumerator(list
, Class
, Enumerator
, hEnumeratorKey
);
1124 /* Enumerate enumerators */
1128 dwLength
= sizeof(KeyBuffer
) / sizeof(KeyBuffer
[0]);
1129 rc
= RegEnumKeyExW(hEnumKey
, i
, KeyBuffer
, &dwLength
, NULL
, NULL
, NULL
, NULL
);
1130 if (rc
== ERROR_NO_MORE_ITEMS
)
1132 else if (rc
!= ERROR_SUCCESS
)
1137 if (hEnumeratorKey
!= NULL
)
1138 RegCloseKey(hEnumeratorKey
);
1139 rc
= RegOpenKeyExW(hEnumKey
, KeyBuffer
, 0, KEY_ENUMERATE_SUB_KEYS
, &hEnumeratorKey
);
1140 if (rc
!= ERROR_SUCCESS
)
1143 /* Call SETUP_CreateDevicesListFromEnumerator */
1144 rc
= SETUP_CreateDevicesListFromEnumerator(list
, Class
, KeyBuffer
, hEnumeratorKey
);
1145 if (rc
!= ERROR_SUCCESS
)
1152 if (HKLM
!= HKEY_LOCAL_MACHINE
)
1154 if (hEnumKey
!= NULL
)
1155 RegCloseKey(hEnumKey
);
1156 if (hEnumeratorKey
!= NULL
)
1157 RegCloseKey(hEnumeratorKey
);
1161 /***********************************************************************
1162 * SetupDiGetClassDevsExW (SETUPAPI.@)
1165 SetupDiGetClassDevsExW(
1166 IN CONST GUID
*ClassGuid OPTIONAL
,
1167 IN PCWSTR Enumerator OPTIONAL
,
1168 IN HWND hwndParent OPTIONAL
,
1170 IN HDEVINFO DeviceInfoSet OPTIONAL
,
1171 IN PCWSTR MachineName OPTIONAL
,
1174 HDEVINFO hDeviceInfo
= INVALID_HANDLE_VALUE
;
1175 struct DeviceInfoSet
*list
;
1176 CONST GUID
*pClassGuid
;
1178 HDEVINFO ret
= INVALID_HANDLE_VALUE
;
1180 TRACE("%s %s %p 0x%08lx %p %s %p\n", debugstr_guid(ClassGuid
), debugstr_w(Enumerator
),
1181 hwndParent
, Flags
, DeviceInfoSet
, debugstr_w(MachineName
), Reserved
);
1183 /* Create the deviceset if not set */
1186 list
= (struct DeviceInfoSet
*)DeviceInfoSet
;
1187 if (list
->magic
!= SETUP_DEV_INFO_SET_MAGIC
)
1189 SetLastError(ERROR_INVALID_HANDLE
);
1192 hDeviceInfo
= DeviceInfoSet
;
1196 hDeviceInfo
= SetupDiCreateDeviceInfoListExW(
1197 Flags
& (DIGCF_DEVICEINTERFACE
| DIGCF_ALLCLASSES
) ? NULL
: ClassGuid
,
1198 NULL
, MachineName
, NULL
);
1199 if (hDeviceInfo
== INVALID_HANDLE_VALUE
)
1201 list
= (struct DeviceInfoSet
*)hDeviceInfo
;
1204 if (Flags
& DIGCF_PROFILE
)
1205 FIXME(": flag DIGCF_PROFILE ignored\n");
1207 if (Flags
& DIGCF_DEVICEINTERFACE
)
1208 rc
= SETUP_CreateInterfaceList(list
, MachineName
, ClassGuid
, Enumerator
, Flags
& DIGCF_PRESENT
);
1211 /* Determine which class(es) should be included in the deviceset */
1212 if (Flags
& DIGCF_ALLCLASSES
)
1214 /* The caller wants all classes. Check if
1215 * the deviceset limits us to one class */
1216 if (IsEqualIID(&list
->ClassGuid
, &GUID_NULL
))
1219 pClassGuid
= &list
->ClassGuid
;
1223 /* The caller wants one class. Check if it matches deviceset class */
1224 if (IsEqualIID(&list
->ClassGuid
, ClassGuid
)
1225 || IsEqualIID(&list
->ClassGuid
, &GUID_NULL
))
1227 pClassGuid
= ClassGuid
;
1231 SetLastError(ERROR_INVALID_PARAMETER
);
1235 else if (!IsEqualIID(&list
->ClassGuid
, &GUID_NULL
))
1237 /* No class specified. Try to use the one of the deviceset */
1238 if (IsEqualIID(&list
->ClassGuid
, &GUID_NULL
))
1239 pClassGuid
= &list
->ClassGuid
;
1242 SetLastError(ERROR_INVALID_PARAMETER
);
1248 SetLastError(ERROR_INVALID_PARAMETER
);
1251 rc
= SETUP_CreateDevicesList(list
, MachineName
, pClassGuid
, Enumerator
);
1253 if (rc
!= ERROR_SUCCESS
)
1261 if (!DeviceInfoSet
&& hDeviceInfo
!= INVALID_HANDLE_VALUE
&& hDeviceInfo
!= ret
)
1262 SetupDiDestroyDeviceInfoList(hDeviceInfo
);
1266 /***********************************************************************
1267 * SetupDiGetClassImageIndex (SETUPAPI.@)
1272 OUT PINT ImageIndex
)
1274 LPWSTR Buffer
= NULL
;
1275 DWORD dwRegType
, dwLength
;
1279 /* Read icon registry key */
1280 rc
= RegQueryValueExW(hClassKey
, REGSTR_VAL_INSICON
, NULL
, &dwRegType
, NULL
, &dwLength
);
1281 if (rc
!= ERROR_SUCCESS
)
1285 } else if (dwRegType
!= REG_SZ
)
1287 SetLastError(ERROR_INVALID_INDEX
);
1290 Buffer
= MyMalloc(dwLength
+ sizeof(WCHAR
));
1293 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1296 rc
= RegQueryValueExW(hClassKey
, REGSTR_VAL_INSICON
, NULL
, NULL
, (LPBYTE
)Buffer
, &dwLength
);
1297 if (rc
!= ERROR_SUCCESS
)
1302 /* make sure the returned buffer is NULL-terminated */
1303 Buffer
[dwLength
/ sizeof(WCHAR
)] = 0;
1305 /* Transform icon value to a INT */
1306 *ImageIndex
= atoiW(Buffer
);
1315 SetupDiGetClassImageIndex(
1316 IN PSP_CLASSIMAGELIST_DATA ClassImageListData
,
1317 IN CONST GUID
*ClassGuid
,
1318 OUT PINT ImageIndex
)
1320 struct ClassImageList
*list
;
1323 TRACE("%p %s %p\n", ClassImageListData
, debugstr_guid(ClassGuid
), ImageIndex
);
1325 if (!ClassImageListData
|| !ClassGuid
|| !ImageIndex
)
1326 SetLastError(ERROR_INVALID_PARAMETER
);
1327 else if (ClassImageListData
->cbSize
!= sizeof(SP_CLASSIMAGELIST_DATA
))
1328 SetLastError(ERROR_INVALID_USER_BUFFER
);
1329 else if ((list
= (struct ClassImageList
*)ClassImageListData
->Reserved
) == NULL
)
1330 SetLastError(ERROR_INVALID_USER_BUFFER
);
1331 else if (list
->magic
!= SETUP_CLASS_IMAGE_LIST_MAGIC
)
1332 SetLastError(ERROR_INVALID_USER_BUFFER
);
1333 else if (!ImageIndex
)
1334 SetLastError(ERROR_INVALID_PARAMETER
);
1339 for (i
= 0; i
< list
->NumberOfGuids
; i
++)
1341 if (IsEqualIID(ClassGuid
, &list
->Guids
[i
]))
1345 if (i
== list
->NumberOfGuids
|| list
->IconIndexes
[i
] < 0)
1346 SetLastError(ERROR_FILE_NOT_FOUND
);
1349 *ImageIndex
= list
->IconIndexes
[i
];
1354 TRACE("Returning %d\n", ret
);
1358 /***********************************************************************
1359 * SetupDiGetClassImageList(SETUPAPI.@)
1362 SetupDiGetClassImageList(
1363 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData
)
1365 return SetupDiGetClassImageListExW(ClassImageListData
, NULL
, NULL
);
1368 /***********************************************************************
1369 * SetupDiGetClassImageListExA(SETUPAPI.@)
1372 SetupDiGetClassImageListExA(
1373 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData
,
1374 IN PCSTR MachineName OPTIONAL
,
1377 PWSTR MachineNameW
= NULL
;
1382 MachineNameW
= MultiByteToUnicode(MachineName
, CP_ACP
);
1383 if (MachineNameW
== NULL
)
1387 ret
= SetupDiGetClassImageListExW(ClassImageListData
, MachineNameW
, Reserved
);
1389 MyFree(MachineNameW
);
1394 /***********************************************************************
1395 * SetupDiGetClassImageListExW(SETUPAPI.@)
1398 SetupDiGetClassImageListExW(
1399 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData
,
1400 IN PCWSTR MachineName OPTIONAL
,
1405 TRACE("%p %p %p\n", ClassImageListData
, debugstr_w(MachineName
), Reserved
);
1407 if (!ClassImageListData
)
1408 SetLastError(ERROR_INVALID_PARAMETER
);
1409 else if (ClassImageListData
->cbSize
!= sizeof(SP_CLASSIMAGELIST_DATA
))
1410 SetLastError(ERROR_INVALID_USER_BUFFER
);
1412 SetLastError(ERROR_INVALID_PARAMETER
);
1415 struct ClassImageList
*list
= NULL
;
1421 /* Get list of all class GUIDs in given computer */
1422 ret
= SetupDiBuildClassInfoListExW(
1429 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
1432 size
= sizeof(struct ClassImageList
)
1433 + (sizeof(GUID
) + sizeof(INT
)) * RequiredSize
;
1434 list
= HeapAlloc(GetProcessHeap(), 0, size
);
1437 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1440 list
->magic
= SETUP_CLASS_IMAGE_LIST_MAGIC
;
1441 list
->NumberOfGuids
= RequiredSize
;
1442 list
->Guids
= (GUID
*)(list
+ 1);
1443 list
->IconIndexes
= (INT
*)((ULONG_PTR
)(list
+ 1) + sizeof(GUID
) * RequiredSize
);
1445 ret
= SetupDiBuildClassInfoListExW(
1448 list
->NumberOfGuids
,
1454 else if (RequiredSize
!= list
->NumberOfGuids
)
1456 /* Hm. Class list changed since last call. Ignore
1457 * this case as it should be very rare */
1458 SetLastError(ERROR_GEN_FAILURE
);
1463 /* Prepare a HIMAGELIST */
1464 InitCommonControls();
1465 ClassImageListData
->ImageList
= ImageList_Create(16, 16, ILC_COLOR
, 100, 10);
1466 if (!ClassImageListData
->ImageList
)
1469 ClassImageListData
->Reserved
= (ULONG_PTR
)list
;
1471 /* Now, we "simply" need to load icons associated with all class guids,
1472 * and put their index in the image list in the IconIndexes array */
1473 for (i
= 0; i
< list
->NumberOfGuids
; i
++)
1475 ret
= SetupDiLoadClassIcon(
1480 list
->IconIndexes
[i
] = ImageList_AddIcon(ClassImageListData
->ImageList
, hIcon
);
1482 list
->IconIndexes
[i
] = -1; /* Special value to tell that icon is unavailable */
1490 if (ClassImageListData
->Reserved
)
1491 SetupDiDestroyClassImageList(ClassImageListData
);
1497 TRACE("Returning %d\n", ret
);
1501 /***********************************************************************
1502 * SetupDiLoadClassIcon(SETUPAPI.@)
1505 SetupDiLoadClassIcon(
1506 IN CONST GUID
*ClassGuid
,
1507 OUT HICON
*LargeIcon OPTIONAL
,
1508 OUT PINT MiniIconIndex OPTIONAL
)
1513 SetLastError(ERROR_INVALID_PARAMETER
);
1516 LPWSTR Buffer
= NULL
;
1519 HKEY hKey
= INVALID_HANDLE_VALUE
;
1521 hKey
= SetupDiOpenClassRegKey(ClassGuid
, KEY_QUERY_VALUE
);
1522 if (hKey
== INVALID_HANDLE_VALUE
)
1525 if (!SETUP_GetIconIndex(hKey
, &iconIndex
))
1530 /* Look up icon in dll specified by Installer32 or EnumPropPages32 key */
1533 DWORD dwRegType
, dwLength
;
1534 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_INSTALLER_32
, NULL
, &dwRegType
, NULL
, &dwLength
);
1535 if (rc
== ERROR_SUCCESS
&& dwRegType
== REG_SZ
)
1537 Buffer
= MyMalloc(dwLength
+ sizeof(WCHAR
));
1540 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1543 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_INSTALLER_32
, NULL
, NULL
, (LPBYTE
)Buffer
, &dwLength
);
1544 if (rc
!= ERROR_SUCCESS
)
1549 /* make sure the returned buffer is NULL-terminated */
1550 Buffer
[dwLength
/ sizeof(WCHAR
)] = 0;
1553 (ERROR_SUCCESS
== (rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, &dwRegType
, NULL
, &dwLength
))
1554 && dwRegType
== REG_SZ
)
1556 Buffer
= MyMalloc(dwLength
+ sizeof(WCHAR
));
1559 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1562 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, NULL
, (LPBYTE
)Buffer
, &dwLength
);
1563 if (rc
!= ERROR_SUCCESS
)
1568 /* make sure the returned buffer is NULL-terminated */
1569 Buffer
[dwLength
/ sizeof(WCHAR
)] = 0;
1573 /* Unable to find where to load the icon */
1574 SetLastError(ERROR_FILE_NOT_FOUND
);
1577 Comma
= strchrW(Buffer
, ',');
1580 SetLastError(ERROR_GEN_FAILURE
);
1588 /* Look up icon in setupapi.dll */
1589 DllName
= L
"setupapi.dll";
1590 iconIndex
= -iconIndex
;
1593 TRACE("Icon index %d, dll name %s\n", iconIndex
, debugstr_w(DllName
));
1596 if (1 != ExtractIconEx(DllName
, iconIndex
, LargeIcon
, NULL
, 1))
1598 SetLastError(ERROR_INVALID_INDEX
);
1603 *MiniIconIndex
= iconIndex
;
1607 if (hKey
!= INVALID_HANDLE_VALUE
)
1612 TRACE("Returning %d\n", ret
);
1616 /***********************************************************************
1617 * SetupDiInstallClassA (SETUPAPI.@)
1620 SetupDiInstallClassA(
1621 IN HWND hwndParent OPTIONAL
,
1622 IN PCSTR InfFileName
,
1624 IN HSPFILEQ FileQueue OPTIONAL
)
1626 return SetupDiInstallClassExA(hwndParent
, InfFileName
, Flags
, FileQueue
, NULL
, NULL
, NULL
);
1629 /***********************************************************************
1630 * SetupDiInstallClassW (SETUPAPI.@)
1633 SetupDiInstallClassW(
1634 IN HWND hwndParent OPTIONAL
,
1635 IN PCWSTR InfFileName
,
1637 IN HSPFILEQ FileQueue OPTIONAL
)
1639 return SetupDiInstallClassExW(hwndParent
, InfFileName
, Flags
, FileQueue
, NULL
, NULL
, NULL
);
1642 /***********************************************************************
1643 * SetupDiInstallClassExA (SETUPAPI.@)
1646 SetupDiInstallClassExA(
1647 IN HWND hwndParent OPTIONAL
,
1648 IN PCSTR InfFileName OPTIONAL
,
1650 IN HSPFILEQ FileQueue OPTIONAL
,
1651 IN CONST GUID
*InterfaceClassGuid OPTIONAL
,
1655 PWSTR InfFileNameW
= NULL
;
1660 InfFileNameW
= MultiByteToUnicode(InfFileName
, CP_ACP
);
1661 if (InfFileNameW
== NULL
)
1663 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1668 Result
= SetupDiInstallClassExW(hwndParent
, InfFileNameW
, Flags
,
1669 FileQueue
, InterfaceClassGuid
, Reserved1
, Reserved2
);
1671 MyFree(InfFileNameW
);
1676 /***********************************************************************
1677 * Helper function for SetupDiInstallClassExW
1680 SETUP_CreateClassKey(HINF hInf
)
1682 WCHAR FullBuffer
[MAX_PATH
];
1683 WCHAR Buffer
[MAX_PATH
];
1685 HKEY hClassKey
= NULL
;
1686 HKEY ret
= INVALID_HANDLE_VALUE
;
1688 FullBuffer
[0] = '\0';
1690 if (!SetupGetLineTextW(NULL
,
1701 lstrcpyW(FullBuffer
, REGSTR_PATH_CLASS_NT
);
1702 lstrcatW(FullBuffer
, Buffer
);
1704 if (!SetupGetLineTextW(NULL
,
1712 RegDeleteKeyW(HKEY_LOCAL_MACHINE
, FullBuffer
);
1716 if (ERROR_SUCCESS
!= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
1720 REG_OPTION_NON_VOLATILE
,
1729 if (ERROR_SUCCESS
!= RegSetValueExW(hClassKey
,
1734 RequiredSize
* sizeof(WCHAR
)))
1742 if (hClassKey
!= NULL
&& hClassKey
!= ret
)
1743 RegCloseKey(hClassKey
);
1744 if (ret
== INVALID_HANDLE_VALUE
&& FullBuffer
[0] != '\0')
1745 RegDeleteKeyW(HKEY_LOCAL_MACHINE
, FullBuffer
);
1749 /***********************************************************************
1750 * SetupDiInstallClassExW (SETUPAPI.@)
1753 SetupDiInstallClassExW(
1754 IN HWND hwndParent OPTIONAL
,
1755 IN PCWSTR InfFileName OPTIONAL
,
1757 IN HSPFILEQ FileQueue OPTIONAL
,
1758 IN CONST GUID
*InterfaceClassGuid OPTIONAL
,
1764 TRACE("%p %s 0x%lx %p %s %p %p\n", hwndParent
, debugstr_w(InfFileName
), Flags
,
1765 FileQueue
, debugstr_guid(InterfaceClassGuid
), Reserved1
, Reserved2
);
1769 FIXME("Case not implemented: InfFileName NULL\n");
1770 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1772 else if (Flags
& ~(DI_NOVCP
| DI_NOBROWSE
| DI_FORCECOPY
| DI_QUIETINSTALL
))
1774 TRACE("Unknown flags: 0x%08lx\n", Flags
& ~(DI_NOVCP
| DI_NOBROWSE
| DI_FORCECOPY
| DI_QUIETINSTALL
));
1775 SetLastError(ERROR_INVALID_FLAGS
);
1777 else if ((Flags
& DI_NOVCP
) && FileQueue
== NULL
)
1778 SetLastError(ERROR_INVALID_PARAMETER
);
1779 else if (Reserved1
!= NULL
)
1780 SetLastError(ERROR_INVALID_PARAMETER
);
1781 else if (Reserved2
!= NULL
)
1782 SetLastError(ERROR_INVALID_PARAMETER
);
1785 HDEVINFO hDeviceInfo
= INVALID_HANDLE_VALUE
;
1786 SP_DEVINSTALL_PARAMS_W InstallParams
;
1787 WCHAR SectionName
[MAX_PATH
];
1788 HINF hInf
= INVALID_HANDLE_VALUE
;
1789 HKEY hRootKey
= INVALID_HANDLE_VALUE
;
1790 PVOID callback_context
= NULL
;
1792 hDeviceInfo
= SetupDiCreateDeviceInfoList(NULL
, NULL
);
1793 if (hDeviceInfo
== INVALID_HANDLE_VALUE
)
1796 InstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS
);
1797 if (!SetupDiGetDeviceInstallParamsW(hDeviceInfo
, NULL
, &InstallParams
))
1799 InstallParams
.Flags
&= ~(DI_NOVCP
| DI_NOBROWSE
| DI_QUIETINSTALL
);
1800 InstallParams
.Flags
|= Flags
& (DI_NOVCP
| DI_NOBROWSE
| DI_QUIETINSTALL
);
1801 if (Flags
& DI_NOVCP
)
1802 InstallParams
.FileQueue
= FileQueue
;
1803 if (!SetupDiSetDeviceInstallParamsW(hDeviceInfo
, NULL
, &InstallParams
))
1806 /* Open the .inf file */
1807 hInf
= SetupOpenInfFileW(
1812 if (hInf
== INVALID_HANDLE_VALUE
)
1815 /* Try to append a layout file */
1816 ret
= SetupOpenAppendInfFileW(NULL
, hInf
, NULL
);
1820 if (InterfaceClassGuid
)
1822 /* Retrieve the actual section name */
1823 ret
= SetupDiGetActualSectionToInstallW(
1833 /* Open registry key related to this interface */
1834 /* FIXME: What happens if the key doesn't exist? */
1835 hRootKey
= SetupDiOpenClassRegKeyExW(InterfaceClassGuid
, KEY_ENUMERATE_SUB_KEYS
, DIOCR_INTERFACE
, NULL
, NULL
);
1836 if (hRootKey
== INVALID_HANDLE_VALUE
)
1839 /* SetupDiCreateDeviceInterface??? */
1840 FIXME("Installing an interface is not implemented\n");
1841 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1845 /* Create or open the class registry key 'HKLM\CurrentControlSet\Class\{GUID}' */
1846 hRootKey
= SETUP_CreateClassKey(hInf
);
1847 if (hRootKey
== INVALID_HANDLE_VALUE
)
1850 /* Retrieve the actual section name */
1851 ret
= SetupDiGetActualSectionToInstallW(
1855 MAX_PATH
- strlenW(DotServices
),
1861 callback_context
= SetupInitDefaultQueueCallback(hwndParent
);
1862 if (!callback_context
)
1865 ret
= SetupInstallFromInfSectionW(
1869 SPINST_REGISTRY
| SPINST_FILES
| SPINST_BITREG
| SPINST_INIFILES
| SPINST_INI2REG
,
1871 NULL
, /* FIXME: SourceRootPath */
1872 !(Flags
& DI_NOVCP
) && (Flags
& DI_FORCECOPY
) ? SP_COPY_FORCE_IN_USE
: 0, /* CopyFlags */
1873 SetupDefaultQueueCallbackW
,
1880 /* Install .Services section */
1881 lstrcatW(SectionName
, DotServices
);
1882 ret
= SetupInstallServicesFromInfSectionExW(
1897 if (hDeviceInfo
!= INVALID_HANDLE_VALUE
)
1898 SetupDiDestroyDeviceInfoList(hDeviceInfo
);
1899 if (hInf
!= INVALID_HANDLE_VALUE
)
1900 SetupCloseInfFile(hInf
);
1901 if (hRootKey
!= INVALID_HANDLE_VALUE
)
1902 RegCloseKey(hRootKey
);
1903 SetupTermDefaultQueueCallback(callback_context
);
1906 TRACE("Returning %d\n", ret
);
1910 /***********************************************************************
1911 * SetupDiOpenClassRegKey (SETUPAPI.@)
1914 SetupDiOpenClassRegKey(
1915 IN CONST GUID
*ClassGuid OPTIONAL
,
1916 IN REGSAM samDesired
)
1918 return SetupDiOpenClassRegKeyExW(ClassGuid
, samDesired
,
1919 DIOCR_INSTALLER
, NULL
, NULL
);
1922 /***********************************************************************
1923 * SetupDiOpenClassRegKeyExA (SETUPAPI.@)
1926 SetupDiOpenClassRegKeyExA(
1927 IN CONST GUID
*ClassGuid OPTIONAL
,
1928 IN REGSAM samDesired
,
1930 IN PCSTR MachineName OPTIONAL
,
1933 PWSTR MachineNameW
= NULL
;
1936 TRACE("%s 0x%lx 0x%lx %s %p\n", debugstr_guid(ClassGuid
), samDesired
,
1937 Flags
, debugstr_a(MachineName
), Reserved
);
1941 MachineNameW
= MultiByteToUnicode(MachineName
, CP_ACP
);
1942 if (MachineNameW
== NULL
)
1943 return INVALID_HANDLE_VALUE
;
1946 hKey
= SetupDiOpenClassRegKeyExW(ClassGuid
, samDesired
,
1947 Flags
, MachineNameW
, Reserved
);
1949 MyFree(MachineNameW
);
1954 /***********************************************************************
1955 * SetupDiOpenClassRegKeyExW (SETUPAPI.@)
1958 SetupDiOpenClassRegKeyExW(
1959 IN CONST GUID
* ClassGuid OPTIONAL
,
1960 IN REGSAM samDesired
,
1962 IN PCWSTR MachineName OPTIONAL
,
1965 LPWSTR lpGuidString
= NULL
;
1966 LPWSTR lpFullGuidString
= NULL
;
1969 HKEY hClassesKey
= NULL
;
1970 HKEY hClassKey
= NULL
;
1971 HKEY ret
= INVALID_HANDLE_VALUE
;
1975 TRACE("%s 0x%lx 0x%lx %s %p\n", debugstr_guid(ClassGuid
), samDesired
,
1976 Flags
, debugstr_w(MachineName
), Reserved
);
1978 if (Flags
== DIOCR_INSTALLER
)
1979 lpKeyName
= REGSTR_PATH_CLASS_NT
;
1980 else if (Flags
== DIOCR_INTERFACE
)
1981 lpKeyName
= REGSTR_PATH_DEVICE_CLASSES
;
1984 TRACE("Unknown flags: 0x%lx\n", Flags
);
1985 SetLastError(ERROR_INVALID_FLAGS
);
1989 if (MachineName
!= NULL
)
1991 rc
= RegConnectRegistryW(MachineName
, HKEY_LOCAL_MACHINE
, &HKLM
);
1992 if (rc
!= ERROR_SUCCESS
)
1999 HKLM
= HKEY_LOCAL_MACHINE
;
2001 rc
= RegOpenKeyExW(HKLM
,
2004 ClassGuid
? KEY_ENUMERATE_SUB_KEYS
: samDesired
,
2006 if (MachineName
!= NULL
)
2008 if (rc
!= ERROR_SUCCESS
)
2014 if (ClassGuid
== NULL
)
2016 /* Stop here. We don't need to open a subkey */
2021 if (UuidToStringW((UUID
*)ClassGuid
, &lpGuidString
) != RPC_S_OK
)
2023 SetLastError(ERROR_GEN_FAILURE
);
2027 dwLength
= lstrlenW(lpGuidString
);
2028 lpFullGuidString
= HeapAlloc(GetProcessHeap(), 0, (dwLength
+ 3) * sizeof(WCHAR
));
2029 if (!lpFullGuidString
)
2031 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2034 lpFullGuidString
[0] = '{';
2035 memcpy(&lpFullGuidString
[1], lpGuidString
, dwLength
* sizeof(WCHAR
));
2036 lpFullGuidString
[dwLength
+ 1] = '}';
2037 lpFullGuidString
[dwLength
+ 2] = '\0';
2039 rc
= RegOpenKeyExW(hClassesKey
,
2044 if (rc
!= ERROR_SUCCESS
)
2052 if (hClassKey
!= NULL
&& hClassKey
!= ret
)
2053 RegCloseKey(hClassKey
);
2054 if (hClassesKey
!= NULL
&& hClassesKey
!= ret
)
2055 RegCloseKey(hClassesKey
);
2057 RpcStringFreeW(&lpGuidString
);
2058 HeapFree(GetProcessHeap(), 0, lpFullGuidString
);
2063 /***********************************************************************
2064 * SetupDiSetClassInstallParamsA (SETUPAPI.@)
2067 SetupDiSetClassInstallParamsA(
2068 IN HDEVINFO DeviceInfoSet
,
2069 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
2070 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
2071 IN DWORD ClassInstallParamsSize
)
2073 FIXME("%p %p %x %lu\n",DeviceInfoSet
, DeviceInfoData
,
2074 ClassInstallParams
->InstallFunction
, ClassInstallParamsSize
);
2078 /***********************************************************************
2079 * Helper functions for SetupDiSetClassInstallParamsW
2082 SETUP_PropertyChangeHandler(
2083 IN HDEVINFO DeviceInfoSet
,
2084 IN PSP_DEVINFO_DATA DeviceInfoData
,
2085 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
2086 IN DWORD ClassInstallParamsSize
)
2088 PSP_PROPCHANGE_PARAMS PropChangeParams
= (PSP_PROPCHANGE_PARAMS
)ClassInstallParams
;
2091 if (!DeviceInfoData
)
2092 SetLastError(ERROR_INVALID_PARAMETER
);
2093 else if (ClassInstallParamsSize
!= sizeof(SP_PROPCHANGE_PARAMS
))
2094 SetLastError(ERROR_INVALID_PARAMETER
);
2095 else if (PropChangeParams
&& PropChangeParams
->StateChange
!= DICS_ENABLE
2096 && PropChangeParams
->StateChange
!= DICS_DISABLE
&& PropChangeParams
->StateChange
!= DICS_PROPCHANGE
2097 && PropChangeParams
->StateChange
!= DICS_START
&& PropChangeParams
->StateChange
!= DICS_STOP
)
2098 SetLastError(ERROR_INVALID_FLAGS
);
2099 else if (PropChangeParams
&& PropChangeParams
->Scope
!= DICS_FLAG_GLOBAL
2100 && PropChangeParams
->Scope
!= DICS_FLAG_CONFIGSPECIFIC
)
2101 SetLastError(ERROR_INVALID_FLAGS
);
2102 else if (PropChangeParams
2103 && (PropChangeParams
->StateChange
== DICS_START
|| PropChangeParams
->StateChange
== DICS_STOP
)
2104 && PropChangeParams
->Scope
!= DICS_FLAG_CONFIGSPECIFIC
)
2105 SetLastError(ERROR_INVALID_USER_BUFFER
);
2108 PSP_PROPCHANGE_PARAMS
*CurrentPropChangeParams
;
2109 if (!DeviceInfoData
)
2111 struct DeviceInfoSet
*list
= (struct DeviceInfoSet
*)DeviceInfoSet
;
2112 CurrentPropChangeParams
= &list
->ClassInstallParams
.PropChange
;
2116 struct DeviceInfoElement
*deviceInfo
= (struct DeviceInfoElement
*)DeviceInfoData
->Reserved
;
2117 CurrentPropChangeParams
= &deviceInfo
->ClassInstallParams
.PropChange
;
2119 if (*CurrentPropChangeParams
)
2121 MyFree(*CurrentPropChangeParams
);
2122 *CurrentPropChangeParams
= NULL
;
2124 if (PropChangeParams
)
2126 *CurrentPropChangeParams
= MyMalloc(sizeof(SP_PROPCHANGE_PARAMS
));
2127 if (!*CurrentPropChangeParams
)
2129 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2132 memcpy(*CurrentPropChangeParams
, PropChangeParams
, sizeof(SP_PROPCHANGE_PARAMS
));
2141 /***********************************************************************
2142 * SetupDiSetClassInstallParamsW (SETUPAPI.@)
2145 SetupDiSetClassInstallParamsW(
2146 IN HDEVINFO DeviceInfoSet
,
2147 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
2148 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
2149 IN DWORD ClassInstallParamsSize
)
2151 struct DeviceInfoSet
*list
;
2154 TRACE("%p %p %p %lu\n", DeviceInfoSet
, DeviceInfoData
,
2155 ClassInstallParams
, ClassInstallParamsSize
);
2158 SetLastError(ERROR_INVALID_PARAMETER
);
2159 else if (DeviceInfoSet
== (HDEVINFO
)INVALID_HANDLE_VALUE
)
2160 SetLastError(ERROR_INVALID_HANDLE
);
2161 else if ((list
= (struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEV_INFO_SET_MAGIC
)
2162 SetLastError(ERROR_INVALID_HANDLE
);
2163 else if (DeviceInfoData
&& DeviceInfoData
->cbSize
!= sizeof(SP_DEVINFO_DATA
))
2164 SetLastError(ERROR_INVALID_USER_BUFFER
);
2165 else if (ClassInstallParams
&& ClassInstallParams
->cbSize
!= sizeof(SP_CLASSINSTALL_HEADER
))
2166 SetLastError(ERROR_INVALID_USER_BUFFER
);
2167 else if (ClassInstallParams
&& ClassInstallParamsSize
< sizeof(SP_CLASSINSTALL_HEADER
))
2168 SetLastError(ERROR_INVALID_PARAMETER
);
2169 else if (!ClassInstallParams
&& ClassInstallParamsSize
!= 0)
2170 SetLastError(ERROR_INVALID_PARAMETER
);
2173 SP_DEVINSTALL_PARAMS_W InstallParams
;
2176 InstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS_W
);
2177 Result
= SetupDiGetDeviceInstallParamsW(DeviceInfoSet
, DeviceInfoData
, &InstallParams
);
2181 if (ClassInstallParams
)
2183 /* Check parameters in ClassInstallParams */
2184 if (ClassInstallParams
->InstallFunction
< DIF_SELECTDEVICE
2185 || ClassInstallParams
->InstallFunction
- DIF_SELECTDEVICE
>= sizeof(UpdateClassInstallParamHandlers
)/sizeof(UpdateClassInstallParamHandlers
[0]))
2187 SetLastError(ERROR_INVALID_USER_BUFFER
);
2190 else if (UpdateClassInstallParamHandlers
[ClassInstallParams
->InstallFunction
- DIF_SELECTDEVICE
] == NULL
)
2192 ERR("InstallFunction %u is valid, but has no associated update handler\n", ClassInstallParams
->InstallFunction
);
2193 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2196 ret
= UpdateClassInstallParamHandlers
[ClassInstallParams
->InstallFunction
- DIF_SELECTDEVICE
](DeviceInfoSet
, DeviceInfoData
, ClassInstallParams
, ClassInstallParamsSize
);
2199 InstallParams
.Flags
|= DI_CLASSINSTALLPARAMS
;
2203 InstallParams
.Flags
&= ~DI_CLASSINSTALLPARAMS
;
2206 ret
= SetupDiSetDeviceInstallParamsW(DeviceInfoSet
, DeviceInfoData
, &InstallParams
);
2210 TRACE("Returning %d\n", ret
);
2214 /***********************************************************************
2215 * SetupDiGetClassDevPropertySheetsA(SETUPAPI.@)
2218 SetupDiGetClassDevPropertySheetsA(
2219 IN HDEVINFO DeviceInfoSet
,
2220 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
2221 IN LPPROPSHEETHEADERA PropertySheetHeader
,
2222 IN DWORD PropertySheetHeaderPageListSize
,
2223 OUT PDWORD RequiredSize OPTIONAL
,
2224 IN DWORD PropertySheetType
)
2226 PROPSHEETHEADERW psh
;
2229 TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet
, DeviceInfoData
,
2230 PropertySheetHeader
, PropertySheetHeaderPageListSize
,
2231 RequiredSize
, PropertySheetType
);
2233 psh
.dwFlags
= PropertySheetHeader
->dwFlags
;
2234 psh
.phpage
= PropertySheetHeader
->phpage
;
2235 psh
.nPages
= PropertySheetHeader
->nPages
;
2237 ret
= SetupDiGetClassDevPropertySheetsW(DeviceInfoSet
, DeviceInfoData
, PropertySheetHeader
? &psh
: NULL
,
2238 PropertySheetHeaderPageListSize
, RequiredSize
,
2242 PropertySheetHeader
->nPages
= psh
.nPages
;
2245 TRACE("Returning %d\n", ret
);
2249 struct ClassDevPropertySheetsData
2251 HPROPSHEETPAGE
*PropertySheetPages
;
2252 DWORD MaximumNumberOfPages
;
2253 DWORD NumberOfPages
;
2257 SETUP_GetClassDevPropertySheetsCallback(
2258 IN HPROPSHEETPAGE hPropSheetPage
,
2259 IN OUT LPARAM lParam
)
2261 struct ClassDevPropertySheetsData
*PropPageData
;
2263 PropPageData
= (struct ClassDevPropertySheetsData
*)lParam
;
2265 if (PropPageData
->NumberOfPages
< PropPageData
->MaximumNumberOfPages
)
2267 *PropPageData
->PropertySheetPages
= hPropSheetPage
;
2268 PropPageData
->PropertySheetPages
++;
2271 PropPageData
->NumberOfPages
++;
2275 /***********************************************************************
2276 * SetupDiGetClassDevPropertySheetsW(SETUPAPI.@)
2279 SetupDiGetClassDevPropertySheetsW(
2280 IN HDEVINFO DeviceInfoSet
,
2281 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
2282 IN OUT LPPROPSHEETHEADERW PropertySheetHeader
,
2283 IN DWORD PropertySheetHeaderPageListSize
,
2284 OUT PDWORD RequiredSize OPTIONAL
,
2285 IN DWORD PropertySheetType
)
2287 struct DeviceInfoSet
*list
;
2290 TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet
, DeviceInfoData
,
2291 PropertySheetHeader
, PropertySheetHeaderPageListSize
,
2292 RequiredSize
, PropertySheetType
);
2295 SetLastError(ERROR_INVALID_HANDLE
);
2296 else if (((struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEV_INFO_SET_MAGIC
)
2297 SetLastError(ERROR_INVALID_HANDLE
);
2298 else if ((list
= (struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEV_INFO_SET_MAGIC
)
2299 SetLastError(ERROR_INVALID_HANDLE
);
2300 else if (!PropertySheetHeader
)
2301 SetLastError(ERROR_INVALID_PARAMETER
);
2302 else if (PropertySheetHeader
->dwFlags
& PSH_PROPSHEETPAGE
)
2303 SetLastError(ERROR_INVALID_FLAGS
);
2304 else if (DeviceInfoData
&& DeviceInfoData
->cbSize
!= sizeof(SP_DEVINFO_DATA
))
2305 SetLastError(ERROR_INVALID_USER_BUFFER
);
2306 else if (!DeviceInfoData
&& IsEqualIID(&list
->ClassGuid
, &GUID_NULL
))
2307 SetLastError(ERROR_INVALID_PARAMETER
);
2308 else if (!PropertySheetHeader
)
2309 SetLastError(ERROR_INVALID_PARAMETER
);
2310 else if (PropertySheetType
!= DIGCDP_FLAG_ADVANCED
2311 && PropertySheetType
!= DIGCDP_FLAG_BASIC
2312 && PropertySheetType
!= DIGCDP_FLAG_REMOTE_ADVANCED
2313 && PropertySheetType
!= DIGCDP_FLAG_REMOTE_BASIC
)
2314 SetLastError(ERROR_INVALID_PARAMETER
);
2317 HKEY hKey
= INVALID_HANDLE_VALUE
;
2318 SP_PROPSHEETPAGE_REQUEST Request
;
2319 LPWSTR PropPageProvider
= NULL
;
2320 HMODULE hModule
= NULL
;
2321 PROPERTY_PAGE_PROVIDER pPropPageProvider
= NULL
;
2322 struct ClassDevPropertySheetsData PropPageData
;
2323 DWORD dwLength
, dwRegType
;
2327 hKey
= SetupDiOpenDevRegKey(DeviceInfoSet
, DeviceInfoData
, DICS_FLAG_GLOBAL
, 0, DIREG_DRV
, KEY_QUERY_VALUE
);
2330 hKey
= SetupDiOpenClassRegKeyExW(&list
->ClassGuid
, KEY_QUERY_VALUE
,
2331 DIOCR_INSTALLER
, list
->MachineName
+ 2, NULL
);
2333 if (hKey
== INVALID_HANDLE_VALUE
)
2336 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, &dwRegType
, NULL
, &dwLength
);
2337 if (rc
== ERROR_FILE_NOT_FOUND
)
2339 /* No registry key. As it is optional, don't say it's a bad error */
2345 else if (rc
!= ERROR_SUCCESS
&& dwRegType
!= REG_SZ
)
2351 PropPageProvider
= HeapAlloc(GetProcessHeap(), 0, dwLength
+ sizeof(WCHAR
));
2352 if (!PropPageProvider
)
2354 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2357 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, NULL
, (LPBYTE
)PropPageProvider
, &dwLength
);
2358 if (rc
!= ERROR_SUCCESS
)
2363 PropPageProvider
[dwLength
/ sizeof(WCHAR
)] = 0;
2365 rc
= GetFunctionPointer(PropPageProvider
, &hModule
, (PVOID
*)&pPropPageProvider
);
2366 if (rc
!= ERROR_SUCCESS
)
2368 SetLastError(ERROR_INVALID_PROPPAGE_PROVIDER
);
2372 Request
.cbSize
= sizeof(SP_PROPSHEETPAGE_REQUEST
);
2373 Request
.PageRequested
= SPPSR_ENUM_ADV_DEVICE_PROPERTIES
;
2374 Request
.DeviceInfoSet
= DeviceInfoSet
;
2375 Request
.DeviceInfoData
= DeviceInfoData
;
2376 PropPageData
.PropertySheetPages
= &PropertySheetHeader
->phpage
[PropertySheetHeader
->nPages
];
2377 PropPageData
.MaximumNumberOfPages
= PropertySheetHeaderPageListSize
- PropertySheetHeader
->nPages
;
2378 PropPageData
.NumberOfPages
= 0;
2379 ret
= pPropPageProvider(&Request
, SETUP_GetClassDevPropertySheetsCallback
, (LPARAM
)&PropPageData
);
2384 *RequiredSize
= PropPageData
.NumberOfPages
+ PropertySheetHeader
->nPages
;
2385 if (PropPageData
.NumberOfPages
<= PropPageData
.MaximumNumberOfPages
)
2387 PropertySheetHeader
->nPages
+= PropPageData
.NumberOfPages
;
2392 PropertySheetHeader
->nPages
+= PropPageData
.MaximumNumberOfPages
;
2393 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2397 if (hKey
!= INVALID_HANDLE_VALUE
)
2399 HeapFree(GetProcessHeap(), 0, PropPageProvider
);
2400 FreeFunctionPointer(hModule
, pPropPageProvider
);
2403 TRACE("Returning %d\n", ret
);