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"
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
;
491 /* Get list of all class GUIDs in given computer */
492 ret
= SetupDiBuildClassInfoListExW(
499 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
502 size
= sizeof(struct ClassImageList
)
503 + (sizeof(GUID
) + sizeof(INT
)) * RequiredSize
;
504 list
= HeapAlloc(GetProcessHeap(), 0, size
);
507 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
510 list
->magic
= SETUP_CLASS_IMAGE_LIST_MAGIC
;
511 list
->NumberOfGuids
= RequiredSize
;
512 list
->Guids
= (GUID
*)(list
+ 1);
513 list
->IconIndexes
= (INT
*)((ULONG_PTR
)(list
+ 1) + sizeof(GUID
) * RequiredSize
);
515 ret
= SetupDiBuildClassInfoListExW(
524 else if (RequiredSize
!= list
->NumberOfGuids
)
526 /* Hm. Class list changed since last call. Ignore
527 * this case as it should be very rare */
528 SetLastError(ERROR_GEN_FAILURE
);
533 /* Prepare a HIMAGELIST */
534 InitCommonControls();
540 bpp
= GetDeviceCaps(hDC
, BITSPIXEL
);
541 ReleaseDC(NULL
, hDC
);
548 ilMask
= ILC_COLOR16
;
550 ilMask
= ILC_COLOR24
;
552 ilMask
= ILC_COLOR32
;
558 ClassImageListData
->ImageList
= ImageList_Create(16, 16, ilMask
, 100, 10);
559 if (!ClassImageListData
->ImageList
)
562 ClassImageListData
->Reserved
= (ULONG_PTR
)list
;
564 /* For some reason, Windows sets the list background to COLOR_WINDOW */
565 bkColor
= GetSysColor(COLOR_WINDOW
);
566 ImageList_SetBkColor(ClassImageListData
->ImageList
, bkColor
);
568 /* Now, we "simply" need to load icons associated with all class guids,
569 * and put their index in the image list in the IconIndexes array */
570 for (i
= 0; i
< list
->NumberOfGuids
; i
++)
574 ret
= SetupDiLoadClassIcon(
580 hIcon
= LoadImage(hInstance
, MAKEINTRESOURCE(miniIconIndex
), IMAGE_ICON
, 16, 16, LR_DEFAULTCOLOR
);
583 list
->IconIndexes
[i
] = ImageList_AddIcon(ClassImageListData
->ImageList
, hIcon
);
587 list
->IconIndexes
[i
] = -1;
590 list
->IconIndexes
[i
] = -1; /* Special value to indicate that the icon is unavailable */
593 /* Finally, add the overlay icons to the image list */
594 for (i
= 0; i
< 2; i
++)
596 hIcon
= LoadImage(hInstance
, MAKEINTRESOURCE(500 + i
), IMAGE_ICON
, 16, 16, LR_DEFAULTCOLOR
);
599 idx
= ImageList_AddIcon(ClassImageListData
->ImageList
, hIcon
);
601 ImageList_SetOverlayImage(ClassImageListData
->ImageList
, idx
, i
);
611 if (ClassImageListData
->Reserved
)
612 SetupDiDestroyClassImageList(ClassImageListData
);
618 TRACE("Returning %d\n", ret
);
622 /***********************************************************************
623 * SetupDiGetClassInstallParamsA(SETUPAPI.@)
626 SetupDiGetClassInstallParamsA(
627 IN HDEVINFO DeviceInfoSet
,
628 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
629 OUT PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
630 IN DWORD ClassInstallParamsSize
,
631 OUT PDWORD RequiredSize OPTIONAL
)
633 FIXME("SetupDiGetClassInstallParamsA(%p %p %p %lu %p) Stub\n",
634 DeviceInfoSet
, DeviceInfoData
, ClassInstallParams
, ClassInstallParamsSize
, RequiredSize
);
638 /***********************************************************************
639 * SetupDiGetClassInstallParamsW(SETUPAPI.@)
642 SetupDiGetClassInstallParamsW(
643 IN HDEVINFO DeviceInfoSet
,
644 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
645 OUT PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
646 IN DWORD ClassInstallParamsSize
,
647 OUT PDWORD RequiredSize OPTIONAL
)
649 FIXME("SetupDiGetClassInstallParamsW(%p %p %p %lu %p) Stub\n",
650 DeviceInfoSet
, DeviceInfoData
, ClassInstallParams
, ClassInstallParamsSize
, RequiredSize
);
654 /***********************************************************************
655 * SetupDiLoadClassIcon(SETUPAPI.@)
658 SetupDiLoadClassIcon(
659 IN CONST GUID
*ClassGuid
,
660 OUT HICON
*LargeIcon OPTIONAL
,
661 OUT PINT MiniIconIndex OPTIONAL
)
663 LPWSTR Buffer
= NULL
;
666 HKEY hKey
= INVALID_HANDLE_VALUE
;
672 hKey
= SetupDiOpenClassRegKey(ClassGuid
, KEY_QUERY_VALUE
);
673 if (hKey
!= INVALID_HANDLE_VALUE
)
674 SETUP_GetIconIndex(hKey
, &iconIndex
);
679 /* Look up icon in dll specified by Installer32 or EnumPropPages32 key */
682 DWORD dwRegType
, dwLength
;
683 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_INSTALLER_32
, NULL
, &dwRegType
, NULL
, &dwLength
);
684 if (rc
== ERROR_SUCCESS
&& dwRegType
== REG_SZ
)
686 Buffer
= MyMalloc(dwLength
+ sizeof(WCHAR
));
689 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
692 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_INSTALLER_32
, NULL
, NULL
, (LPBYTE
)Buffer
, &dwLength
);
693 if (rc
!= ERROR_SUCCESS
)
698 /* make sure the returned buffer is NULL-terminated */
699 Buffer
[dwLength
/ sizeof(WCHAR
)] = 0;
702 (ERROR_SUCCESS
== (rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, &dwRegType
, NULL
, &dwLength
))
703 && dwRegType
== REG_SZ
)
705 Buffer
= MyMalloc(dwLength
+ sizeof(WCHAR
));
708 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
711 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, NULL
, (LPBYTE
)Buffer
, &dwLength
);
712 if (rc
!= ERROR_SUCCESS
)
717 /* make sure the returned buffer is NULL-terminated */
718 Buffer
[dwLength
/ sizeof(WCHAR
)] = 0;
722 /* Unable to find where to load the icon */
723 SetLastError(ERROR_FILE_NOT_FOUND
);
726 Comma
= strchrW(Buffer
, ',');
729 SetLastError(ERROR_GEN_FAILURE
);
737 /* Look up icon in setupapi.dll */
738 DllName
= SetupapiDll
;
739 iconIndex
= -iconIndex
;
742 TRACE("Icon index %d, dll name %s\n", iconIndex
, debugstr_w(DllName
));
745 *LargeIcon
= LoadImage(hInstance
, MAKEINTRESOURCE(iconIndex
), IMAGE_ICON
, 32, 32, LR_DEFAULTCOLOR
);
748 SetLastError(ERROR_INVALID_INDEX
);
753 *MiniIconIndex
= iconIndex
;
757 if (hKey
!= INVALID_HANDLE_VALUE
)
763 TRACE("Returning %d\n", ret
);
767 /***********************************************************************
768 * SetupDiInstallClassExW (SETUPAPI.@)
771 SETUP_CreateClassKey(HINF hInf
);
773 SetupDiInstallClassExW(
774 IN HWND hwndParent OPTIONAL
,
775 IN PCWSTR InfFileName OPTIONAL
,
777 IN HSPFILEQ FileQueue OPTIONAL
,
778 IN CONST GUID
*InterfaceClassGuid OPTIONAL
,
784 TRACE("%p %s 0x%lx %p %s %p %p\n", hwndParent
, debugstr_w(InfFileName
), Flags
,
785 FileQueue
, debugstr_guid(InterfaceClassGuid
), Reserved1
, Reserved2
);
789 FIXME("Case not implemented: InfFileName NULL\n");
790 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
792 else if (Flags
& ~(DI_NOVCP
| DI_NOBROWSE
| DI_FORCECOPY
| DI_QUIETINSTALL
))
794 TRACE("Unknown flags: 0x%08lx\n", Flags
& ~(DI_NOVCP
| DI_NOBROWSE
| DI_FORCECOPY
| DI_QUIETINSTALL
));
795 SetLastError(ERROR_INVALID_FLAGS
);
797 else if ((Flags
& DI_NOVCP
) && FileQueue
== NULL
)
798 SetLastError(ERROR_INVALID_PARAMETER
);
799 else if (Reserved1
!= NULL
)
800 SetLastError(ERROR_INVALID_PARAMETER
);
801 else if (Reserved2
!= NULL
)
802 SetLastError(ERROR_INVALID_PARAMETER
);
805 HDEVINFO hDeviceInfo
= INVALID_HANDLE_VALUE
;
806 SP_DEVINSTALL_PARAMS_W InstallParams
;
807 WCHAR SectionName
[MAX_PATH
];
808 HINF hInf
= INVALID_HANDLE_VALUE
;
809 HKEY hRootKey
= INVALID_HANDLE_VALUE
;
810 PVOID callback_context
= NULL
;
812 hDeviceInfo
= SetupDiCreateDeviceInfoList(NULL
, NULL
);
813 if (hDeviceInfo
== INVALID_HANDLE_VALUE
)
816 InstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS
);
817 if (!SetupDiGetDeviceInstallParamsW(hDeviceInfo
, NULL
, &InstallParams
))
819 InstallParams
.Flags
&= ~(DI_NOVCP
| DI_NOBROWSE
| DI_QUIETINSTALL
);
820 InstallParams
.Flags
|= Flags
& (DI_NOVCP
| DI_NOBROWSE
| DI_QUIETINSTALL
);
821 if (Flags
& DI_NOVCP
)
822 InstallParams
.FileQueue
= FileQueue
;
823 if (!SetupDiSetDeviceInstallParamsW(hDeviceInfo
, NULL
, &InstallParams
))
826 /* Open the .inf file */
827 hInf
= SetupOpenInfFileW(
832 if (hInf
== INVALID_HANDLE_VALUE
)
835 /* Try to append a layout file */
836 SetupOpenAppendInfFileW(NULL
, hInf
, NULL
);
838 if (InterfaceClassGuid
)
840 /* Retrieve the actual section name */
841 ret
= SetupDiGetActualSectionToInstallW(
851 /* Open registry key related to this interface */
852 /* FIXME: What happens if the key doesn't exist? */
853 hRootKey
= SetupDiOpenClassRegKeyExW(InterfaceClassGuid
, KEY_ENUMERATE_SUB_KEYS
, DIOCR_INTERFACE
, NULL
, NULL
);
854 if (hRootKey
== INVALID_HANDLE_VALUE
)
857 /* SetupDiCreateDeviceInterface??? */
858 FIXME("Installing an interface is not implemented\n");
859 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
863 /* Create or open the class registry key 'HKLM\CurrentControlSet\Class\{GUID}' */
864 hRootKey
= SETUP_CreateClassKey(hInf
);
865 if (hRootKey
== INVALID_HANDLE_VALUE
)
868 /* Retrieve the actual section name */
869 ret
= SetupDiGetActualSectionToInstallW(
873 MAX_PATH
- strlenW(DotServices
),
879 callback_context
= SetupInitDefaultQueueCallback(hwndParent
);
880 if (!callback_context
)
883 ret
= SetupInstallFromInfSectionW(
887 SPINST_REGISTRY
| SPINST_FILES
| SPINST_BITREG
| SPINST_INIFILES
| SPINST_INI2REG
,
889 NULL
, /* FIXME: SourceRootPath */
890 !(Flags
& DI_NOVCP
) && (Flags
& DI_FORCECOPY
) ? SP_COPY_FORCE_IN_USE
: 0, /* CopyFlags */
891 SetupDefaultQueueCallbackW
,
898 /* Install .Services section */
899 lstrcatW(SectionName
, DotServices
);
900 ret
= SetupInstallServicesFromInfSectionExW(
915 if (hDeviceInfo
!= INVALID_HANDLE_VALUE
)
916 SetupDiDestroyDeviceInfoList(hDeviceInfo
);
917 if (hInf
!= INVALID_HANDLE_VALUE
)
918 SetupCloseInfFile(hInf
);
919 if (hRootKey
!= INVALID_HANDLE_VALUE
)
920 RegCloseKey(hRootKey
);
921 SetupTermDefaultQueueCallback(callback_context
);
924 TRACE("Returning %d\n", ret
);
928 /***********************************************************************
929 * Helper functions for SetupDiSetClassInstallParamsW
932 SETUP_PropertyChangeHandler(
933 IN HDEVINFO DeviceInfoSet
,
934 IN PSP_DEVINFO_DATA DeviceInfoData
,
935 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
936 IN DWORD ClassInstallParamsSize
)
938 PSP_PROPCHANGE_PARAMS PropChangeParams
= (PSP_PROPCHANGE_PARAMS
)ClassInstallParams
;
942 SetLastError(ERROR_INVALID_PARAMETER
);
943 else if (ClassInstallParamsSize
!= sizeof(SP_PROPCHANGE_PARAMS
))
944 SetLastError(ERROR_INVALID_PARAMETER
);
945 else if (PropChangeParams
&& PropChangeParams
->StateChange
!= DICS_ENABLE
946 && PropChangeParams
->StateChange
!= DICS_DISABLE
&& PropChangeParams
->StateChange
!= DICS_PROPCHANGE
947 && PropChangeParams
->StateChange
!= DICS_START
&& PropChangeParams
->StateChange
!= DICS_STOP
)
948 SetLastError(ERROR_INVALID_FLAGS
);
949 else if (PropChangeParams
&& PropChangeParams
->Scope
!= DICS_FLAG_GLOBAL
950 && PropChangeParams
->Scope
!= DICS_FLAG_CONFIGSPECIFIC
)
951 SetLastError(ERROR_INVALID_FLAGS
);
952 else if (PropChangeParams
953 && (PropChangeParams
->StateChange
== DICS_START
|| PropChangeParams
->StateChange
== DICS_STOP
)
954 && PropChangeParams
->Scope
!= DICS_FLAG_CONFIGSPECIFIC
)
955 SetLastError(ERROR_INVALID_USER_BUFFER
);
958 PSP_PROPCHANGE_PARAMS
*CurrentPropChangeParams
;
959 struct DeviceInfo
*deviceInfo
= (struct DeviceInfo
*)DeviceInfoData
->Reserved
;
960 CurrentPropChangeParams
= &deviceInfo
->ClassInstallParams
.PropChangeParams
;
962 if (*CurrentPropChangeParams
)
964 MyFree(*CurrentPropChangeParams
);
965 *CurrentPropChangeParams
= NULL
;
967 if (PropChangeParams
)
969 *CurrentPropChangeParams
= MyMalloc(ClassInstallParamsSize
);
970 if (!*CurrentPropChangeParams
)
972 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
975 memcpy(*CurrentPropChangeParams
, PropChangeParams
, ClassInstallParamsSize
);
985 SETUP_PropertyAddPropertyAdvancedHandler(
986 IN HDEVINFO DeviceInfoSet
,
987 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
988 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
989 IN DWORD ClassInstallParamsSize
)
991 PSP_ADDPROPERTYPAGE_DATA AddPropertyPageData
= (PSP_ADDPROPERTYPAGE_DATA
)ClassInstallParams
;
994 if (ClassInstallParamsSize
!= sizeof(SP_PROPCHANGE_PARAMS
))
995 SetLastError(ERROR_INVALID_PARAMETER
);
996 else if (AddPropertyPageData
&& AddPropertyPageData
->Flags
!= 0)
997 SetLastError(ERROR_INVALID_FLAGS
);
998 else if (AddPropertyPageData
&& AddPropertyPageData
->NumDynamicPages
>= MAX_INSTALLWIZARD_DYNAPAGES
)
999 SetLastError(ERROR_INVALID_USER_BUFFER
);
1002 PSP_ADDPROPERTYPAGE_DATA
*CurrentAddPropertyPageData
;
1003 if (!DeviceInfoData
)
1005 struct DeviceInfoSet
*list
= (struct DeviceInfoSet
*)DeviceInfoSet
;
1006 CurrentAddPropertyPageData
= &list
->ClassInstallParams
.AddPropertyPageData
;
1010 struct DeviceInfo
*deviceInfo
= (struct DeviceInfo
*)DeviceInfoData
->Reserved
;
1011 CurrentAddPropertyPageData
= &deviceInfo
->ClassInstallParams
.AddPropertyPageData
;
1013 if (*CurrentAddPropertyPageData
)
1015 MyFree(*CurrentAddPropertyPageData
);
1016 *CurrentAddPropertyPageData
= NULL
;
1018 if (AddPropertyPageData
)
1020 *CurrentAddPropertyPageData
= MyMalloc(ClassInstallParamsSize
);
1021 if (!*CurrentAddPropertyPageData
)
1023 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1026 memcpy(*CurrentAddPropertyPageData
, AddPropertyPageData
, ClassInstallParamsSize
);
1035 /***********************************************************************
1036 * SetupDiSetClassInstallParamsW (SETUPAPI.@)
1039 SetupDiSetClassInstallParamsW(
1040 IN HDEVINFO DeviceInfoSet
,
1041 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
1042 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
1043 IN DWORD ClassInstallParamsSize
)
1045 struct DeviceInfoSet
*list
;
1048 TRACE("%p %p %p %lu\n", DeviceInfoSet
, DeviceInfoData
,
1049 ClassInstallParams
, ClassInstallParamsSize
);
1052 SetLastError(ERROR_INVALID_PARAMETER
);
1053 else if (DeviceInfoSet
== (HDEVINFO
)INVALID_HANDLE_VALUE
)
1054 SetLastError(ERROR_INVALID_HANDLE
);
1055 else if ((list
= (struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEVICE_INFO_SET_MAGIC
)
1056 SetLastError(ERROR_INVALID_HANDLE
);
1057 else if (DeviceInfoData
&& DeviceInfoData
->cbSize
!= sizeof(SP_DEVINFO_DATA
))
1058 SetLastError(ERROR_INVALID_USER_BUFFER
);
1059 else if (ClassInstallParams
&& ClassInstallParams
->cbSize
!= sizeof(SP_CLASSINSTALL_HEADER
))
1060 SetLastError(ERROR_INVALID_USER_BUFFER
);
1061 else if (ClassInstallParams
&& ClassInstallParamsSize
< sizeof(SP_CLASSINSTALL_HEADER
))
1062 SetLastError(ERROR_INVALID_PARAMETER
);
1063 else if (!ClassInstallParams
&& ClassInstallParamsSize
!= 0)
1064 SetLastError(ERROR_INVALID_PARAMETER
);
1067 SP_DEVINSTALL_PARAMS_W InstallParams
;
1070 InstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS_W
);
1071 Result
= SetupDiGetDeviceInstallParamsW(DeviceInfoSet
, DeviceInfoData
, &InstallParams
);
1075 if (ClassInstallParams
)
1078 /* Check parameters in ClassInstallParams */
1079 for (i
= 0; i
< sizeof(InstallParamsData
) / sizeof(InstallParamsData
[0]); i
++)
1081 if (InstallParamsData
[i
].Function
== ClassInstallParams
->InstallFunction
)
1083 ret
= InstallParamsData
[i
].UpdateHandler(
1087 ClassInstallParamsSize
);
1090 InstallParams
.Flags
|= DI_CLASSINSTALLPARAMS
;
1091 ret
= SetupDiSetDeviceInstallParamsW(DeviceInfoSet
, DeviceInfoData
, &InstallParams
);
1096 ERR("InstallFunction %u has no associated update handler\n", ClassInstallParams
->InstallFunction
);
1097 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1102 InstallParams
.Flags
&= ~DI_CLASSINSTALLPARAMS
;
1103 ret
= SetupDiSetDeviceInstallParamsW(DeviceInfoSet
, DeviceInfoData
, &InstallParams
);
1108 TRACE("Returning %d\n", ret
);
1112 /***********************************************************************
1113 * SetupDiGetClassDevPropertySheetsA(SETUPAPI.@)
1116 SetupDiGetClassDevPropertySheetsA(
1117 IN HDEVINFO DeviceInfoSet
,
1118 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
1119 IN LPPROPSHEETHEADERA PropertySheetHeader
,
1120 IN DWORD PropertySheetHeaderPageListSize
,
1121 OUT PDWORD RequiredSize OPTIONAL
,
1122 IN DWORD PropertySheetType
)
1124 PROPSHEETHEADERW psh
;
1127 TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet
, DeviceInfoData
,
1128 PropertySheetHeader
, PropertySheetHeaderPageListSize
,
1129 RequiredSize
, PropertySheetType
);
1131 psh
.dwFlags
= PropertySheetHeader
->dwFlags
;
1132 psh
.phpage
= PropertySheetHeader
->phpage
;
1133 psh
.nPages
= PropertySheetHeader
->nPages
;
1135 ret
= SetupDiGetClassDevPropertySheetsW(DeviceInfoSet
, DeviceInfoData
, PropertySheetHeader
? &psh
: NULL
,
1136 PropertySheetHeaderPageListSize
, RequiredSize
,
1140 PropertySheetHeader
->nPages
= psh
.nPages
;
1143 TRACE("Returning %d\n", ret
);
1147 struct ClassDevPropertySheetsData
1149 LPPROPSHEETHEADERW PropertySheetHeader
;
1150 DWORD PropertySheetHeaderPageListSize
;
1151 DWORD NumberOfPages
;
1156 SETUP_GetClassDevPropertySheetsCallback(
1157 IN HPROPSHEETPAGE hPropSheetPage
,
1158 IN OUT LPARAM lParam
)
1160 struct ClassDevPropertySheetsData
*PropPageData
;
1162 PropPageData
= (struct ClassDevPropertySheetsData
*)lParam
;
1164 PropPageData
->NumberOfPages
++;
1166 if (PropPageData
->PropertySheetHeader
->nPages
< PropPageData
->PropertySheetHeaderPageListSize
)
1168 PropPageData
->PropertySheetHeader
->phpage
[PropPageData
->PropertySheetHeader
->nPages
] = hPropSheetPage
;
1169 PropPageData
->PropertySheetHeader
->nPages
++;
1173 return PropPageData
->DontCancel
;
1176 /***********************************************************************
1177 * SetupDiGetClassDevPropertySheetsW(SETUPAPI.@)
1180 SetupDiGetClassDevPropertySheetsW(
1181 IN HDEVINFO DeviceInfoSet
,
1182 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
1183 IN OUT LPPROPSHEETHEADERW PropertySheetHeader
,
1184 IN DWORD PropertySheetHeaderPageListSize
,
1185 OUT PDWORD RequiredSize OPTIONAL
,
1186 IN DWORD PropertySheetType
)
1188 struct DeviceInfoSet
*list
;
1191 TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet
, DeviceInfoData
,
1192 PropertySheetHeader
, PropertySheetHeaderPageListSize
,
1193 RequiredSize
, PropertySheetType
);
1196 SetLastError(ERROR_INVALID_HANDLE
);
1197 else if (((struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEVICE_INFO_SET_MAGIC
)
1198 SetLastError(ERROR_INVALID_HANDLE
);
1199 else if ((list
= (struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEVICE_INFO_SET_MAGIC
)
1200 SetLastError(ERROR_INVALID_HANDLE
);
1201 else if (!PropertySheetHeader
)
1202 SetLastError(ERROR_INVALID_PARAMETER
);
1203 else if (PropertySheetHeader
->dwFlags
& PSH_PROPSHEETPAGE
)
1204 SetLastError(ERROR_INVALID_FLAGS
);
1205 else if (DeviceInfoData
&& DeviceInfoData
->cbSize
!= sizeof(SP_DEVINFO_DATA
))
1206 SetLastError(ERROR_INVALID_USER_BUFFER
);
1207 else if (!DeviceInfoData
&& IsEqualIID(&list
->ClassGuid
, &GUID_NULL
))
1208 SetLastError(ERROR_INVALID_PARAMETER
);
1209 else if (PropertySheetType
!= DIGCDP_FLAG_ADVANCED
1210 && PropertySheetType
!= DIGCDP_FLAG_BASIC
1211 && PropertySheetType
!= DIGCDP_FLAG_REMOTE_ADVANCED
1212 && PropertySheetType
!= DIGCDP_FLAG_REMOTE_BASIC
)
1213 SetLastError(ERROR_INVALID_PARAMETER
);
1216 HKEY hKey
= INVALID_HANDLE_VALUE
;
1217 SP_PROPSHEETPAGE_REQUEST Request
;
1218 LPWSTR PropPageProvider
= NULL
;
1219 HMODULE hModule
= NULL
;
1220 PROPERTY_PAGE_PROVIDER pPropPageProvider
= NULL
;
1221 struct ClassDevPropertySheetsData PropPageData
;
1222 DWORD dwLength
, dwRegType
;
1223 DWORD InitialNumberOfPages
;
1227 hKey
= SetupDiOpenDevRegKey(DeviceInfoSet
, DeviceInfoData
, DICS_FLAG_GLOBAL
, 0, DIREG_DRV
, KEY_QUERY_VALUE
);
1230 hKey
= SetupDiOpenClassRegKeyExW(&list
->ClassGuid
, KEY_QUERY_VALUE
,
1231 DIOCR_INSTALLER
, list
->MachineName
+ 2, NULL
);
1233 if (hKey
== INVALID_HANDLE_VALUE
)
1236 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, &dwRegType
, NULL
, &dwLength
);
1237 if (rc
== ERROR_FILE_NOT_FOUND
)
1239 /* No registry key. As it is optional, don't say it's a bad error */
1245 else if (rc
!= ERROR_SUCCESS
&& dwRegType
!= REG_SZ
)
1251 PropPageProvider
= HeapAlloc(GetProcessHeap(), 0, dwLength
+ sizeof(WCHAR
));
1252 if (!PropPageProvider
)
1254 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1257 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, NULL
, (LPBYTE
)PropPageProvider
, &dwLength
);
1258 if (rc
!= ERROR_SUCCESS
)
1263 PropPageProvider
[dwLength
/ sizeof(WCHAR
)] = 0;
1265 rc
= GetFunctionPointer(PropPageProvider
, &hModule
, (PVOID
*)&pPropPageProvider
);
1266 if (rc
!= ERROR_SUCCESS
)
1268 SetLastError(ERROR_INVALID_PROPPAGE_PROVIDER
);
1274 struct DeviceInfo
*devInfo
= (struct DeviceInfo
*)DeviceInfoData
->Reserved
;
1275 devInfo
->hmodDevicePropPageProvider
= hModule
;
1276 devInfo
->pDevicePropPageProvider
= pPropPageProvider
;
1280 struct DeviceInfoSet
*devInfoSet
= (struct DeviceInfoSet
*)DeviceInfoSet
;
1281 devInfoSet
->hmodClassPropPageProvider
= hModule
;
1282 devInfoSet
->pClassPropPageProvider
= pPropPageProvider
;
1285 InitialNumberOfPages
= PropertySheetHeader
->nPages
;
1287 Request
.cbSize
= sizeof(SP_PROPSHEETPAGE_REQUEST
);
1288 Request
.PageRequested
= SPPSR_ENUM_ADV_DEVICE_PROPERTIES
;
1289 Request
.DeviceInfoSet
= DeviceInfoSet
;
1290 Request
.DeviceInfoData
= DeviceInfoData
;
1292 PropPageData
.PropertySheetHeader
= PropertySheetHeader
;
1293 PropPageData
.PropertySheetHeaderPageListSize
= PropertySheetHeaderPageListSize
;
1294 PropPageData
.NumberOfPages
= 0;
1295 PropPageData
.DontCancel
= (RequiredSize
!= NULL
) ? TRUE
: FALSE
;
1297 pPropPageProvider(&Request
, SETUP_GetClassDevPropertySheetsCallback
, (LPARAM
)&PropPageData
);
1300 *RequiredSize
= PropPageData
.NumberOfPages
;
1302 if (InitialNumberOfPages
+ PropPageData
.NumberOfPages
<= PropertySheetHeaderPageListSize
)
1308 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1312 if (hKey
!= INVALID_HANDLE_VALUE
)
1314 HeapFree(GetProcessHeap(), 0, PropPageProvider
);
1317 TRACE("Returning %d\n", ret
);