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 SetupapiDll
[] = {'s','e','t','u','p','a','p','i','.','d','l','l',0};
34 static const WCHAR Version
[] = {'V','e','r','s','i','o','n',0};
37 (WINAPI
* PROPERTY_PAGE_PROVIDER
) (
38 IN PSP_PROPSHEETPAGE_REQUEST PropPageRequest
,
39 IN LPFNADDPROPSHEETPAGE fAddFunc
,
42 (*UPDATE_CLASS_PARAM_HANDLER
) (
43 IN HDEVINFO DeviceInfoSet
,
44 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
45 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
46 IN DWORD ClassInstallParamsSize
);
49 SETUP_PropertyChangeHandler(
50 IN HDEVINFO DeviceInfoSet
,
51 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
52 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
53 IN DWORD ClassInstallParamsSize
);
56 SETUP_PropertyAddPropertyAdvancedHandler(
57 IN HDEVINFO DeviceInfoSet
,
58 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
59 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
60 IN DWORD ClassInstallParamsSize
);
62 typedef struct _INSTALL_PARAMS_DATA
65 UPDATE_CLASS_PARAM_HANDLER UpdateHandler
;
68 } INSTALL_PARAMS_DATA
;
70 #define ADD_PARAM_HANDLER(Function, UpdateHandler, ParamsType, ParamsField) \
71 { Function, UpdateHandler, sizeof(ParamsType), FIELD_OFFSET(struct ClassInstallParams, ParamsField) },
73 static const INSTALL_PARAMS_DATA InstallParamsData
[] = {
74 ADD_PARAM_HANDLER(DIF_PROPERTYCHANGE
, SETUP_PropertyChangeHandler
, SP_PROPCHANGE_PARAMS
, PropChangeParams
)
75 ADD_PARAM_HANDLER(DIF_ADDPROPERTYPAGE_ADVANCED
, SETUP_PropertyAddPropertyAdvancedHandler
, SP_ADDPROPERTYPAGE_DATA
, AddPropertyPageData
)
77 #undef ADD_PARAM_HANDLER
80 /***********************************************************************
81 * SetupDiDestroyClassImageList(SETUPAPI.@)
84 SetupDiDestroyClassImageList(
85 IN PSP_CLASSIMAGELIST_DATA ClassImageListData
)
87 struct ClassImageList
*list
;
90 TRACE("%p\n", ClassImageListData
);
92 if (!ClassImageListData
)
93 SetLastError(ERROR_INVALID_PARAMETER
);
94 else if (ClassImageListData
->cbSize
!= sizeof(SP_CLASSIMAGELIST_DATA
))
95 SetLastError(ERROR_INVALID_USER_BUFFER
);
96 else if ((list
= (struct ClassImageList
*)ClassImageListData
->Reserved
) == NULL
)
97 SetLastError(ERROR_INVALID_USER_BUFFER
);
98 else if (list
->magic
!= SETUP_CLASS_IMAGE_LIST_MAGIC
)
99 SetLastError(ERROR_INVALID_USER_BUFFER
);
103 //ImageList_Destroy();
104 FIXME("Stub %p\n", ClassImageListData
);
105 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
108 TRACE("Returning %d\n", ret
);
112 /***********************************************************************
113 * SETUP_CreateDevicesListFromEnumerator
116 * list [IO] Device info set to fill with discovered devices.
117 * pClassGuid [I] If specified, only devices which belong to this class will be added.
118 * Enumerator [I] Location to search devices to add.
119 * hEnumeratorKey [I] Registry key corresponding to Enumerator key. Must have KEY_ENUMERATE_SUB_KEYS right.
122 * Success: ERROR_SUCCESS.
123 * Failure: an error code.
126 SETUP_CreateDevicesListFromEnumerator(
127 IN OUT
struct DeviceInfoSet
*list
,
128 IN CONST GUID
*pClassGuid OPTIONAL
,
129 IN LPCWSTR Enumerator
,
130 IN HKEY hEnumeratorKey
) /* handle to Enumerator registry key */
132 HKEY hDeviceIdKey
= NULL
, hInstanceIdKey
;
133 WCHAR KeyBuffer
[MAX_PATH
];
134 WCHAR InstancePath
[MAX_PATH
];
135 LPWSTR pEndOfInstancePath
; /* Pointer into InstancePath buffer */
136 struct DeviceInfo
*deviceInfo
;
138 DWORD dwLength
, dwRegType
;
141 /* Enumerate device IDs (subkeys of hEnumeratorKey) */
144 dwLength
= sizeof(KeyBuffer
) / sizeof(KeyBuffer
[0]);
145 rc
= RegEnumKeyExW(hEnumeratorKey
, i
, KeyBuffer
, &dwLength
, NULL
, NULL
, NULL
, NULL
);
146 if (rc
== ERROR_NO_MORE_ITEMS
)
148 if (rc
!= ERROR_SUCCESS
)
152 /* Open device id sub key */
153 if (hDeviceIdKey
!= NULL
)
154 RegCloseKey(hDeviceIdKey
);
155 rc
= RegOpenKeyExW(hEnumeratorKey
, KeyBuffer
, 0, KEY_ENUMERATE_SUB_KEYS
, &hDeviceIdKey
);
156 if (rc
!= ERROR_SUCCESS
)
158 strcpyW(InstancePath
, Enumerator
);
159 strcatW(InstancePath
, BackSlash
);
160 strcatW(InstancePath
, KeyBuffer
);
161 strcatW(InstancePath
, BackSlash
);
162 pEndOfInstancePath
= &InstancePath
[strlenW(InstancePath
)];
164 /* Enumerate instance IDs (subkeys of hDeviceIdKey) */
170 dwLength
= sizeof(KeyBuffer
) / sizeof(KeyBuffer
[0]);
171 rc
= RegEnumKeyExW(hDeviceIdKey
, j
, KeyBuffer
, &dwLength
, NULL
, NULL
, NULL
, NULL
);
172 if (rc
== ERROR_NO_MORE_ITEMS
)
174 if (rc
!= ERROR_SUCCESS
)
178 /* Open instance id sub key */
179 rc
= RegOpenKeyExW(hDeviceIdKey
, KeyBuffer
, 0, KEY_QUERY_VALUE
, &hInstanceIdKey
);
180 if (rc
!= ERROR_SUCCESS
)
182 *pEndOfInstancePath
= '\0';
183 strcatW(InstancePath
, KeyBuffer
);
185 /* Read ClassGUID value */
186 dwLength
= sizeof(KeyBuffer
) - sizeof(WCHAR
);
187 rc
= RegQueryValueExW(hInstanceIdKey
, ClassGUID
, NULL
, &dwRegType
, (LPBYTE
)KeyBuffer
, &dwLength
);
188 RegCloseKey(hInstanceIdKey
);
189 if (rc
== ERROR_FILE_NOT_FOUND
)
192 /* Skip this bad entry as we can't verify it */
194 /* Set a default GUID for this device */
195 memcpy(&KeyGuid
, &GUID_NULL
, sizeof(GUID
));
197 else if (rc
!= ERROR_SUCCESS
)
201 else if (dwRegType
!= REG_SZ
|| dwLength
< MAX_GUID_STRING_LEN
* sizeof(WCHAR
))
203 rc
= ERROR_GEN_FAILURE
;
208 KeyBuffer
[MAX_GUID_STRING_LEN
- 2] = '\0'; /* Replace the } by a NULL character */
209 if (UuidFromStringW(&KeyBuffer
[1], &KeyGuid
) != RPC_S_OK
)
210 /* Bad GUID, skip the entry */
214 if (pClassGuid
&& !IsEqualIID(&KeyGuid
, pClassGuid
))
216 /* Skip this entry as it is not the right device class */
220 /* Add the entry to the list */
221 if (!CreateDeviceInfo(list
, InstancePath
, &KeyGuid
, &deviceInfo
))
226 TRACE("Adding '%s' to device info set %p\n", debugstr_w(InstancePath
), list
);
227 InsertTailList(&list
->ListHead
, &deviceInfo
->ListEntry
);
234 if (hDeviceIdKey
!= NULL
)
235 RegCloseKey(hDeviceIdKey
);
240 SETUP_CreateDevicesList(
241 IN OUT
struct DeviceInfoSet
*list
,
242 IN PCWSTR MachineName OPTIONAL
,
243 IN CONST GUID
*Class OPTIONAL
,
244 IN PCWSTR Enumerator OPTIONAL
)
246 HKEY HKLM
= HKEY_LOCAL_MACHINE
;
247 HKEY hEnumKey
= NULL
;
248 HKEY hEnumeratorKey
= NULL
;
249 WCHAR KeyBuffer
[MAX_PATH
];
254 if (Class
&& IsEqualIID(Class
, &GUID_NULL
))
257 /* Open Enum key (if applicable) */
258 if (MachineName
!= NULL
)
260 rc
= RegConnectRegistryW(MachineName
, HKEY_LOCAL_MACHINE
, &HKLM
);
261 if (rc
!= ERROR_SUCCESS
)
267 REGSTR_PATH_SYSTEMENUM
,
269 KEY_ENUMERATE_SUB_KEYS
,
271 if (rc
!= ERROR_SUCCESS
)
274 /* If enumerator is provided, call directly SETUP_CreateDevicesListFromEnumerator.
275 * Else, enumerate all enumerators and call SETUP_CreateDevicesListFromEnumerator
284 KEY_ENUMERATE_SUB_KEYS
,
286 if (rc
!= ERROR_SUCCESS
)
288 if (rc
== ERROR_FILE_NOT_FOUND
)
289 rc
= ERROR_INVALID_DATA
;
292 rc
= SETUP_CreateDevicesListFromEnumerator(list
, Class
, Enumerator
, hEnumeratorKey
);
296 /* Enumerate enumerators */
300 dwLength
= sizeof(KeyBuffer
) / sizeof(KeyBuffer
[0]);
301 rc
= RegEnumKeyExW(hEnumKey
, i
, KeyBuffer
, &dwLength
, NULL
, NULL
, NULL
, NULL
);
302 if (rc
== ERROR_NO_MORE_ITEMS
)
304 else if (rc
!= ERROR_SUCCESS
)
309 if (hEnumeratorKey
!= NULL
)
310 RegCloseKey(hEnumeratorKey
);
311 rc
= RegOpenKeyExW(hEnumKey
, KeyBuffer
, 0, KEY_ENUMERATE_SUB_KEYS
, &hEnumeratorKey
);
312 if (rc
!= ERROR_SUCCESS
)
315 /* Call SETUP_CreateDevicesListFromEnumerator */
316 rc
= SETUP_CreateDevicesListFromEnumerator(list
, Class
, KeyBuffer
, hEnumeratorKey
);
317 if (rc
!= ERROR_SUCCESS
)
324 if (HKLM
!= HKEY_LOCAL_MACHINE
)
326 if (hEnumKey
!= NULL
)
327 RegCloseKey(hEnumKey
);
328 if (hEnumeratorKey
!= NULL
)
329 RegCloseKey(hEnumeratorKey
);
333 /***********************************************************************
334 * SetupDiGetClassImageIndex (SETUPAPI.@)
341 LPWSTR Buffer
= NULL
;
342 DWORD dwRegType
, dwLength
;
346 /* Read icon registry key */
347 rc
= RegQueryValueExW(hClassKey
, REGSTR_VAL_INSICON
, NULL
, &dwRegType
, NULL
, &dwLength
);
348 if (rc
!= ERROR_SUCCESS
)
352 } else if (dwRegType
!= REG_SZ
)
354 SetLastError(ERROR_INVALID_INDEX
);
357 Buffer
= MyMalloc(dwLength
+ sizeof(WCHAR
));
360 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
363 rc
= RegQueryValueExW(hClassKey
, REGSTR_VAL_INSICON
, NULL
, NULL
, (LPBYTE
)Buffer
, &dwLength
);
364 if (rc
!= ERROR_SUCCESS
)
369 /* make sure the returned buffer is NULL-terminated */
370 Buffer
[dwLength
/ sizeof(WCHAR
)] = 0;
372 /* Transform icon value to a INT */
373 *ImageIndex
= atoiW(Buffer
);
382 SetupDiGetClassImageIndex(
383 IN PSP_CLASSIMAGELIST_DATA ClassImageListData
,
384 IN CONST GUID
*ClassGuid
,
387 struct ClassImageList
*list
;
390 TRACE("%p %s %p\n", ClassImageListData
, debugstr_guid(ClassGuid
), ImageIndex
);
392 if (!ClassImageListData
|| !ClassGuid
|| !ImageIndex
)
393 SetLastError(ERROR_INVALID_PARAMETER
);
394 else if (ClassImageListData
->cbSize
!= sizeof(SP_CLASSIMAGELIST_DATA
))
395 SetLastError(ERROR_INVALID_USER_BUFFER
);
396 else if ((list
= (struct ClassImageList
*)ClassImageListData
->Reserved
) == NULL
)
397 SetLastError(ERROR_INVALID_USER_BUFFER
);
398 else if (list
->magic
!= SETUP_CLASS_IMAGE_LIST_MAGIC
)
399 SetLastError(ERROR_INVALID_USER_BUFFER
);
400 else if (!ImageIndex
)
401 SetLastError(ERROR_INVALID_PARAMETER
);
406 for (i
= 0; i
< list
->NumberOfGuids
; i
++)
408 if (IsEqualIID(ClassGuid
, &list
->Guids
[i
]))
412 if (i
== list
->NumberOfGuids
|| list
->IconIndexes
[i
] < 0)
413 SetLastError(ERROR_FILE_NOT_FOUND
);
416 *ImageIndex
= list
->IconIndexes
[i
];
421 TRACE("Returning %d\n", ret
);
425 /***********************************************************************
426 * SetupDiGetClassImageList(SETUPAPI.@)
429 SetupDiGetClassImageList(
430 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData
)
432 return SetupDiGetClassImageListExW(ClassImageListData
, NULL
, NULL
);
435 /***********************************************************************
436 * SetupDiGetClassImageListExA(SETUPAPI.@)
439 SetupDiGetClassImageListExA(
440 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData
,
441 IN PCSTR MachineName OPTIONAL
,
444 PWSTR MachineNameW
= NULL
;
449 MachineNameW
= pSetupMultiByteToUnicode(MachineName
, CP_ACP
);
450 if (MachineNameW
== NULL
)
454 ret
= SetupDiGetClassImageListExW(ClassImageListData
, MachineNameW
, Reserved
);
456 MyFree(MachineNameW
);
461 /***********************************************************************
462 * SetupDiGetClassImageListExW(SETUPAPI.@)
465 SetupDiGetClassImageListExW(
466 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData
,
467 IN PCWSTR MachineName OPTIONAL
,
472 TRACE("%p %p %p\n", ClassImageListData
, debugstr_w(MachineName
), Reserved
);
474 if (!ClassImageListData
)
475 SetLastError(ERROR_INVALID_PARAMETER
);
476 else if (ClassImageListData
->cbSize
!= sizeof(SP_CLASSIMAGELIST_DATA
))
477 SetLastError(ERROR_INVALID_USER_BUFFER
);
479 SetLastError(ERROR_INVALID_PARAMETER
);
482 struct ClassImageList
*list
= NULL
;
485 DWORD ilMask
, bkColor
;
490 /* Get list of all class GUIDs in given computer */
491 ret
= SetupDiBuildClassInfoListExW(
498 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
501 size
= sizeof(struct ClassImageList
)
502 + (sizeof(GUID
) + sizeof(INT
)) * RequiredSize
;
503 list
= HeapAlloc(GetProcessHeap(), 0, size
);
506 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
509 list
->magic
= SETUP_CLASS_IMAGE_LIST_MAGIC
;
510 list
->NumberOfGuids
= RequiredSize
;
511 list
->Guids
= (GUID
*)(list
+ 1);
512 list
->IconIndexes
= (INT
*)((ULONG_PTR
)(list
+ 1) + sizeof(GUID
) * RequiredSize
);
514 ret
= SetupDiBuildClassInfoListExW(
523 else if (RequiredSize
!= list
->NumberOfGuids
)
525 /* Hm. Class list changed since last call. Ignore
526 * this case as it should be very rare */
527 SetLastError(ERROR_GEN_FAILURE
);
532 /* Prepare a HIMAGELIST */
533 InitCommonControls();
539 bpp
= GetDeviceCaps(hDC
, BITSPIXEL
);
540 ReleaseDC(NULL
, hDC
);
547 ilMask
= ILC_COLOR16
;
549 ilMask
= ILC_COLOR24
;
551 ilMask
= ILC_COLOR32
;
557 ClassImageListData
->ImageList
= ImageList_Create(16, 16, ilMask
, 100, 10);
558 if (!ClassImageListData
->ImageList
)
561 ClassImageListData
->Reserved
= (ULONG_PTR
)list
;
563 /* For some reason, Windows sets the list background to COLOR_WINDOW */
564 bkColor
= GetSysColor(COLOR_WINDOW
);
565 ImageList_SetBkColor(ClassImageListData
->ImageList
, bkColor
);
567 /* Now, we "simply" need to load icons associated with all class guids,
568 * and put their index in the image list in the IconIndexes array */
569 for (i
= 0; i
< list
->NumberOfGuids
; i
++)
573 ret
= SetupDiLoadClassIcon(
579 hIcon
= LoadImage(hInstance
, MAKEINTRESOURCE(miniIconIndex
), IMAGE_ICON
, 16, 16, LR_DEFAULTCOLOR
);
582 list
->IconIndexes
[i
] = ImageList_AddIcon(ClassImageListData
->ImageList
, hIcon
);
586 list
->IconIndexes
[i
] = -1;
589 list
->IconIndexes
[i
] = -1; /* Special value to indicate that the icon is unavailable */
597 if (ClassImageListData
->Reserved
)
598 SetupDiDestroyClassImageList(ClassImageListData
);
604 TRACE("Returning %d\n", ret
);
608 /***********************************************************************
609 * SetupDiGetClassInstallParamsA(SETUPAPI.@)
612 SetupDiGetClassInstallParamsA(
613 IN HDEVINFO DeviceInfoSet
,
614 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
615 OUT PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
616 IN DWORD ClassInstallParamsSize
,
617 OUT PDWORD RequiredSize OPTIONAL
)
619 FIXME("SetupDiGetClassInstallParamsA(%p %p %p %lu %p) Stub\n",
620 DeviceInfoSet
, DeviceInfoData
, ClassInstallParams
, ClassInstallParamsSize
, RequiredSize
);
624 /***********************************************************************
625 * SetupDiGetClassInstallParamsW(SETUPAPI.@)
628 SetupDiGetClassInstallParamsW(
629 IN HDEVINFO DeviceInfoSet
,
630 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
631 OUT PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
632 IN DWORD ClassInstallParamsSize
,
633 OUT PDWORD RequiredSize OPTIONAL
)
635 FIXME("SetupDiGetClassInstallParamsW(%p %p %p %lu %p) Stub\n",
636 DeviceInfoSet
, DeviceInfoData
, ClassInstallParams
, ClassInstallParamsSize
, RequiredSize
);
640 /***********************************************************************
641 * SetupDiLoadClassIcon(SETUPAPI.@)
644 SetupDiLoadClassIcon(
645 IN CONST GUID
*ClassGuid
,
646 OUT HICON
*LargeIcon OPTIONAL
,
647 OUT PINT MiniIconIndex OPTIONAL
)
649 LPWSTR Buffer
= NULL
;
652 HKEY hKey
= INVALID_HANDLE_VALUE
;
658 hKey
= SetupDiOpenClassRegKey(ClassGuid
, KEY_QUERY_VALUE
);
659 if (hKey
!= INVALID_HANDLE_VALUE
)
660 SETUP_GetIconIndex(hKey
, &iconIndex
);
665 /* Look up icon in dll specified by Installer32 or EnumPropPages32 key */
668 DWORD dwRegType
, dwLength
;
669 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_INSTALLER_32
, NULL
, &dwRegType
, NULL
, &dwLength
);
670 if (rc
== ERROR_SUCCESS
&& dwRegType
== REG_SZ
)
672 Buffer
= MyMalloc(dwLength
+ sizeof(WCHAR
));
675 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
678 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_INSTALLER_32
, NULL
, NULL
, (LPBYTE
)Buffer
, &dwLength
);
679 if (rc
!= ERROR_SUCCESS
)
684 /* make sure the returned buffer is NULL-terminated */
685 Buffer
[dwLength
/ sizeof(WCHAR
)] = 0;
688 (ERROR_SUCCESS
== (rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, &dwRegType
, NULL
, &dwLength
))
689 && dwRegType
== REG_SZ
)
691 Buffer
= MyMalloc(dwLength
+ sizeof(WCHAR
));
694 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
697 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, NULL
, (LPBYTE
)Buffer
, &dwLength
);
698 if (rc
!= ERROR_SUCCESS
)
703 /* make sure the returned buffer is NULL-terminated */
704 Buffer
[dwLength
/ sizeof(WCHAR
)] = 0;
708 /* Unable to find where to load the icon */
709 SetLastError(ERROR_FILE_NOT_FOUND
);
712 Comma
= strchrW(Buffer
, ',');
715 SetLastError(ERROR_GEN_FAILURE
);
723 /* Look up icon in setupapi.dll */
724 DllName
= SetupapiDll
;
725 iconIndex
= -iconIndex
;
728 TRACE("Icon index %d, dll name %s\n", iconIndex
, debugstr_w(DllName
));
731 *LargeIcon
= LoadImage(hInstance
, MAKEINTRESOURCE(iconIndex
), IMAGE_ICON
, 32, 32, LR_DEFAULTCOLOR
);
734 SetLastError(ERROR_INVALID_INDEX
);
739 *MiniIconIndex
= iconIndex
;
743 if (hKey
!= INVALID_HANDLE_VALUE
)
749 TRACE("Returning %d\n", ret
);
753 /***********************************************************************
754 * SetupDiInstallClassExW (SETUPAPI.@)
757 SETUP_CreateClassKey(HINF hInf
);
759 SetupDiInstallClassExW(
760 IN HWND hwndParent OPTIONAL
,
761 IN PCWSTR InfFileName OPTIONAL
,
763 IN HSPFILEQ FileQueue OPTIONAL
,
764 IN CONST GUID
*InterfaceClassGuid OPTIONAL
,
770 TRACE("%p %s 0x%lx %p %s %p %p\n", hwndParent
, debugstr_w(InfFileName
), Flags
,
771 FileQueue
, debugstr_guid(InterfaceClassGuid
), Reserved1
, Reserved2
);
775 FIXME("Case not implemented: InfFileName NULL\n");
776 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
778 else if (Flags
& ~(DI_NOVCP
| DI_NOBROWSE
| DI_FORCECOPY
| DI_QUIETINSTALL
))
780 TRACE("Unknown flags: 0x%08lx\n", Flags
& ~(DI_NOVCP
| DI_NOBROWSE
| DI_FORCECOPY
| DI_QUIETINSTALL
));
781 SetLastError(ERROR_INVALID_FLAGS
);
783 else if ((Flags
& DI_NOVCP
) && FileQueue
== NULL
)
784 SetLastError(ERROR_INVALID_PARAMETER
);
785 else if (Reserved1
!= NULL
)
786 SetLastError(ERROR_INVALID_PARAMETER
);
787 else if (Reserved2
!= NULL
)
788 SetLastError(ERROR_INVALID_PARAMETER
);
791 HDEVINFO hDeviceInfo
= INVALID_HANDLE_VALUE
;
792 SP_DEVINSTALL_PARAMS_W InstallParams
;
793 WCHAR SectionName
[MAX_PATH
];
794 HINF hInf
= INVALID_HANDLE_VALUE
;
795 HKEY hRootKey
= INVALID_HANDLE_VALUE
;
796 PVOID callback_context
= NULL
;
798 hDeviceInfo
= SetupDiCreateDeviceInfoList(NULL
, NULL
);
799 if (hDeviceInfo
== INVALID_HANDLE_VALUE
)
802 InstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS
);
803 if (!SetupDiGetDeviceInstallParamsW(hDeviceInfo
, NULL
, &InstallParams
))
805 InstallParams
.Flags
&= ~(DI_NOVCP
| DI_NOBROWSE
| DI_QUIETINSTALL
);
806 InstallParams
.Flags
|= Flags
& (DI_NOVCP
| DI_NOBROWSE
| DI_QUIETINSTALL
);
807 if (Flags
& DI_NOVCP
)
808 InstallParams
.FileQueue
= FileQueue
;
809 if (!SetupDiSetDeviceInstallParamsW(hDeviceInfo
, NULL
, &InstallParams
))
812 /* Open the .inf file */
813 hInf
= SetupOpenInfFileW(
818 if (hInf
== INVALID_HANDLE_VALUE
)
821 /* Try to append a layout file */
822 SetupOpenAppendInfFileW(NULL
, hInf
, NULL
);
824 if (InterfaceClassGuid
)
826 /* Retrieve the actual section name */
827 ret
= SetupDiGetActualSectionToInstallW(
837 /* Open registry key related to this interface */
838 /* FIXME: What happens if the key doesn't exist? */
839 hRootKey
= SetupDiOpenClassRegKeyExW(InterfaceClassGuid
, KEY_ENUMERATE_SUB_KEYS
, DIOCR_INTERFACE
, NULL
, NULL
);
840 if (hRootKey
== INVALID_HANDLE_VALUE
)
843 /* SetupDiCreateDeviceInterface??? */
844 FIXME("Installing an interface is not implemented\n");
845 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
849 /* Create or open the class registry key 'HKLM\CurrentControlSet\Class\{GUID}' */
850 hRootKey
= SETUP_CreateClassKey(hInf
);
851 if (hRootKey
== INVALID_HANDLE_VALUE
)
854 /* Retrieve the actual section name */
855 ret
= SetupDiGetActualSectionToInstallW(
859 MAX_PATH
- strlenW(DotServices
),
865 callback_context
= SetupInitDefaultQueueCallback(hwndParent
);
866 if (!callback_context
)
869 ret
= SetupInstallFromInfSectionW(
873 SPINST_REGISTRY
| SPINST_FILES
| SPINST_BITREG
| SPINST_INIFILES
| SPINST_INI2REG
,
875 NULL
, /* FIXME: SourceRootPath */
876 !(Flags
& DI_NOVCP
) && (Flags
& DI_FORCECOPY
) ? SP_COPY_FORCE_IN_USE
: 0, /* CopyFlags */
877 SetupDefaultQueueCallbackW
,
884 /* Install .Services section */
885 lstrcatW(SectionName
, DotServices
);
886 ret
= SetupInstallServicesFromInfSectionExW(
901 if (hDeviceInfo
!= INVALID_HANDLE_VALUE
)
902 SetupDiDestroyDeviceInfoList(hDeviceInfo
);
903 if (hInf
!= INVALID_HANDLE_VALUE
)
904 SetupCloseInfFile(hInf
);
905 if (hRootKey
!= INVALID_HANDLE_VALUE
)
906 RegCloseKey(hRootKey
);
907 SetupTermDefaultQueueCallback(callback_context
);
910 TRACE("Returning %d\n", ret
);
914 /***********************************************************************
915 * Helper functions for SetupDiSetClassInstallParamsW
918 SETUP_PropertyChangeHandler(
919 IN HDEVINFO DeviceInfoSet
,
920 IN PSP_DEVINFO_DATA DeviceInfoData
,
921 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
922 IN DWORD ClassInstallParamsSize
)
924 PSP_PROPCHANGE_PARAMS PropChangeParams
= (PSP_PROPCHANGE_PARAMS
)ClassInstallParams
;
928 SetLastError(ERROR_INVALID_PARAMETER
);
929 else if (ClassInstallParamsSize
!= sizeof(SP_PROPCHANGE_PARAMS
))
930 SetLastError(ERROR_INVALID_PARAMETER
);
931 else if (PropChangeParams
&& PropChangeParams
->StateChange
!= DICS_ENABLE
932 && PropChangeParams
->StateChange
!= DICS_DISABLE
&& PropChangeParams
->StateChange
!= DICS_PROPCHANGE
933 && PropChangeParams
->StateChange
!= DICS_START
&& PropChangeParams
->StateChange
!= DICS_STOP
)
934 SetLastError(ERROR_INVALID_FLAGS
);
935 else if (PropChangeParams
&& PropChangeParams
->Scope
!= DICS_FLAG_GLOBAL
936 && PropChangeParams
->Scope
!= DICS_FLAG_CONFIGSPECIFIC
)
937 SetLastError(ERROR_INVALID_FLAGS
);
938 else if (PropChangeParams
939 && (PropChangeParams
->StateChange
== DICS_START
|| PropChangeParams
->StateChange
== DICS_STOP
)
940 && PropChangeParams
->Scope
!= DICS_FLAG_CONFIGSPECIFIC
)
941 SetLastError(ERROR_INVALID_USER_BUFFER
);
944 PSP_PROPCHANGE_PARAMS
*CurrentPropChangeParams
;
945 struct DeviceInfo
*deviceInfo
= (struct DeviceInfo
*)DeviceInfoData
->Reserved
;
946 CurrentPropChangeParams
= &deviceInfo
->ClassInstallParams
.PropChangeParams
;
948 if (*CurrentPropChangeParams
)
950 MyFree(*CurrentPropChangeParams
);
951 *CurrentPropChangeParams
= NULL
;
953 if (PropChangeParams
)
955 *CurrentPropChangeParams
= MyMalloc(ClassInstallParamsSize
);
956 if (!*CurrentPropChangeParams
)
958 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
961 memcpy(*CurrentPropChangeParams
, PropChangeParams
, ClassInstallParamsSize
);
971 SETUP_PropertyAddPropertyAdvancedHandler(
972 IN HDEVINFO DeviceInfoSet
,
973 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
974 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
975 IN DWORD ClassInstallParamsSize
)
977 PSP_ADDPROPERTYPAGE_DATA AddPropertyPageData
= (PSP_ADDPROPERTYPAGE_DATA
)ClassInstallParams
;
980 if (ClassInstallParamsSize
!= sizeof(SP_PROPCHANGE_PARAMS
))
981 SetLastError(ERROR_INVALID_PARAMETER
);
982 else if (AddPropertyPageData
&& AddPropertyPageData
->Flags
!= 0)
983 SetLastError(ERROR_INVALID_FLAGS
);
984 else if (AddPropertyPageData
&& AddPropertyPageData
->NumDynamicPages
>= MAX_INSTALLWIZARD_DYNAPAGES
)
985 SetLastError(ERROR_INVALID_USER_BUFFER
);
988 PSP_ADDPROPERTYPAGE_DATA
*CurrentAddPropertyPageData
;
991 struct DeviceInfoSet
*list
= (struct DeviceInfoSet
*)DeviceInfoSet
;
992 CurrentAddPropertyPageData
= &list
->ClassInstallParams
.AddPropertyPageData
;
996 struct DeviceInfo
*deviceInfo
= (struct DeviceInfo
*)DeviceInfoData
->Reserved
;
997 CurrentAddPropertyPageData
= &deviceInfo
->ClassInstallParams
.AddPropertyPageData
;
999 if (*CurrentAddPropertyPageData
)
1001 MyFree(*CurrentAddPropertyPageData
);
1002 *CurrentAddPropertyPageData
= NULL
;
1004 if (AddPropertyPageData
)
1006 *CurrentAddPropertyPageData
= MyMalloc(ClassInstallParamsSize
);
1007 if (!*CurrentAddPropertyPageData
)
1009 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1012 memcpy(*CurrentAddPropertyPageData
, AddPropertyPageData
, ClassInstallParamsSize
);
1021 /***********************************************************************
1022 * SetupDiSetClassInstallParamsW (SETUPAPI.@)
1025 SetupDiSetClassInstallParamsW(
1026 IN HDEVINFO DeviceInfoSet
,
1027 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
1028 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
1029 IN DWORD ClassInstallParamsSize
)
1031 struct DeviceInfoSet
*list
;
1034 TRACE("%p %p %p %lu\n", DeviceInfoSet
, DeviceInfoData
,
1035 ClassInstallParams
, ClassInstallParamsSize
);
1038 SetLastError(ERROR_INVALID_PARAMETER
);
1039 else if (DeviceInfoSet
== (HDEVINFO
)INVALID_HANDLE_VALUE
)
1040 SetLastError(ERROR_INVALID_HANDLE
);
1041 else if ((list
= (struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEVICE_INFO_SET_MAGIC
)
1042 SetLastError(ERROR_INVALID_HANDLE
);
1043 else if (DeviceInfoData
&& DeviceInfoData
->cbSize
!= sizeof(SP_DEVINFO_DATA
))
1044 SetLastError(ERROR_INVALID_USER_BUFFER
);
1045 else if (ClassInstallParams
&& ClassInstallParams
->cbSize
!= sizeof(SP_CLASSINSTALL_HEADER
))
1046 SetLastError(ERROR_INVALID_USER_BUFFER
);
1047 else if (ClassInstallParams
&& ClassInstallParamsSize
< sizeof(SP_CLASSINSTALL_HEADER
))
1048 SetLastError(ERROR_INVALID_PARAMETER
);
1049 else if (!ClassInstallParams
&& ClassInstallParamsSize
!= 0)
1050 SetLastError(ERROR_INVALID_PARAMETER
);
1053 SP_DEVINSTALL_PARAMS_W InstallParams
;
1056 InstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS_W
);
1057 Result
= SetupDiGetDeviceInstallParamsW(DeviceInfoSet
, DeviceInfoData
, &InstallParams
);
1061 if (ClassInstallParams
)
1064 /* Check parameters in ClassInstallParams */
1065 for (i
= 0; i
< sizeof(InstallParamsData
) / sizeof(InstallParamsData
[0]); i
++)
1067 if (InstallParamsData
[i
].Function
== ClassInstallParams
->InstallFunction
)
1069 ret
= InstallParamsData
[i
].UpdateHandler(
1073 ClassInstallParamsSize
);
1076 InstallParams
.Flags
|= DI_CLASSINSTALLPARAMS
;
1077 ret
= SetupDiSetDeviceInstallParamsW(DeviceInfoSet
, DeviceInfoData
, &InstallParams
);
1082 ERR("InstallFunction %u has no associated update handler\n", ClassInstallParams
->InstallFunction
);
1083 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1088 InstallParams
.Flags
&= ~DI_CLASSINSTALLPARAMS
;
1089 ret
= SetupDiSetDeviceInstallParamsW(DeviceInfoSet
, DeviceInfoData
, &InstallParams
);
1094 TRACE("Returning %d\n", ret
);
1098 /***********************************************************************
1099 * SetupDiGetClassDevPropertySheetsA(SETUPAPI.@)
1102 SetupDiGetClassDevPropertySheetsA(
1103 IN HDEVINFO DeviceInfoSet
,
1104 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
1105 IN LPPROPSHEETHEADERA PropertySheetHeader
,
1106 IN DWORD PropertySheetHeaderPageListSize
,
1107 OUT PDWORD RequiredSize OPTIONAL
,
1108 IN DWORD PropertySheetType
)
1110 PROPSHEETHEADERW psh
;
1113 TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet
, DeviceInfoData
,
1114 PropertySheetHeader
, PropertySheetHeaderPageListSize
,
1115 RequiredSize
, PropertySheetType
);
1117 psh
.dwFlags
= PropertySheetHeader
->dwFlags
;
1118 psh
.phpage
= PropertySheetHeader
->phpage
;
1119 psh
.nPages
= PropertySheetHeader
->nPages
;
1121 ret
= SetupDiGetClassDevPropertySheetsW(DeviceInfoSet
, DeviceInfoData
, PropertySheetHeader
? &psh
: NULL
,
1122 PropertySheetHeaderPageListSize
, RequiredSize
,
1126 PropertySheetHeader
->nPages
= psh
.nPages
;
1129 TRACE("Returning %d\n", ret
);
1133 struct ClassDevPropertySheetsData
1135 LPPROPSHEETHEADERW PropertySheetHeader
;
1136 DWORD PropertySheetHeaderPageListSize
;
1137 DWORD NumberOfPages
;
1142 SETUP_GetClassDevPropertySheetsCallback(
1143 IN HPROPSHEETPAGE hPropSheetPage
,
1144 IN OUT LPARAM lParam
)
1146 struct ClassDevPropertySheetsData
*PropPageData
;
1148 PropPageData
= (struct ClassDevPropertySheetsData
*)lParam
;
1150 PropPageData
->NumberOfPages
++;
1152 if (PropPageData
->PropertySheetHeader
->nPages
< PropPageData
->PropertySheetHeaderPageListSize
)
1154 PropPageData
->PropertySheetHeader
->phpage
[PropPageData
->PropertySheetHeader
->nPages
] = hPropSheetPage
;
1155 PropPageData
->PropertySheetHeader
->nPages
++;
1159 return PropPageData
->DontCancel
;
1162 /***********************************************************************
1163 * SetupDiGetClassDevPropertySheetsW(SETUPAPI.@)
1166 SetupDiGetClassDevPropertySheetsW(
1167 IN HDEVINFO DeviceInfoSet
,
1168 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
1169 IN OUT LPPROPSHEETHEADERW PropertySheetHeader
,
1170 IN DWORD PropertySheetHeaderPageListSize
,
1171 OUT PDWORD RequiredSize OPTIONAL
,
1172 IN DWORD PropertySheetType
)
1174 struct DeviceInfoSet
*list
;
1177 TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet
, DeviceInfoData
,
1178 PropertySheetHeader
, PropertySheetHeaderPageListSize
,
1179 RequiredSize
, PropertySheetType
);
1182 SetLastError(ERROR_INVALID_HANDLE
);
1183 else if (((struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEVICE_INFO_SET_MAGIC
)
1184 SetLastError(ERROR_INVALID_HANDLE
);
1185 else if ((list
= (struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEVICE_INFO_SET_MAGIC
)
1186 SetLastError(ERROR_INVALID_HANDLE
);
1187 else if (!PropertySheetHeader
)
1188 SetLastError(ERROR_INVALID_PARAMETER
);
1189 else if (PropertySheetHeader
->dwFlags
& PSH_PROPSHEETPAGE
)
1190 SetLastError(ERROR_INVALID_FLAGS
);
1191 else if (DeviceInfoData
&& DeviceInfoData
->cbSize
!= sizeof(SP_DEVINFO_DATA
))
1192 SetLastError(ERROR_INVALID_USER_BUFFER
);
1193 else if (!DeviceInfoData
&& IsEqualIID(&list
->ClassGuid
, &GUID_NULL
))
1194 SetLastError(ERROR_INVALID_PARAMETER
);
1195 else if (PropertySheetType
!= DIGCDP_FLAG_ADVANCED
1196 && PropertySheetType
!= DIGCDP_FLAG_BASIC
1197 && PropertySheetType
!= DIGCDP_FLAG_REMOTE_ADVANCED
1198 && PropertySheetType
!= DIGCDP_FLAG_REMOTE_BASIC
)
1199 SetLastError(ERROR_INVALID_PARAMETER
);
1202 HKEY hKey
= INVALID_HANDLE_VALUE
;
1203 SP_PROPSHEETPAGE_REQUEST Request
;
1204 LPWSTR PropPageProvider
= NULL
;
1205 HMODULE hModule
= NULL
;
1206 PROPERTY_PAGE_PROVIDER pPropPageProvider
= NULL
;
1207 struct ClassDevPropertySheetsData PropPageData
;
1208 DWORD dwLength
, dwRegType
;
1209 DWORD InitialNumberOfPages
;
1213 hKey
= SetupDiOpenDevRegKey(DeviceInfoSet
, DeviceInfoData
, DICS_FLAG_GLOBAL
, 0, DIREG_DRV
, KEY_QUERY_VALUE
);
1216 hKey
= SetupDiOpenClassRegKeyExW(&list
->ClassGuid
, KEY_QUERY_VALUE
,
1217 DIOCR_INSTALLER
, list
->MachineName
+ 2, NULL
);
1219 if (hKey
== INVALID_HANDLE_VALUE
)
1222 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, &dwRegType
, NULL
, &dwLength
);
1223 if (rc
== ERROR_FILE_NOT_FOUND
)
1225 /* No registry key. As it is optional, don't say it's a bad error */
1231 else if (rc
!= ERROR_SUCCESS
&& dwRegType
!= REG_SZ
)
1237 PropPageProvider
= HeapAlloc(GetProcessHeap(), 0, dwLength
+ sizeof(WCHAR
));
1238 if (!PropPageProvider
)
1240 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1243 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, NULL
, (LPBYTE
)PropPageProvider
, &dwLength
);
1244 if (rc
!= ERROR_SUCCESS
)
1249 PropPageProvider
[dwLength
/ sizeof(WCHAR
)] = 0;
1251 rc
= GetFunctionPointer(PropPageProvider
, &hModule
, (PVOID
*)&pPropPageProvider
);
1252 if (rc
!= ERROR_SUCCESS
)
1254 SetLastError(ERROR_INVALID_PROPPAGE_PROVIDER
);
1258 InitialNumberOfPages
= PropertySheetHeader
->nPages
;
1260 Request
.cbSize
= sizeof(SP_PROPSHEETPAGE_REQUEST
);
1261 Request
.PageRequested
= SPPSR_ENUM_ADV_DEVICE_PROPERTIES
;
1262 Request
.DeviceInfoSet
= DeviceInfoSet
;
1263 Request
.DeviceInfoData
= DeviceInfoData
;
1265 PropPageData
.PropertySheetHeader
= PropertySheetHeader
;
1266 PropPageData
.PropertySheetHeaderPageListSize
= PropertySheetHeaderPageListSize
;
1267 PropPageData
.NumberOfPages
= 0;
1268 PropPageData
.DontCancel
= (RequiredSize
!= NULL
) ? TRUE
: FALSE
;
1270 pPropPageProvider(&Request
, SETUP_GetClassDevPropertySheetsCallback
, (LPARAM
)&PropPageData
);
1273 *RequiredSize
= PropPageData
.NumberOfPages
;
1275 if (InitialNumberOfPages
+ PropPageData
.NumberOfPages
<= PropertySheetHeaderPageListSize
)
1281 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1285 if (hKey
!= INVALID_HANDLE_VALUE
)
1287 HeapFree(GetProcessHeap(), 0, PropPageProvider
);
1288 FreeFunctionPointer(hModule
, pPropPageProvider
);
1291 TRACE("Returning %d\n", ret
);