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"
28 /* Unicode constants */
29 static const WCHAR BackSlash
[] = {'\\',0};
30 static const WCHAR Class
[] = {'C','l','a','s','s',0};
31 static const WCHAR ClassGUID
[] = {'C','l','a','s','s','G','U','I','D',0};
32 static const WCHAR ClassInstall32
[] = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
33 static const WCHAR DotServices
[] = {'.','S','e','r','v','i','c','e','s',0};
34 static const WCHAR InterfaceInstall32
[] = {'I','n','t','e','r','f','a','c','e','I','n','s','t','a','l','l','3','2',0};
35 static const WCHAR SetupapiDll
[] = {'s','e','t','u','p','a','p','i','.','d','l','l',0};
36 static const WCHAR Version
[] = {'V','e','r','s','i','o','n',0};
39 (WINAPI
* PROPERTY_PAGE_PROVIDER
) (
40 IN PSP_PROPSHEETPAGE_REQUEST PropPageRequest
,
41 IN LPFNADDPROPSHEETPAGE fAddFunc
,
44 (*UPDATE_CLASS_PARAM_HANDLER
) (
45 IN HDEVINFO DeviceInfoSet
,
46 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
47 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
48 IN DWORD ClassInstallParamsSize
);
51 SETUP_PropertyChangeHandler(
52 IN HDEVINFO DeviceInfoSet
,
53 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
54 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
55 IN DWORD ClassInstallParamsSize
);
58 SETUP_PropertyAddPropertyAdvancedHandler(
59 IN HDEVINFO DeviceInfoSet
,
60 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
61 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
62 IN DWORD ClassInstallParamsSize
);
64 typedef struct _INSTALL_PARAMS_DATA
67 UPDATE_CLASS_PARAM_HANDLER UpdateHandler
;
70 } INSTALL_PARAMS_DATA
;
72 #define ADD_PARAM_HANDLER(Function, UpdateHandler, ParamsType, ParamsField) \
73 { Function, UpdateHandler, sizeof(ParamsType), FIELD_OFFSET(struct ClassInstallParams, ParamsField) },
75 static const INSTALL_PARAMS_DATA InstallParamsData
[] = {
76 ADD_PARAM_HANDLER(DIF_PROPERTYCHANGE
, SETUP_PropertyChangeHandler
, SP_PROPCHANGE_PARAMS
, PropChangeParams
)
77 ADD_PARAM_HANDLER(DIF_ADDPROPERTYPAGE_ADVANCED
, SETUP_PropertyAddPropertyAdvancedHandler
, SP_ADDPROPERTYPAGE_DATA
, AddPropertyPageData
)
79 #undef ADD_PARAM_HANDLER
81 #define UNKNOWN_ICON_INDEX 18
83 /***********************************************************************
84 * SetupDiDestroyClassImageList(SETUPAPI.@)
87 SetupDiDestroyClassImageList(
88 IN PSP_CLASSIMAGELIST_DATA ClassImageListData
)
90 struct ClassImageList
*list
;
93 TRACE("%p\n", ClassImageListData
);
95 if (!ClassImageListData
)
96 SetLastError(ERROR_INVALID_PARAMETER
);
97 else if (ClassImageListData
->cbSize
!= sizeof(SP_CLASSIMAGELIST_DATA
))
98 SetLastError(ERROR_INVALID_USER_BUFFER
);
99 else if ((list
= (struct ClassImageList
*)ClassImageListData
->Reserved
) == NULL
)
100 SetLastError(ERROR_INVALID_USER_BUFFER
);
101 else if (list
->magic
!= SETUP_CLASS_IMAGE_LIST_MAGIC
)
102 SetLastError(ERROR_INVALID_USER_BUFFER
);
105 /* If Reserved wasn't NULL, then this is valid too */
106 if (ClassImageListData
->ImageList
)
108 ImageList_Destroy(ClassImageListData
->ImageList
);
109 ClassImageListData
->ImageList
= NULL
;
113 ClassImageListData
->Reserved
= 0;
118 TRACE("Returning %d\n", ret
);
122 /***********************************************************************
123 * SETUP_CreateDevicesListFromEnumerator
126 * list [IO] Device info set to fill with discovered devices.
127 * pClassGuid [I] If specified, only devices which belong to this class will be added.
128 * Enumerator [I] Location to search devices to add.
129 * hEnumeratorKey [I] Registry key corresponding to Enumerator key. Must have KEY_ENUMERATE_SUB_KEYS right.
132 * Success: ERROR_SUCCESS.
133 * Failure: an error code.
136 SETUP_CreateDevicesListFromEnumerator(
137 IN OUT
struct DeviceInfoSet
*list
,
138 IN CONST GUID
*pClassGuid OPTIONAL
,
139 IN LPCWSTR Enumerator
,
140 IN HKEY hEnumeratorKey
) /* handle to Enumerator registry key */
142 HKEY hDeviceIdKey
= NULL
, hInstanceIdKey
;
143 WCHAR KeyBuffer
[MAX_PATH
];
144 WCHAR InstancePath
[MAX_PATH
];
145 LPWSTR pEndOfInstancePath
; /* Pointer into InstancePath buffer */
146 struct DeviceInfo
*deviceInfo
;
148 DWORD dwLength
, dwRegType
;
151 /* Enumerate device IDs (subkeys of hEnumeratorKey) */
154 dwLength
= sizeof(KeyBuffer
) / sizeof(KeyBuffer
[0]);
155 rc
= RegEnumKeyExW(hEnumeratorKey
, i
, KeyBuffer
, &dwLength
, NULL
, NULL
, NULL
, NULL
);
156 if (rc
== ERROR_NO_MORE_ITEMS
)
158 if (rc
!= ERROR_SUCCESS
)
162 /* Open device id sub key */
163 if (hDeviceIdKey
!= NULL
)
164 RegCloseKey(hDeviceIdKey
);
165 rc
= RegOpenKeyExW(hEnumeratorKey
, KeyBuffer
, 0, KEY_ENUMERATE_SUB_KEYS
, &hDeviceIdKey
);
166 if (rc
!= ERROR_SUCCESS
)
169 if (FAILED(StringCchCopyW(InstancePath
, _countof(InstancePath
), Enumerator
)) ||
170 FAILED(StringCchCatW(InstancePath
, _countof(InstancePath
), BackSlash
)) ||
171 FAILED(StringCchCatW(InstancePath
, _countof(InstancePath
), KeyBuffer
)) ||
172 FAILED(StringCchCatW(InstancePath
, _countof(InstancePath
), BackSlash
)))
174 rc
= ERROR_GEN_FAILURE
;
178 pEndOfInstancePath
= &InstancePath
[strlenW(InstancePath
)];
180 /* Enumerate instance IDs (subkeys of hDeviceIdKey) */
186 dwLength
= sizeof(KeyBuffer
) / sizeof(KeyBuffer
[0]);
187 rc
= RegEnumKeyExW(hDeviceIdKey
, j
, KeyBuffer
, &dwLength
, NULL
, NULL
, NULL
, NULL
);
188 if (rc
== ERROR_NO_MORE_ITEMS
)
190 if (rc
!= ERROR_SUCCESS
)
194 /* Open instance id sub key */
195 rc
= RegOpenKeyExW(hDeviceIdKey
, KeyBuffer
, 0, KEY_QUERY_VALUE
, &hInstanceIdKey
);
196 if (rc
!= ERROR_SUCCESS
)
198 *pEndOfInstancePath
= '\0';
199 strcatW(InstancePath
, KeyBuffer
);
201 /* Read ClassGUID value */
202 dwLength
= sizeof(KeyBuffer
) - sizeof(WCHAR
);
203 rc
= RegQueryValueExW(hInstanceIdKey
, ClassGUID
, NULL
, &dwRegType
, (LPBYTE
)KeyBuffer
, &dwLength
);
204 RegCloseKey(hInstanceIdKey
);
205 if (rc
== ERROR_FILE_NOT_FOUND
)
208 /* Skip this bad entry as we can't verify it */
210 /* Set a default GUID for this device */
211 memcpy(&KeyGuid
, &GUID_NULL
, sizeof(GUID
));
213 else if (rc
!= ERROR_SUCCESS
)
217 else if (dwRegType
!= REG_SZ
|| dwLength
< MAX_GUID_STRING_LEN
* sizeof(WCHAR
))
219 rc
= ERROR_GEN_FAILURE
;
224 KeyBuffer
[MAX_GUID_STRING_LEN
- 2] = '\0'; /* Replace the } by a NULL character */
225 if (UuidFromStringW(&KeyBuffer
[1], &KeyGuid
) != RPC_S_OK
)
226 /* Bad GUID, skip the entry */
230 if (pClassGuid
&& !IsEqualIID(&KeyGuid
, pClassGuid
))
232 /* Skip this entry as it is not the right device class */
236 /* Add the entry to the list */
237 if (!CreateDeviceInfo(list
, InstancePath
, &KeyGuid
, &deviceInfo
))
242 TRACE("Adding '%s' to device info set %p\n", debugstr_w(InstancePath
), list
);
243 InsertTailList(&list
->ListHead
, &deviceInfo
->ListEntry
);
250 if (hDeviceIdKey
!= NULL
)
251 RegCloseKey(hDeviceIdKey
);
256 SETUP_CreateDevicesList(
257 IN OUT
struct DeviceInfoSet
*list
,
258 IN PCWSTR MachineName OPTIONAL
,
259 IN CONST GUID
*Class OPTIONAL
,
260 IN PCWSTR Enumerator OPTIONAL
)
262 HKEY HKLM
= HKEY_LOCAL_MACHINE
;
263 HKEY hEnumKey
= NULL
;
264 HKEY hEnumeratorKey
= NULL
;
265 WCHAR KeyBuffer
[MAX_PATH
];
270 if (Class
&& IsEqualIID(Class
, &GUID_NULL
))
273 /* Open Enum key (if applicable) */
274 if (MachineName
!= NULL
)
276 rc
= RegConnectRegistryW(MachineName
, HKEY_LOCAL_MACHINE
, &HKLM
);
277 if (rc
!= ERROR_SUCCESS
)
283 REGSTR_PATH_SYSTEMENUM
,
285 KEY_ENUMERATE_SUB_KEYS
,
287 if (rc
!= ERROR_SUCCESS
)
290 /* If enumerator is provided, call directly SETUP_CreateDevicesListFromEnumerator.
291 * Else, enumerate all enumerators and call SETUP_CreateDevicesListFromEnumerator
300 KEY_ENUMERATE_SUB_KEYS
,
302 if (rc
!= ERROR_SUCCESS
)
304 if (rc
== ERROR_FILE_NOT_FOUND
)
305 rc
= ERROR_INVALID_DATA
;
308 rc
= SETUP_CreateDevicesListFromEnumerator(list
, Class
, Enumerator
, hEnumeratorKey
);
312 /* Enumerate enumerators */
316 dwLength
= sizeof(KeyBuffer
) / sizeof(KeyBuffer
[0]);
317 rc
= RegEnumKeyExW(hEnumKey
, i
, KeyBuffer
, &dwLength
, NULL
, NULL
, NULL
, NULL
);
318 if (rc
== ERROR_NO_MORE_ITEMS
)
320 else if (rc
!= ERROR_SUCCESS
)
325 if (hEnumeratorKey
!= NULL
)
326 RegCloseKey(hEnumeratorKey
);
327 rc
= RegOpenKeyExW(hEnumKey
, KeyBuffer
, 0, KEY_ENUMERATE_SUB_KEYS
, &hEnumeratorKey
);
328 if (rc
!= ERROR_SUCCESS
)
331 /* Call SETUP_CreateDevicesListFromEnumerator */
332 rc
= SETUP_CreateDevicesListFromEnumerator(list
, Class
, KeyBuffer
, hEnumeratorKey
);
333 if (rc
!= ERROR_SUCCESS
)
340 if (HKLM
!= HKEY_LOCAL_MACHINE
)
342 if (hEnumKey
!= NULL
)
343 RegCloseKey(hEnumKey
);
344 if (hEnumeratorKey
!= NULL
)
345 RegCloseKey(hEnumeratorKey
);
354 LPWSTR Buffer
= NULL
;
355 DWORD dwRegType
, dwLength
;
359 /* Read icon registry key */
360 rc
= RegQueryValueExW(hClassKey
, REGSTR_VAL_INSICON
, NULL
, &dwRegType
, NULL
, &dwLength
);
361 if (rc
!= ERROR_SUCCESS
)
365 } else if (dwRegType
!= REG_SZ
)
367 SetLastError(ERROR_INVALID_INDEX
);
370 Buffer
= MyMalloc(dwLength
+ sizeof(WCHAR
));
373 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
376 rc
= RegQueryValueExW(hClassKey
, REGSTR_VAL_INSICON
, NULL
, NULL
, (LPBYTE
)Buffer
, &dwLength
);
377 if (rc
!= ERROR_SUCCESS
)
382 /* make sure the returned buffer is NULL-terminated */
383 Buffer
[dwLength
/ sizeof(WCHAR
)] = 0;
385 /* Transform icon value to a INT */
386 *ImageIndex
= atoiW(Buffer
);
394 /***********************************************************************
395 * SetupDiGetClassImageIndex (SETUPAPI.@)
398 SetupDiGetClassImageIndex(
399 IN PSP_CLASSIMAGELIST_DATA ClassImageListData
,
400 IN CONST GUID
*ClassGuid
,
403 struct ClassImageList
*list
;
406 TRACE("%p %s %p\n", ClassImageListData
, debugstr_guid(ClassGuid
), ImageIndex
);
408 if (!ClassImageListData
|| !ClassGuid
|| !ImageIndex
)
409 SetLastError(ERROR_INVALID_PARAMETER
);
410 else if (ClassImageListData
->cbSize
!= sizeof(SP_CLASSIMAGELIST_DATA
))
411 SetLastError(ERROR_INVALID_USER_BUFFER
);
412 else if ((list
= (struct ClassImageList
*)ClassImageListData
->Reserved
) == NULL
)
413 SetLastError(ERROR_INVALID_USER_BUFFER
);
414 else if (list
->magic
!= SETUP_CLASS_IMAGE_LIST_MAGIC
)
415 SetLastError(ERROR_INVALID_USER_BUFFER
);
420 for (i
= 0; i
< list
->NumberOfGuids
; i
++)
422 if (IsEqualIID(ClassGuid
, &list
->Guids
[i
]))
426 if (i
== list
->NumberOfGuids
|| list
->IconIndexes
[i
] < 0)
427 SetLastError(ERROR_FILE_NOT_FOUND
);
430 *ImageIndex
= list
->IconIndexes
[i
];
435 TRACE("Returning %d\n", ret
);
439 /***********************************************************************
440 * SetupDiGetClassImageList(SETUPAPI.@)
443 SetupDiGetClassImageList(
444 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData
)
446 return SetupDiGetClassImageListExW(ClassImageListData
, NULL
, NULL
);
449 /***********************************************************************
450 * SetupDiGetClassImageListExA(SETUPAPI.@)
453 SetupDiGetClassImageListExA(
454 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData
,
455 IN PCSTR MachineName OPTIONAL
,
458 PWSTR MachineNameW
= NULL
;
463 MachineNameW
= pSetupMultiByteToUnicode(MachineName
, CP_ACP
);
464 if (MachineNameW
== NULL
)
468 ret
= SetupDiGetClassImageListExW(ClassImageListData
, MachineNameW
, Reserved
);
470 MyFree(MachineNameW
);
476 SETUP_GetClassIconInfo(IN CONST GUID
*ClassGuid
, OUT PINT OutIndex
, OUT LPWSTR
*OutDllName
)
478 LPWSTR Buffer
= NULL
;
479 INT iconIndex
= -UNKNOWN_ICON_INDEX
;
480 HKEY hKey
= INVALID_HANDLE_VALUE
;
485 hKey
= SetupDiOpenClassRegKey(ClassGuid
, KEY_QUERY_VALUE
);
486 if (hKey
!= INVALID_HANDLE_VALUE
)
488 SETUP_GetIconIndex(hKey
, &iconIndex
);
494 /* Look up icon in dll specified by Installer32 or EnumPropPages32 key */
497 DWORD dwRegType
, dwLength
;
498 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_INSTALLER_32
, NULL
, &dwRegType
, NULL
, &dwLength
);
499 if (rc
== ERROR_SUCCESS
&& dwRegType
== REG_SZ
)
501 Buffer
= MyMalloc(dwLength
+ sizeof(WCHAR
));
504 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
507 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_INSTALLER_32
, NULL
, NULL
, (LPBYTE
)Buffer
, &dwLength
);
508 if (rc
!= ERROR_SUCCESS
)
513 /* make sure the returned buffer is NULL-terminated */
514 Buffer
[dwLength
/ sizeof(WCHAR
)] = 0;
517 (ERROR_SUCCESS
== (rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, &dwRegType
, NULL
, &dwLength
))
518 && dwRegType
== REG_SZ
)
520 Buffer
= MyMalloc(dwLength
+ sizeof(WCHAR
));
523 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
526 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, NULL
, (LPBYTE
)Buffer
, &dwLength
);
527 if (rc
!= ERROR_SUCCESS
)
532 /* make sure the returned buffer is NULL-terminated */
533 Buffer
[dwLength
/ sizeof(WCHAR
)] = 0;
537 /* Unable to find where to load the icon */
538 SetLastError(ERROR_FILE_NOT_FOUND
);
541 Comma
= strchrW(Buffer
, ',');
544 SetLastError(ERROR_GEN_FAILURE
);
548 *OutDllName
= Buffer
;
552 /* Look up icon in setupapi.dll */
553 iconIndex
= -iconIndex
;
557 *OutIndex
= iconIndex
;
560 TRACE("Icon index %d, dll name %s\n", iconIndex
, debugstr_w(*OutDllName
? *OutDllName
: SetupapiDll
));
564 if (hKey
!= INVALID_HANDLE_VALUE
)
574 /***********************************************************************
575 * SetupDiGetClassImageListExW(SETUPAPI.@)
578 SetupDiGetClassImageListExW(
579 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData
,
580 IN PCWSTR MachineName OPTIONAL
,
585 TRACE("%p %p %p\n", ClassImageListData
, debugstr_w(MachineName
), Reserved
);
587 if (!ClassImageListData
)
588 SetLastError(ERROR_INVALID_PARAMETER
);
589 else if (ClassImageListData
->cbSize
!= sizeof(SP_CLASSIMAGELIST_DATA
))
590 SetLastError(ERROR_INVALID_USER_BUFFER
);
592 SetLastError(ERROR_INVALID_PARAMETER
);
595 struct ClassImageList
*list
= NULL
;
598 DWORD ilMask
, bkColor
;
604 /* Get list of all class GUIDs in given computer */
605 ret
= SetupDiBuildClassInfoListExW(
612 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
615 size
= sizeof(struct ClassImageList
)
616 + (sizeof(GUID
) + sizeof(INT
)) * RequiredSize
;
617 list
= HeapAlloc(GetProcessHeap(), 0, size
);
620 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
623 list
->magic
= SETUP_CLASS_IMAGE_LIST_MAGIC
;
624 list
->NumberOfGuids
= RequiredSize
;
625 list
->Guids
= (GUID
*)(list
+ 1);
626 list
->IconIndexes
= (INT
*)((ULONG_PTR
)(list
+ 1) + sizeof(GUID
) * RequiredSize
);
628 ret
= SetupDiBuildClassInfoListExW(
637 else if (RequiredSize
!= list
->NumberOfGuids
)
639 /* Hm. Class list changed since last call. Ignore
640 * this case as it should be very rare */
641 SetLastError(ERROR_GEN_FAILURE
);
646 /* Prepare a HIMAGELIST */
647 InitCommonControls();
653 bpp
= GetDeviceCaps(hDC
, BITSPIXEL
);
654 ReleaseDC(NULL
, hDC
);
661 ilMask
= ILC_COLOR16
;
663 ilMask
= ILC_COLOR24
;
665 ilMask
= ILC_COLOR32
;
671 ClassImageListData
->ImageList
= ImageList_Create(16, 16, ilMask
, 100, 10);
672 if (!ClassImageListData
->ImageList
)
675 ClassImageListData
->Reserved
= (ULONG_PTR
)list
;
677 /* For some reason, Windows sets the list background to COLOR_WINDOW */
678 bkColor
= GetSysColor(COLOR_WINDOW
);
679 ImageList_SetBkColor(ClassImageListData
->ImageList
, bkColor
);
681 /* Now, we "simply" need to load icons associated with all class guids,
682 * and put their index in the image list in the IconIndexes array */
683 for (i
= 0; i
< list
->NumberOfGuids
; i
++)
686 LPWSTR DllName
= NULL
;
688 if (SETUP_GetClassIconInfo(&list
->Guids
[i
], &miniIconIndex
, &DllName
))
690 if (DllName
&& ExtractIconExW(DllName
, -miniIconIndex
, NULL
, &hIcon
, 1) == 1)
692 list
->IconIndexes
[i
] = ImageList_AddIcon(ClassImageListData
->ImageList
, hIcon
);
696 hIcon
= LoadImage(hInstance
, MAKEINTRESOURCE(miniIconIndex
), IMAGE_ICON
, 16, 16, LR_DEFAULTCOLOR
);
697 list
->IconIndexes
[i
] = ImageList_AddIcon(ClassImageListData
->ImageList
, hIcon
);
703 list
->IconIndexes
[i
] = -1;
710 list
->IconIndexes
[i
] = -1; /* Special value to indicate that the icon is unavailable */
714 /* Finally, add the overlay icons to the image list */
715 for (i
= 0; i
<= 2; i
++)
717 hIcon
= LoadImage(hInstance
, MAKEINTRESOURCE(500 + i
), IMAGE_ICON
, 16, 16, LR_DEFAULTCOLOR
);
720 idx
= ImageList_AddIcon(ClassImageListData
->ImageList
, hIcon
);
722 ImageList_SetOverlayImage(ClassImageListData
->ImageList
, idx
, i
+ 1);
732 if (ClassImageListData
->Reserved
)
733 SetupDiDestroyClassImageList(ClassImageListData
);
739 TRACE("Returning %d\n", ret
);
743 /***********************************************************************
744 * SetupDiGetClassInstallParamsA(SETUPAPI.@)
747 SetupDiGetClassInstallParamsA(
748 IN HDEVINFO DeviceInfoSet
,
749 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
750 OUT PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
751 IN DWORD ClassInstallParamsSize
,
752 OUT PDWORD RequiredSize OPTIONAL
)
754 FIXME("SetupDiGetClassInstallParamsA(%p %p %p %lu %p) Stub\n",
755 DeviceInfoSet
, DeviceInfoData
, ClassInstallParams
, ClassInstallParamsSize
, RequiredSize
);
759 /***********************************************************************
760 * SetupDiGetClassInstallParamsW(SETUPAPI.@)
763 SetupDiGetClassInstallParamsW(
764 IN HDEVINFO DeviceInfoSet
,
765 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
766 OUT PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
767 IN DWORD ClassInstallParamsSize
,
768 OUT PDWORD RequiredSize OPTIONAL
)
770 FIXME("SetupDiGetClassInstallParamsW(%p %p %p %lu %p) Stub\n",
771 DeviceInfoSet
, DeviceInfoData
, ClassInstallParams
, ClassInstallParamsSize
, RequiredSize
);
775 /***********************************************************************
776 * SetupDiLoadClassIcon(SETUPAPI.@)
779 SetupDiLoadClassIcon(
780 IN CONST GUID
*ClassGuid
,
781 OUT HICON
*LargeIcon OPTIONAL
,
782 OUT PINT MiniIconIndex OPTIONAL
)
785 LPWSTR DllName
= NULL
;
791 if(!SETUP_GetClassIconInfo(ClassGuid
, &iconIndex
, &DllName
))
794 if (!DllName
|| ExtractIconExW(DllName
, -iconIndex
, &hIcon
, NULL
, 1) != 1 || hIcon
== NULL
)
796 /* load the default unknown device icon if ExtractIcon failed */
798 iconIndex
= UNKNOWN_ICON_INDEX
;
800 hIcon
= LoadImage(hInstance
, MAKEINTRESOURCE(iconIndex
), IMAGE_ICON
, 32, 32, LR_DEFAULTCOLOR
);
810 *MiniIconIndex
= iconIndex
;
819 TRACE("Returning %d\n", ret
);
823 /***********************************************************************
824 * SetupDiInstallClassExW (SETUPAPI.@)
827 SETUP_CreateClassKey(HINF hInf
);
829 SetupDiInstallClassExW(
830 IN HWND hwndParent OPTIONAL
,
831 IN PCWSTR InfFileName OPTIONAL
,
833 IN HSPFILEQ FileQueue OPTIONAL
,
834 IN CONST GUID
*InterfaceClassGuid OPTIONAL
,
840 TRACE("%p %s 0x%lx %p %s %p %p\n", hwndParent
, debugstr_w(InfFileName
), Flags
,
841 FileQueue
, debugstr_guid(InterfaceClassGuid
), Reserved1
, Reserved2
);
845 FIXME("Case not implemented: InfFileName NULL\n");
846 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
848 else if (Flags
& ~(DI_NOVCP
| DI_NOBROWSE
| DI_FORCECOPY
| DI_QUIETINSTALL
))
850 TRACE("Unknown flags: 0x%08lx\n", Flags
& ~(DI_NOVCP
| DI_NOBROWSE
| DI_FORCECOPY
| DI_QUIETINSTALL
));
851 SetLastError(ERROR_INVALID_FLAGS
);
853 else if ((Flags
& DI_NOVCP
) && FileQueue
== NULL
)
854 SetLastError(ERROR_INVALID_PARAMETER
);
855 else if (Reserved1
!= NULL
)
856 SetLastError(ERROR_INVALID_PARAMETER
);
857 else if (Reserved2
!= NULL
)
858 SetLastError(ERROR_INVALID_PARAMETER
);
861 HDEVINFO hDeviceInfo
= INVALID_HANDLE_VALUE
;
862 SP_DEVINSTALL_PARAMS_W InstallParams
;
863 WCHAR SectionName
[MAX_PATH
];
864 HINF hInf
= INVALID_HANDLE_VALUE
;
865 HKEY hRootKey
= INVALID_HANDLE_VALUE
;
866 PVOID callback_context
= NULL
;
868 hDeviceInfo
= SetupDiCreateDeviceInfoList(NULL
, NULL
);
869 if (hDeviceInfo
== INVALID_HANDLE_VALUE
)
872 InstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS
);
873 if (!SetupDiGetDeviceInstallParamsW(hDeviceInfo
, NULL
, &InstallParams
))
876 InstallParams
.Flags
&= ~(DI_NOVCP
| DI_NOBROWSE
| DI_QUIETINSTALL
);
877 InstallParams
.Flags
|= Flags
& (DI_NOVCP
| DI_NOBROWSE
| DI_QUIETINSTALL
);
878 if (Flags
& DI_NOVCP
)
879 InstallParams
.FileQueue
= FileQueue
;
880 if (!SetupDiSetDeviceInstallParamsW(hDeviceInfo
, NULL
, &InstallParams
))
883 /* Open the .inf file */
884 hInf
= SetupOpenInfFileW(
889 if (hInf
== INVALID_HANDLE_VALUE
)
892 /* Try to append a layout file */
893 SetupOpenAppendInfFileW(NULL
, hInf
, NULL
);
895 if (InterfaceClassGuid
)
897 /* Retrieve the actual section name */
898 ret
= SetupDiGetActualSectionToInstallW(
908 /* Open registry key related to this interface */
909 /* FIXME: What happens if the key doesn't exist? */
910 hRootKey
= SetupDiOpenClassRegKeyExW(InterfaceClassGuid
, KEY_ENUMERATE_SUB_KEYS
, DIOCR_INTERFACE
, NULL
, NULL
);
911 if (hRootKey
== INVALID_HANDLE_VALUE
)
914 /* SetupDiCreateDeviceInterface??? */
915 FIXME("Installing an interface is not implemented\n");
916 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
920 /* Create or open the class registry key 'HKLM\CurrentControlSet\Class\{GUID}' */
921 hRootKey
= SETUP_CreateClassKey(hInf
);
922 if (hRootKey
== INVALID_HANDLE_VALUE
)
925 /* Retrieve the actual section name */
926 ret
= SetupDiGetActualSectionToInstallW(
930 MAX_PATH
- strlenW(DotServices
),
936 callback_context
= SetupInitDefaultQueueCallback(hwndParent
);
937 if (!callback_context
)
940 ret
= SetupInstallFromInfSectionW(
944 SPINST_REGISTRY
| SPINST_FILES
| SPINST_BITREG
| SPINST_INIFILES
| SPINST_INI2REG
,
946 NULL
, /* FIXME: SourceRootPath */
947 !(Flags
& DI_NOVCP
) && (Flags
& DI_FORCECOPY
) ? SP_COPY_FORCE_IN_USE
: 0, /* CopyFlags */
948 SetupDefaultQueueCallbackW
,
955 /* OPTIONAL: Install .Services section */
956 lstrcatW(SectionName
, DotServices
);
957 SetupInstallServicesFromInfSectionExW(
969 if (hDeviceInfo
!= INVALID_HANDLE_VALUE
)
970 SetupDiDestroyDeviceInfoList(hDeviceInfo
);
971 if (hInf
!= INVALID_HANDLE_VALUE
)
972 SetupCloseInfFile(hInf
);
973 if (hRootKey
!= INVALID_HANDLE_VALUE
)
974 RegCloseKey(hRootKey
);
975 SetupTermDefaultQueueCallback(callback_context
);
978 TRACE("Returning %d\n", ret
);
982 /***********************************************************************
983 * Helper functions for SetupDiSetClassInstallParamsW
986 SETUP_PropertyChangeHandler(
987 IN HDEVINFO DeviceInfoSet
,
988 IN PSP_DEVINFO_DATA DeviceInfoData
,
989 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
990 IN DWORD ClassInstallParamsSize
)
992 PSP_PROPCHANGE_PARAMS PropChangeParams
= (PSP_PROPCHANGE_PARAMS
)ClassInstallParams
;
996 SetLastError(ERROR_INVALID_PARAMETER
);
997 else if (ClassInstallParamsSize
!= sizeof(SP_PROPCHANGE_PARAMS
))
998 SetLastError(ERROR_INVALID_PARAMETER
);
999 else if (PropChangeParams
&& PropChangeParams
->StateChange
!= DICS_ENABLE
1000 && PropChangeParams
->StateChange
!= DICS_DISABLE
&& PropChangeParams
->StateChange
!= DICS_PROPCHANGE
1001 && PropChangeParams
->StateChange
!= DICS_START
&& PropChangeParams
->StateChange
!= DICS_STOP
)
1002 SetLastError(ERROR_INVALID_FLAGS
);
1003 else if (PropChangeParams
&& PropChangeParams
->Scope
!= DICS_FLAG_GLOBAL
1004 && PropChangeParams
->Scope
!= DICS_FLAG_CONFIGSPECIFIC
)
1005 SetLastError(ERROR_INVALID_FLAGS
);
1006 else if (PropChangeParams
1007 && (PropChangeParams
->StateChange
== DICS_START
|| PropChangeParams
->StateChange
== DICS_STOP
)
1008 && PropChangeParams
->Scope
!= DICS_FLAG_CONFIGSPECIFIC
)
1009 SetLastError(ERROR_INVALID_USER_BUFFER
);
1012 PSP_PROPCHANGE_PARAMS
*CurrentPropChangeParams
;
1013 struct DeviceInfo
*deviceInfo
= (struct DeviceInfo
*)DeviceInfoData
->Reserved
;
1014 CurrentPropChangeParams
= &deviceInfo
->ClassInstallParams
.PropChangeParams
;
1016 if (*CurrentPropChangeParams
)
1018 MyFree(*CurrentPropChangeParams
);
1019 *CurrentPropChangeParams
= NULL
;
1021 if (PropChangeParams
)
1023 *CurrentPropChangeParams
= MyMalloc(ClassInstallParamsSize
);
1024 if (!*CurrentPropChangeParams
)
1026 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1029 memcpy(*CurrentPropChangeParams
, PropChangeParams
, ClassInstallParamsSize
);
1039 SETUP_PropertyAddPropertyAdvancedHandler(
1040 IN HDEVINFO DeviceInfoSet
,
1041 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
1042 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
1043 IN DWORD ClassInstallParamsSize
)
1045 PSP_ADDPROPERTYPAGE_DATA AddPropertyPageData
= (PSP_ADDPROPERTYPAGE_DATA
)ClassInstallParams
;
1048 if (ClassInstallParamsSize
!= sizeof(SP_PROPCHANGE_PARAMS
))
1049 SetLastError(ERROR_INVALID_PARAMETER
);
1050 else if (AddPropertyPageData
&& AddPropertyPageData
->Flags
!= 0)
1051 SetLastError(ERROR_INVALID_FLAGS
);
1052 else if (AddPropertyPageData
&& AddPropertyPageData
->NumDynamicPages
>= MAX_INSTALLWIZARD_DYNAPAGES
)
1053 SetLastError(ERROR_INVALID_USER_BUFFER
);
1056 PSP_ADDPROPERTYPAGE_DATA
*CurrentAddPropertyPageData
;
1057 if (!DeviceInfoData
)
1059 struct DeviceInfoSet
*list
= (struct DeviceInfoSet
*)DeviceInfoSet
;
1060 CurrentAddPropertyPageData
= &list
->ClassInstallParams
.AddPropertyPageData
;
1064 struct DeviceInfo
*deviceInfo
= (struct DeviceInfo
*)DeviceInfoData
->Reserved
;
1065 CurrentAddPropertyPageData
= &deviceInfo
->ClassInstallParams
.AddPropertyPageData
;
1067 if (*CurrentAddPropertyPageData
)
1069 MyFree(*CurrentAddPropertyPageData
);
1070 *CurrentAddPropertyPageData
= NULL
;
1072 if (AddPropertyPageData
)
1074 *CurrentAddPropertyPageData
= MyMalloc(ClassInstallParamsSize
);
1075 if (!*CurrentAddPropertyPageData
)
1077 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1080 memcpy(*CurrentAddPropertyPageData
, AddPropertyPageData
, ClassInstallParamsSize
);
1089 /***********************************************************************
1090 * SetupDiSetClassInstallParamsW (SETUPAPI.@)
1093 SetupDiSetClassInstallParamsW(
1094 IN HDEVINFO DeviceInfoSet
,
1095 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
1096 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
1097 IN DWORD ClassInstallParamsSize
)
1099 struct DeviceInfoSet
*list
;
1102 TRACE("%p %p %p %lu\n", DeviceInfoSet
, DeviceInfoData
,
1103 ClassInstallParams
, ClassInstallParamsSize
);
1106 SetLastError(ERROR_INVALID_PARAMETER
);
1107 else if (DeviceInfoSet
== (HDEVINFO
)INVALID_HANDLE_VALUE
)
1108 SetLastError(ERROR_INVALID_HANDLE
);
1109 else if ((list
= (struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEVICE_INFO_SET_MAGIC
)
1110 SetLastError(ERROR_INVALID_HANDLE
);
1111 else if (DeviceInfoData
&& DeviceInfoData
->cbSize
!= sizeof(SP_DEVINFO_DATA
))
1112 SetLastError(ERROR_INVALID_USER_BUFFER
);
1113 else if (ClassInstallParams
&& ClassInstallParams
->cbSize
!= sizeof(SP_CLASSINSTALL_HEADER
))
1114 SetLastError(ERROR_INVALID_USER_BUFFER
);
1115 else if (ClassInstallParams
&& ClassInstallParamsSize
< sizeof(SP_CLASSINSTALL_HEADER
))
1116 SetLastError(ERROR_INVALID_PARAMETER
);
1117 else if (!ClassInstallParams
&& ClassInstallParamsSize
!= 0)
1118 SetLastError(ERROR_INVALID_PARAMETER
);
1121 SP_DEVINSTALL_PARAMS_W InstallParams
;
1124 InstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS_W
);
1125 Result
= SetupDiGetDeviceInstallParamsW(DeviceInfoSet
, DeviceInfoData
, &InstallParams
);
1129 if (ClassInstallParams
)
1132 /* Check parameters in ClassInstallParams */
1133 for (i
= 0; i
< sizeof(InstallParamsData
) / sizeof(InstallParamsData
[0]); i
++)
1135 if (InstallParamsData
[i
].Function
== ClassInstallParams
->InstallFunction
)
1137 ret
= InstallParamsData
[i
].UpdateHandler(
1141 ClassInstallParamsSize
);
1144 InstallParams
.Flags
|= DI_CLASSINSTALLPARAMS
;
1145 ret
= SetupDiSetDeviceInstallParamsW(DeviceInfoSet
, DeviceInfoData
, &InstallParams
);
1150 ERR("InstallFunction %u has no associated update handler\n", ClassInstallParams
->InstallFunction
);
1151 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1156 InstallParams
.Flags
&= ~DI_CLASSINSTALLPARAMS
;
1157 ret
= SetupDiSetDeviceInstallParamsW(DeviceInfoSet
, DeviceInfoData
, &InstallParams
);
1162 TRACE("Returning %d\n", ret
);
1166 /***********************************************************************
1167 * SetupDiGetClassDevPropertySheetsA(SETUPAPI.@)
1170 SetupDiGetClassDevPropertySheetsA(
1171 IN HDEVINFO DeviceInfoSet
,
1172 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
1173 IN LPPROPSHEETHEADERA PropertySheetHeader
,
1174 IN DWORD PropertySheetHeaderPageListSize
,
1175 OUT PDWORD RequiredSize OPTIONAL
,
1176 IN DWORD PropertySheetType
)
1178 PROPSHEETHEADERW psh
;
1181 TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet
, DeviceInfoData
,
1182 PropertySheetHeader
, PropertySheetHeaderPageListSize
,
1183 RequiredSize
, PropertySheetType
);
1185 if(PropertySheetHeader
)
1187 psh
.dwFlags
= PropertySheetHeader
->dwFlags
;
1188 psh
.phpage
= PropertySheetHeader
->phpage
;
1189 psh
.nPages
= PropertySheetHeader
->nPages
;
1192 ret
= SetupDiGetClassDevPropertySheetsW(DeviceInfoSet
, DeviceInfoData
, PropertySheetHeader
? &psh
: NULL
,
1193 PropertySheetHeaderPageListSize
, RequiredSize
,
1197 PropertySheetHeader
->nPages
= psh
.nPages
;
1200 TRACE("Returning %d\n", ret
);
1204 struct ClassDevPropertySheetsData
1206 LPPROPSHEETHEADERW PropertySheetHeader
;
1207 DWORD PropertySheetHeaderPageListSize
;
1208 DWORD NumberOfPages
;
1213 SETUP_GetClassDevPropertySheetsCallback(
1214 IN HPROPSHEETPAGE hPropSheetPage
,
1215 IN OUT LPARAM lParam
)
1217 struct ClassDevPropertySheetsData
*PropPageData
;
1219 PropPageData
= (struct ClassDevPropertySheetsData
*)lParam
;
1221 PropPageData
->NumberOfPages
++;
1223 if (PropPageData
->PropertySheetHeader
->nPages
< PropPageData
->PropertySheetHeaderPageListSize
)
1225 PropPageData
->PropertySheetHeader
->phpage
[PropPageData
->PropertySheetHeader
->nPages
] = hPropSheetPage
;
1226 PropPageData
->PropertySheetHeader
->nPages
++;
1230 return PropPageData
->DontCancel
;
1233 /***********************************************************************
1234 * SetupDiGetClassDevPropertySheetsW(SETUPAPI.@)
1237 SetupDiGetClassDevPropertySheetsW(
1238 IN HDEVINFO DeviceInfoSet
,
1239 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
1240 IN OUT LPPROPSHEETHEADERW PropertySheetHeader
,
1241 IN DWORD PropertySheetHeaderPageListSize
,
1242 OUT PDWORD RequiredSize OPTIONAL
,
1243 IN DWORD PropertySheetType
)
1245 struct DeviceInfoSet
*list
;
1248 TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet
, DeviceInfoData
,
1249 PropertySheetHeader
, PropertySheetHeaderPageListSize
,
1250 RequiredSize
, PropertySheetType
);
1253 SetLastError(ERROR_INVALID_HANDLE
);
1254 else if (((struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEVICE_INFO_SET_MAGIC
)
1255 SetLastError(ERROR_INVALID_HANDLE
);
1256 else if ((list
= (struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEVICE_INFO_SET_MAGIC
)
1257 SetLastError(ERROR_INVALID_HANDLE
);
1258 else if (!PropertySheetHeader
)
1259 SetLastError(ERROR_INVALID_PARAMETER
);
1260 else if (PropertySheetHeader
->dwFlags
& PSH_PROPSHEETPAGE
)
1261 SetLastError(ERROR_INVALID_FLAGS
);
1262 else if (DeviceInfoData
&& DeviceInfoData
->cbSize
!= sizeof(SP_DEVINFO_DATA
))
1263 SetLastError(ERROR_INVALID_USER_BUFFER
);
1264 else if (!DeviceInfoData
&& IsEqualIID(&list
->ClassGuid
, &GUID_NULL
))
1265 SetLastError(ERROR_INVALID_PARAMETER
);
1266 else if (PropertySheetType
!= DIGCDP_FLAG_ADVANCED
1267 && PropertySheetType
!= DIGCDP_FLAG_BASIC
1268 && PropertySheetType
!= DIGCDP_FLAG_REMOTE_ADVANCED
1269 && PropertySheetType
!= DIGCDP_FLAG_REMOTE_BASIC
)
1270 SetLastError(ERROR_INVALID_PARAMETER
);
1273 HKEY hKey
= INVALID_HANDLE_VALUE
;
1274 SP_PROPSHEETPAGE_REQUEST Request
;
1275 LPWSTR PropPageProvider
= NULL
;
1276 HMODULE hModule
= NULL
;
1277 PROPERTY_PAGE_PROVIDER pPropPageProvider
= NULL
;
1278 struct ClassDevPropertySheetsData PropPageData
;
1279 DWORD dwLength
, dwRegType
;
1280 DWORD InitialNumberOfPages
;
1284 hKey
= SetupDiOpenDevRegKey(DeviceInfoSet
, DeviceInfoData
, DICS_FLAG_GLOBAL
, 0, DIREG_DRV
, KEY_QUERY_VALUE
);
1287 hKey
= SetupDiOpenClassRegKeyExW(&list
->ClassGuid
, KEY_QUERY_VALUE
,
1288 DIOCR_INSTALLER
, list
->MachineName
+ 2, NULL
);
1290 if (hKey
== INVALID_HANDLE_VALUE
)
1293 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, &dwRegType
, NULL
, &dwLength
);
1294 if (rc
== ERROR_FILE_NOT_FOUND
)
1296 /* No registry key. As it is optional, don't say it's a bad error */
1302 else if (rc
!= ERROR_SUCCESS
&& dwRegType
!= REG_SZ
)
1308 PropPageProvider
= HeapAlloc(GetProcessHeap(), 0, dwLength
+ sizeof(WCHAR
));
1309 if (!PropPageProvider
)
1311 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1314 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, NULL
, (LPBYTE
)PropPageProvider
, &dwLength
);
1315 if (rc
!= ERROR_SUCCESS
)
1320 PropPageProvider
[dwLength
/ sizeof(WCHAR
)] = 0;
1322 rc
= GetFunctionPointer(PropPageProvider
, &hModule
, (PVOID
*)&pPropPageProvider
);
1323 if (rc
!= ERROR_SUCCESS
)
1325 SetLastError(ERROR_INVALID_PROPPAGE_PROVIDER
);
1331 struct DeviceInfo
*devInfo
= (struct DeviceInfo
*)DeviceInfoData
->Reserved
;
1333 if (devInfo
->hmodDevicePropPageProvider
== NULL
)
1335 devInfo
->hmodDevicePropPageProvider
= hModule
;
1336 devInfo
->pDevicePropPageProvider
= pPropPageProvider
;
1341 struct DeviceInfoSet
*devInfoSet
= (struct DeviceInfoSet
*)DeviceInfoSet
;
1343 if (devInfoSet
->hmodClassPropPageProvider
== NULL
)
1345 devInfoSet
->hmodClassPropPageProvider
= hModule
;
1346 devInfoSet
->pClassPropPageProvider
= pPropPageProvider
;
1350 InitialNumberOfPages
= PropertySheetHeader
->nPages
;
1352 Request
.cbSize
= sizeof(SP_PROPSHEETPAGE_REQUEST
);
1353 Request
.PageRequested
= SPPSR_ENUM_ADV_DEVICE_PROPERTIES
;
1354 Request
.DeviceInfoSet
= DeviceInfoSet
;
1355 Request
.DeviceInfoData
= DeviceInfoData
;
1357 PropPageData
.PropertySheetHeader
= PropertySheetHeader
;
1358 PropPageData
.PropertySheetHeaderPageListSize
= PropertySheetHeaderPageListSize
;
1359 PropPageData
.NumberOfPages
= 0;
1360 PropPageData
.DontCancel
= (RequiredSize
!= NULL
) ? TRUE
: FALSE
;
1362 pPropPageProvider(&Request
, SETUP_GetClassDevPropertySheetsCallback
, (LPARAM
)&PropPageData
);
1365 *RequiredSize
= PropPageData
.NumberOfPages
;
1367 if (InitialNumberOfPages
+ PropPageData
.NumberOfPages
<= PropertySheetHeaderPageListSize
)
1373 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1377 if (hKey
!= INVALID_HANDLE_VALUE
)
1379 HeapFree(GetProcessHeap(), 0, PropPageProvider
);
1382 TRACE("Returning %d\n", ret
);