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
)
652 SetLastError(ERROR_INVALID_PARAMETER
);
655 LPWSTR Buffer
= NULL
;
658 HKEY hKey
= INVALID_HANDLE_VALUE
;
660 hKey
= SetupDiOpenClassRegKey(ClassGuid
, KEY_QUERY_VALUE
);
661 if (hKey
== INVALID_HANDLE_VALUE
)
664 if (!SETUP_GetIconIndex(hKey
, &iconIndex
))
669 /* Look up icon in dll specified by Installer32 or EnumPropPages32 key */
672 DWORD dwRegType
, dwLength
;
673 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_INSTALLER_32
, NULL
, &dwRegType
, NULL
, &dwLength
);
674 if (rc
== ERROR_SUCCESS
&& dwRegType
== REG_SZ
)
676 Buffer
= MyMalloc(dwLength
+ sizeof(WCHAR
));
679 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
682 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_INSTALLER_32
, NULL
, NULL
, (LPBYTE
)Buffer
, &dwLength
);
683 if (rc
!= ERROR_SUCCESS
)
688 /* make sure the returned buffer is NULL-terminated */
689 Buffer
[dwLength
/ sizeof(WCHAR
)] = 0;
692 (ERROR_SUCCESS
== (rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, &dwRegType
, NULL
, &dwLength
))
693 && dwRegType
== REG_SZ
)
695 Buffer
= MyMalloc(dwLength
+ sizeof(WCHAR
));
698 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
701 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, NULL
, (LPBYTE
)Buffer
, &dwLength
);
702 if (rc
!= ERROR_SUCCESS
)
707 /* make sure the returned buffer is NULL-terminated */
708 Buffer
[dwLength
/ sizeof(WCHAR
)] = 0;
712 /* Unable to find where to load the icon */
713 SetLastError(ERROR_FILE_NOT_FOUND
);
716 Comma
= strchrW(Buffer
, ',');
719 SetLastError(ERROR_GEN_FAILURE
);
727 /* Look up icon in setupapi.dll */
728 DllName
= SetupapiDll
;
729 iconIndex
= -iconIndex
;
732 TRACE("Icon index %d, dll name %s\n", iconIndex
, debugstr_w(DllName
));
735 *LargeIcon
= LoadImage(hInstance
, MAKEINTRESOURCE(iconIndex
), IMAGE_ICON
, 32, 32, LR_DEFAULTCOLOR
);
738 SetLastError(ERROR_INVALID_INDEX
);
743 *MiniIconIndex
= iconIndex
;
747 if (hKey
!= INVALID_HANDLE_VALUE
)
752 TRACE("Returning %d\n", ret
);
756 /***********************************************************************
757 * SetupDiInstallClassExW (SETUPAPI.@)
760 SETUP_CreateClassKey(HINF hInf
);
762 SetupDiInstallClassExW(
763 IN HWND hwndParent OPTIONAL
,
764 IN PCWSTR InfFileName OPTIONAL
,
766 IN HSPFILEQ FileQueue OPTIONAL
,
767 IN CONST GUID
*InterfaceClassGuid OPTIONAL
,
773 TRACE("%p %s 0x%lx %p %s %p %p\n", hwndParent
, debugstr_w(InfFileName
), Flags
,
774 FileQueue
, debugstr_guid(InterfaceClassGuid
), Reserved1
, Reserved2
);
778 FIXME("Case not implemented: InfFileName NULL\n");
779 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
781 else if (Flags
& ~(DI_NOVCP
| DI_NOBROWSE
| DI_FORCECOPY
| DI_QUIETINSTALL
))
783 TRACE("Unknown flags: 0x%08lx\n", Flags
& ~(DI_NOVCP
| DI_NOBROWSE
| DI_FORCECOPY
| DI_QUIETINSTALL
));
784 SetLastError(ERROR_INVALID_FLAGS
);
786 else if ((Flags
& DI_NOVCP
) && FileQueue
== NULL
)
787 SetLastError(ERROR_INVALID_PARAMETER
);
788 else if (Reserved1
!= NULL
)
789 SetLastError(ERROR_INVALID_PARAMETER
);
790 else if (Reserved2
!= NULL
)
791 SetLastError(ERROR_INVALID_PARAMETER
);
794 HDEVINFO hDeviceInfo
= INVALID_HANDLE_VALUE
;
795 SP_DEVINSTALL_PARAMS_W InstallParams
;
796 WCHAR SectionName
[MAX_PATH
];
797 HINF hInf
= INVALID_HANDLE_VALUE
;
798 HKEY hRootKey
= INVALID_HANDLE_VALUE
;
799 PVOID callback_context
= NULL
;
801 hDeviceInfo
= SetupDiCreateDeviceInfoList(NULL
, NULL
);
802 if (hDeviceInfo
== INVALID_HANDLE_VALUE
)
805 InstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS
);
806 if (!SetupDiGetDeviceInstallParamsW(hDeviceInfo
, NULL
, &InstallParams
))
808 InstallParams
.Flags
&= ~(DI_NOVCP
| DI_NOBROWSE
| DI_QUIETINSTALL
);
809 InstallParams
.Flags
|= Flags
& (DI_NOVCP
| DI_NOBROWSE
| DI_QUIETINSTALL
);
810 if (Flags
& DI_NOVCP
)
811 InstallParams
.FileQueue
= FileQueue
;
812 if (!SetupDiSetDeviceInstallParamsW(hDeviceInfo
, NULL
, &InstallParams
))
815 /* Open the .inf file */
816 hInf
= SetupOpenInfFileW(
821 if (hInf
== INVALID_HANDLE_VALUE
)
824 /* Try to append a layout file */
825 SetupOpenAppendInfFileW(NULL
, hInf
, NULL
);
827 if (InterfaceClassGuid
)
829 /* Retrieve the actual section name */
830 ret
= SetupDiGetActualSectionToInstallW(
840 /* Open registry key related to this interface */
841 /* FIXME: What happens if the key doesn't exist? */
842 hRootKey
= SetupDiOpenClassRegKeyExW(InterfaceClassGuid
, KEY_ENUMERATE_SUB_KEYS
, DIOCR_INTERFACE
, NULL
, NULL
);
843 if (hRootKey
== INVALID_HANDLE_VALUE
)
846 /* SetupDiCreateDeviceInterface??? */
847 FIXME("Installing an interface is not implemented\n");
848 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
852 /* Create or open the class registry key 'HKLM\CurrentControlSet\Class\{GUID}' */
853 hRootKey
= SETUP_CreateClassKey(hInf
);
854 if (hRootKey
== INVALID_HANDLE_VALUE
)
857 /* Retrieve the actual section name */
858 ret
= SetupDiGetActualSectionToInstallW(
862 MAX_PATH
- strlenW(DotServices
),
868 callback_context
= SetupInitDefaultQueueCallback(hwndParent
);
869 if (!callback_context
)
872 ret
= SetupInstallFromInfSectionW(
876 SPINST_REGISTRY
| SPINST_FILES
| SPINST_BITREG
| SPINST_INIFILES
| SPINST_INI2REG
,
878 NULL
, /* FIXME: SourceRootPath */
879 !(Flags
& DI_NOVCP
) && (Flags
& DI_FORCECOPY
) ? SP_COPY_FORCE_IN_USE
: 0, /* CopyFlags */
880 SetupDefaultQueueCallbackW
,
887 /* Install .Services section */
888 lstrcatW(SectionName
, DotServices
);
889 ret
= SetupInstallServicesFromInfSectionExW(
904 if (hDeviceInfo
!= INVALID_HANDLE_VALUE
)
905 SetupDiDestroyDeviceInfoList(hDeviceInfo
);
906 if (hInf
!= INVALID_HANDLE_VALUE
)
907 SetupCloseInfFile(hInf
);
908 if (hRootKey
!= INVALID_HANDLE_VALUE
)
909 RegCloseKey(hRootKey
);
910 SetupTermDefaultQueueCallback(callback_context
);
913 TRACE("Returning %d\n", ret
);
917 /***********************************************************************
918 * Helper functions for SetupDiSetClassInstallParamsW
921 SETUP_PropertyChangeHandler(
922 IN HDEVINFO DeviceInfoSet
,
923 IN PSP_DEVINFO_DATA DeviceInfoData
,
924 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
925 IN DWORD ClassInstallParamsSize
)
927 PSP_PROPCHANGE_PARAMS PropChangeParams
= (PSP_PROPCHANGE_PARAMS
)ClassInstallParams
;
931 SetLastError(ERROR_INVALID_PARAMETER
);
932 else if (ClassInstallParamsSize
!= sizeof(SP_PROPCHANGE_PARAMS
))
933 SetLastError(ERROR_INVALID_PARAMETER
);
934 else if (PropChangeParams
&& PropChangeParams
->StateChange
!= DICS_ENABLE
935 && PropChangeParams
->StateChange
!= DICS_DISABLE
&& PropChangeParams
->StateChange
!= DICS_PROPCHANGE
936 && PropChangeParams
->StateChange
!= DICS_START
&& PropChangeParams
->StateChange
!= DICS_STOP
)
937 SetLastError(ERROR_INVALID_FLAGS
);
938 else if (PropChangeParams
&& PropChangeParams
->Scope
!= DICS_FLAG_GLOBAL
939 && PropChangeParams
->Scope
!= DICS_FLAG_CONFIGSPECIFIC
)
940 SetLastError(ERROR_INVALID_FLAGS
);
941 else if (PropChangeParams
942 && (PropChangeParams
->StateChange
== DICS_START
|| PropChangeParams
->StateChange
== DICS_STOP
)
943 && PropChangeParams
->Scope
!= DICS_FLAG_CONFIGSPECIFIC
)
944 SetLastError(ERROR_INVALID_USER_BUFFER
);
947 PSP_PROPCHANGE_PARAMS
*CurrentPropChangeParams
;
948 struct DeviceInfo
*deviceInfo
= (struct DeviceInfo
*)DeviceInfoData
->Reserved
;
949 CurrentPropChangeParams
= &deviceInfo
->ClassInstallParams
.PropChangeParams
;
951 if (*CurrentPropChangeParams
)
953 MyFree(*CurrentPropChangeParams
);
954 *CurrentPropChangeParams
= NULL
;
956 if (PropChangeParams
)
958 *CurrentPropChangeParams
= MyMalloc(ClassInstallParamsSize
);
959 if (!*CurrentPropChangeParams
)
961 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
964 memcpy(*CurrentPropChangeParams
, PropChangeParams
, ClassInstallParamsSize
);
974 SETUP_PropertyAddPropertyAdvancedHandler(
975 IN HDEVINFO DeviceInfoSet
,
976 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
977 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
978 IN DWORD ClassInstallParamsSize
)
980 PSP_ADDPROPERTYPAGE_DATA AddPropertyPageData
= (PSP_ADDPROPERTYPAGE_DATA
)ClassInstallParams
;
983 if (ClassInstallParamsSize
!= sizeof(SP_PROPCHANGE_PARAMS
))
984 SetLastError(ERROR_INVALID_PARAMETER
);
985 else if (AddPropertyPageData
&& AddPropertyPageData
->Flags
!= 0)
986 SetLastError(ERROR_INVALID_FLAGS
);
987 else if (AddPropertyPageData
&& AddPropertyPageData
->NumDynamicPages
>= MAX_INSTALLWIZARD_DYNAPAGES
)
988 SetLastError(ERROR_INVALID_USER_BUFFER
);
991 PSP_ADDPROPERTYPAGE_DATA
*CurrentAddPropertyPageData
;
994 struct DeviceInfoSet
*list
= (struct DeviceInfoSet
*)DeviceInfoSet
;
995 CurrentAddPropertyPageData
= &list
->ClassInstallParams
.AddPropertyPageData
;
999 struct DeviceInfo
*deviceInfo
= (struct DeviceInfo
*)DeviceInfoData
->Reserved
;
1000 CurrentAddPropertyPageData
= &deviceInfo
->ClassInstallParams
.AddPropertyPageData
;
1002 if (*CurrentAddPropertyPageData
)
1004 MyFree(*CurrentAddPropertyPageData
);
1005 *CurrentAddPropertyPageData
= NULL
;
1007 if (AddPropertyPageData
)
1009 *CurrentAddPropertyPageData
= MyMalloc(ClassInstallParamsSize
);
1010 if (!*CurrentAddPropertyPageData
)
1012 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1015 memcpy(*CurrentAddPropertyPageData
, AddPropertyPageData
, ClassInstallParamsSize
);
1024 /***********************************************************************
1025 * SetupDiSetClassInstallParamsW (SETUPAPI.@)
1028 SetupDiSetClassInstallParamsW(
1029 IN HDEVINFO DeviceInfoSet
,
1030 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
1031 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
1032 IN DWORD ClassInstallParamsSize
)
1034 struct DeviceInfoSet
*list
;
1037 TRACE("%p %p %p %lu\n", DeviceInfoSet
, DeviceInfoData
,
1038 ClassInstallParams
, ClassInstallParamsSize
);
1041 SetLastError(ERROR_INVALID_PARAMETER
);
1042 else if (DeviceInfoSet
== (HDEVINFO
)INVALID_HANDLE_VALUE
)
1043 SetLastError(ERROR_INVALID_HANDLE
);
1044 else if ((list
= (struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEVICE_INFO_SET_MAGIC
)
1045 SetLastError(ERROR_INVALID_HANDLE
);
1046 else if (DeviceInfoData
&& DeviceInfoData
->cbSize
!= sizeof(SP_DEVINFO_DATA
))
1047 SetLastError(ERROR_INVALID_USER_BUFFER
);
1048 else if (ClassInstallParams
&& ClassInstallParams
->cbSize
!= sizeof(SP_CLASSINSTALL_HEADER
))
1049 SetLastError(ERROR_INVALID_USER_BUFFER
);
1050 else if (ClassInstallParams
&& ClassInstallParamsSize
< sizeof(SP_CLASSINSTALL_HEADER
))
1051 SetLastError(ERROR_INVALID_PARAMETER
);
1052 else if (!ClassInstallParams
&& ClassInstallParamsSize
!= 0)
1053 SetLastError(ERROR_INVALID_PARAMETER
);
1056 SP_DEVINSTALL_PARAMS_W InstallParams
;
1059 InstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS_W
);
1060 Result
= SetupDiGetDeviceInstallParamsW(DeviceInfoSet
, DeviceInfoData
, &InstallParams
);
1064 if (ClassInstallParams
)
1067 /* Check parameters in ClassInstallParams */
1068 for (i
= 0; i
< sizeof(InstallParamsData
) / sizeof(InstallParamsData
[0]); i
++)
1070 if (InstallParamsData
[i
].Function
== ClassInstallParams
->InstallFunction
)
1072 ret
= InstallParamsData
[i
].UpdateHandler(
1076 ClassInstallParamsSize
);
1079 InstallParams
.Flags
|= DI_CLASSINSTALLPARAMS
;
1080 ret
= SetupDiSetDeviceInstallParamsW(DeviceInfoSet
, DeviceInfoData
, &InstallParams
);
1085 ERR("InstallFunction %u has no associated update handler\n", ClassInstallParams
->InstallFunction
);
1086 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1091 InstallParams
.Flags
&= ~DI_CLASSINSTALLPARAMS
;
1092 ret
= SetupDiSetDeviceInstallParamsW(DeviceInfoSet
, DeviceInfoData
, &InstallParams
);
1097 TRACE("Returning %d\n", ret
);
1101 /***********************************************************************
1102 * SetupDiGetClassDevPropertySheetsA(SETUPAPI.@)
1105 SetupDiGetClassDevPropertySheetsA(
1106 IN HDEVINFO DeviceInfoSet
,
1107 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
1108 IN LPPROPSHEETHEADERA PropertySheetHeader
,
1109 IN DWORD PropertySheetHeaderPageListSize
,
1110 OUT PDWORD RequiredSize OPTIONAL
,
1111 IN DWORD PropertySheetType
)
1113 PROPSHEETHEADERW psh
;
1116 TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet
, DeviceInfoData
,
1117 PropertySheetHeader
, PropertySheetHeaderPageListSize
,
1118 RequiredSize
, PropertySheetType
);
1120 psh
.dwFlags
= PropertySheetHeader
->dwFlags
;
1121 psh
.phpage
= PropertySheetHeader
->phpage
;
1122 psh
.nPages
= PropertySheetHeader
->nPages
;
1124 ret
= SetupDiGetClassDevPropertySheetsW(DeviceInfoSet
, DeviceInfoData
, PropertySheetHeader
? &psh
: NULL
,
1125 PropertySheetHeaderPageListSize
, RequiredSize
,
1129 PropertySheetHeader
->nPages
= psh
.nPages
;
1132 TRACE("Returning %d\n", ret
);
1136 struct ClassDevPropertySheetsData
1138 LPPROPSHEETHEADERW PropertySheetHeader
;
1139 DWORD PropertySheetHeaderPageListSize
;
1140 DWORD NumberOfPages
;
1145 SETUP_GetClassDevPropertySheetsCallback(
1146 IN HPROPSHEETPAGE hPropSheetPage
,
1147 IN OUT LPARAM lParam
)
1149 struct ClassDevPropertySheetsData
*PropPageData
;
1151 PropPageData
= (struct ClassDevPropertySheetsData
*)lParam
;
1153 PropPageData
->NumberOfPages
++;
1155 if (PropPageData
->PropertySheetHeader
->nPages
< PropPageData
->PropertySheetHeaderPageListSize
)
1157 PropPageData
->PropertySheetHeader
->phpage
[PropPageData
->PropertySheetHeader
->nPages
] = hPropSheetPage
;
1158 PropPageData
->PropertySheetHeader
->nPages
++;
1162 return PropPageData
->DontCancel
;
1165 /***********************************************************************
1166 * SetupDiGetClassDevPropertySheetsW(SETUPAPI.@)
1169 SetupDiGetClassDevPropertySheetsW(
1170 IN HDEVINFO DeviceInfoSet
,
1171 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
1172 IN OUT LPPROPSHEETHEADERW PropertySheetHeader
,
1173 IN DWORD PropertySheetHeaderPageListSize
,
1174 OUT PDWORD RequiredSize OPTIONAL
,
1175 IN DWORD PropertySheetType
)
1177 struct DeviceInfoSet
*list
;
1180 TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet
, DeviceInfoData
,
1181 PropertySheetHeader
, PropertySheetHeaderPageListSize
,
1182 RequiredSize
, PropertySheetType
);
1185 SetLastError(ERROR_INVALID_HANDLE
);
1186 else if (((struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEVICE_INFO_SET_MAGIC
)
1187 SetLastError(ERROR_INVALID_HANDLE
);
1188 else if ((list
= (struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEVICE_INFO_SET_MAGIC
)
1189 SetLastError(ERROR_INVALID_HANDLE
);
1190 else if (!PropertySheetHeader
)
1191 SetLastError(ERROR_INVALID_PARAMETER
);
1192 else if (PropertySheetHeader
->dwFlags
& PSH_PROPSHEETPAGE
)
1193 SetLastError(ERROR_INVALID_FLAGS
);
1194 else if (DeviceInfoData
&& DeviceInfoData
->cbSize
!= sizeof(SP_DEVINFO_DATA
))
1195 SetLastError(ERROR_INVALID_USER_BUFFER
);
1196 else if (!DeviceInfoData
&& IsEqualIID(&list
->ClassGuid
, &GUID_NULL
))
1197 SetLastError(ERROR_INVALID_PARAMETER
);
1198 else if (PropertySheetType
!= DIGCDP_FLAG_ADVANCED
1199 && PropertySheetType
!= DIGCDP_FLAG_BASIC
1200 && PropertySheetType
!= DIGCDP_FLAG_REMOTE_ADVANCED
1201 && PropertySheetType
!= DIGCDP_FLAG_REMOTE_BASIC
)
1202 SetLastError(ERROR_INVALID_PARAMETER
);
1205 HKEY hKey
= INVALID_HANDLE_VALUE
;
1206 SP_PROPSHEETPAGE_REQUEST Request
;
1207 LPWSTR PropPageProvider
= NULL
;
1208 HMODULE hModule
= NULL
;
1209 PROPERTY_PAGE_PROVIDER pPropPageProvider
= NULL
;
1210 struct ClassDevPropertySheetsData PropPageData
;
1211 DWORD dwLength
, dwRegType
;
1212 DWORD InitialNumberOfPages
;
1216 hKey
= SetupDiOpenDevRegKey(DeviceInfoSet
, DeviceInfoData
, DICS_FLAG_GLOBAL
, 0, DIREG_DRV
, KEY_QUERY_VALUE
);
1219 hKey
= SetupDiOpenClassRegKeyExW(&list
->ClassGuid
, KEY_QUERY_VALUE
,
1220 DIOCR_INSTALLER
, list
->MachineName
+ 2, NULL
);
1222 if (hKey
== INVALID_HANDLE_VALUE
)
1225 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, &dwRegType
, NULL
, &dwLength
);
1226 if (rc
== ERROR_FILE_NOT_FOUND
)
1228 /* No registry key. As it is optional, don't say it's a bad error */
1234 else if (rc
!= ERROR_SUCCESS
&& dwRegType
!= REG_SZ
)
1240 PropPageProvider
= HeapAlloc(GetProcessHeap(), 0, dwLength
+ sizeof(WCHAR
));
1241 if (!PropPageProvider
)
1243 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1246 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, NULL
, (LPBYTE
)PropPageProvider
, &dwLength
);
1247 if (rc
!= ERROR_SUCCESS
)
1252 PropPageProvider
[dwLength
/ sizeof(WCHAR
)] = 0;
1254 rc
= GetFunctionPointer(PropPageProvider
, &hModule
, (PVOID
*)&pPropPageProvider
);
1255 if (rc
!= ERROR_SUCCESS
)
1257 SetLastError(ERROR_INVALID_PROPPAGE_PROVIDER
);
1261 InitialNumberOfPages
= PropertySheetHeader
->nPages
;
1263 Request
.cbSize
= sizeof(SP_PROPSHEETPAGE_REQUEST
);
1264 Request
.PageRequested
= SPPSR_ENUM_ADV_DEVICE_PROPERTIES
;
1265 Request
.DeviceInfoSet
= DeviceInfoSet
;
1266 Request
.DeviceInfoData
= DeviceInfoData
;
1268 PropPageData
.PropertySheetHeader
= PropertySheetHeader
;
1269 PropPageData
.PropertySheetHeaderPageListSize
= PropertySheetHeaderPageListSize
;
1270 PropPageData
.NumberOfPages
= 0;
1271 PropPageData
.DontCancel
= (RequiredSize
!= NULL
) ? TRUE
: FALSE
;
1273 pPropPageProvider(&Request
, SETUP_GetClassDevPropertySheetsCallback
, (LPARAM
)&PropPageData
);
1276 *RequiredSize
= PropPageData
.NumberOfPages
;
1278 if (InitialNumberOfPages
+ PropPageData
.NumberOfPages
<= PropertySheetHeaderPageListSize
)
1284 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1288 if (hKey
!= INVALID_HANDLE_VALUE
)
1290 HeapFree(GetProcessHeap(), 0, PropPageProvider
);
1291 FreeFunctionPointer(hModule
, pPropPageProvider
);
1294 TRACE("Returning %d\n", ret
);