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"
27 /* Unicode constants */
28 static const WCHAR BackSlash
[] = {'\\',0};
29 static const WCHAR Class
[] = {'C','l','a','s','s',0};
30 static const WCHAR ClassGUID
[] = {'C','l','a','s','s','G','U','I','D',0};
31 static const WCHAR ClassInstall32
[] = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
32 static const WCHAR DotServices
[] = {'.','S','e','r','v','i','c','e','s',0};
33 static const WCHAR InterfaceInstall32
[] = {'I','n','t','e','r','f','a','c','e','I','n','s','t','a','l','l','3','2',0};
34 static const WCHAR SetupapiDll
[] = {'s','e','t','u','p','a','p','i','.','d','l','l',0};
35 static const WCHAR Version
[] = {'V','e','r','s','i','o','n',0};
38 (WINAPI
* PROPERTY_PAGE_PROVIDER
) (
39 IN PSP_PROPSHEETPAGE_REQUEST PropPageRequest
,
40 IN LPFNADDPROPSHEETPAGE fAddFunc
,
43 (*UPDATE_CLASS_PARAM_HANDLER
) (
44 IN HDEVINFO DeviceInfoSet
,
45 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
46 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
47 IN DWORD ClassInstallParamsSize
);
50 SETUP_PropertyChangeHandler(
51 IN HDEVINFO DeviceInfoSet
,
52 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
53 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
54 IN DWORD ClassInstallParamsSize
);
57 SETUP_PropertyAddPropertyAdvancedHandler(
58 IN HDEVINFO DeviceInfoSet
,
59 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
60 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
61 IN DWORD ClassInstallParamsSize
);
63 typedef struct _INSTALL_PARAMS_DATA
66 UPDATE_CLASS_PARAM_HANDLER UpdateHandler
;
69 } INSTALL_PARAMS_DATA
;
71 #define ADD_PARAM_HANDLER(Function, UpdateHandler, ParamsType, ParamsField) \
72 { Function, UpdateHandler, sizeof(ParamsType), FIELD_OFFSET(struct ClassInstallParams, ParamsField) },
74 static const INSTALL_PARAMS_DATA InstallParamsData
[] = {
75 ADD_PARAM_HANDLER(DIF_PROPERTYCHANGE
, SETUP_PropertyChangeHandler
, SP_PROPCHANGE_PARAMS
, PropChangeParams
)
76 ADD_PARAM_HANDLER(DIF_ADDPROPERTYPAGE_ADVANCED
, SETUP_PropertyAddPropertyAdvancedHandler
, SP_ADDPROPERTYPAGE_DATA
, AddPropertyPageData
)
78 #undef ADD_PARAM_HANDLER
80 #define UNKNOWN_ICON_INDEX 18
82 /***********************************************************************
83 * SetupDiDestroyClassImageList(SETUPAPI.@)
86 SetupDiDestroyClassImageList(
87 IN PSP_CLASSIMAGELIST_DATA ClassImageListData
)
89 struct ClassImageList
*list
;
92 TRACE("%p\n", ClassImageListData
);
94 if (!ClassImageListData
)
95 SetLastError(ERROR_INVALID_PARAMETER
);
96 else if (ClassImageListData
->cbSize
!= sizeof(SP_CLASSIMAGELIST_DATA
))
97 SetLastError(ERROR_INVALID_USER_BUFFER
);
98 else if ((list
= (struct ClassImageList
*)ClassImageListData
->Reserved
) == NULL
)
99 SetLastError(ERROR_INVALID_USER_BUFFER
);
100 else if (list
->magic
!= SETUP_CLASS_IMAGE_LIST_MAGIC
)
101 SetLastError(ERROR_INVALID_USER_BUFFER
);
105 //ImageList_Destroy();
106 FIXME("Stub %p\n", ClassImageListData
);
107 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
110 TRACE("Returning %d\n", ret
);
114 /***********************************************************************
115 * SETUP_CreateDevicesListFromEnumerator
118 * list [IO] Device info set to fill with discovered devices.
119 * pClassGuid [I] If specified, only devices which belong to this class will be added.
120 * Enumerator [I] Location to search devices to add.
121 * hEnumeratorKey [I] Registry key corresponding to Enumerator key. Must have KEY_ENUMERATE_SUB_KEYS right.
124 * Success: ERROR_SUCCESS.
125 * Failure: an error code.
128 SETUP_CreateDevicesListFromEnumerator(
129 IN OUT
struct DeviceInfoSet
*list
,
130 IN CONST GUID
*pClassGuid OPTIONAL
,
131 IN LPCWSTR Enumerator
,
132 IN HKEY hEnumeratorKey
) /* handle to Enumerator registry key */
134 HKEY hDeviceIdKey
= NULL
, hInstanceIdKey
;
135 WCHAR KeyBuffer
[MAX_PATH
];
136 WCHAR InstancePath
[MAX_PATH
];
137 LPWSTR pEndOfInstancePath
; /* Pointer into InstancePath buffer */
138 struct DeviceInfo
*deviceInfo
;
140 DWORD dwLength
, dwRegType
;
143 /* Enumerate device IDs (subkeys of hEnumeratorKey) */
146 dwLength
= sizeof(KeyBuffer
) / sizeof(KeyBuffer
[0]);
147 rc
= RegEnumKeyExW(hEnumeratorKey
, i
, KeyBuffer
, &dwLength
, NULL
, NULL
, NULL
, NULL
);
148 if (rc
== ERROR_NO_MORE_ITEMS
)
150 if (rc
!= ERROR_SUCCESS
)
154 /* Open device id sub key */
155 if (hDeviceIdKey
!= NULL
)
156 RegCloseKey(hDeviceIdKey
);
157 rc
= RegOpenKeyExW(hEnumeratorKey
, KeyBuffer
, 0, KEY_ENUMERATE_SUB_KEYS
, &hDeviceIdKey
);
158 if (rc
!= ERROR_SUCCESS
)
160 strcpyW(InstancePath
, Enumerator
);
161 strcatW(InstancePath
, BackSlash
);
162 strcatW(InstancePath
, KeyBuffer
);
163 strcatW(InstancePath
, BackSlash
);
164 pEndOfInstancePath
= &InstancePath
[strlenW(InstancePath
)];
166 /* Enumerate instance IDs (subkeys of hDeviceIdKey) */
172 dwLength
= sizeof(KeyBuffer
) / sizeof(KeyBuffer
[0]);
173 rc
= RegEnumKeyExW(hDeviceIdKey
, j
, KeyBuffer
, &dwLength
, NULL
, NULL
, NULL
, NULL
);
174 if (rc
== ERROR_NO_MORE_ITEMS
)
176 if (rc
!= ERROR_SUCCESS
)
180 /* Open instance id sub key */
181 rc
= RegOpenKeyExW(hDeviceIdKey
, KeyBuffer
, 0, KEY_QUERY_VALUE
, &hInstanceIdKey
);
182 if (rc
!= ERROR_SUCCESS
)
184 *pEndOfInstancePath
= '\0';
185 strcatW(InstancePath
, KeyBuffer
);
187 /* Read ClassGUID value */
188 dwLength
= sizeof(KeyBuffer
) - sizeof(WCHAR
);
189 rc
= RegQueryValueExW(hInstanceIdKey
, ClassGUID
, NULL
, &dwRegType
, (LPBYTE
)KeyBuffer
, &dwLength
);
190 RegCloseKey(hInstanceIdKey
);
191 if (rc
== ERROR_FILE_NOT_FOUND
)
194 /* Skip this bad entry as we can't verify it */
196 /* Set a default GUID for this device */
197 memcpy(&KeyGuid
, &GUID_NULL
, sizeof(GUID
));
199 else if (rc
!= ERROR_SUCCESS
)
203 else if (dwRegType
!= REG_SZ
|| dwLength
< MAX_GUID_STRING_LEN
* sizeof(WCHAR
))
205 rc
= ERROR_GEN_FAILURE
;
210 KeyBuffer
[MAX_GUID_STRING_LEN
- 2] = '\0'; /* Replace the } by a NULL character */
211 if (UuidFromStringW(&KeyBuffer
[1], &KeyGuid
) != RPC_S_OK
)
212 /* Bad GUID, skip the entry */
216 if (pClassGuid
&& !IsEqualIID(&KeyGuid
, pClassGuid
))
218 /* Skip this entry as it is not the right device class */
222 /* Add the entry to the list */
223 if (!CreateDeviceInfo(list
, InstancePath
, &KeyGuid
, &deviceInfo
))
228 TRACE("Adding '%s' to device info set %p\n", debugstr_w(InstancePath
), list
);
229 InsertTailList(&list
->ListHead
, &deviceInfo
->ListEntry
);
236 if (hDeviceIdKey
!= NULL
)
237 RegCloseKey(hDeviceIdKey
);
242 SETUP_CreateDevicesList(
243 IN OUT
struct DeviceInfoSet
*list
,
244 IN PCWSTR MachineName OPTIONAL
,
245 IN CONST GUID
*Class OPTIONAL
,
246 IN PCWSTR Enumerator OPTIONAL
)
248 HKEY HKLM
= HKEY_LOCAL_MACHINE
;
249 HKEY hEnumKey
= NULL
;
250 HKEY hEnumeratorKey
= NULL
;
251 WCHAR KeyBuffer
[MAX_PATH
];
256 if (Class
&& IsEqualIID(Class
, &GUID_NULL
))
259 /* Open Enum key (if applicable) */
260 if (MachineName
!= NULL
)
262 rc
= RegConnectRegistryW(MachineName
, HKEY_LOCAL_MACHINE
, &HKLM
);
263 if (rc
!= ERROR_SUCCESS
)
269 REGSTR_PATH_SYSTEMENUM
,
271 KEY_ENUMERATE_SUB_KEYS
,
273 if (rc
!= ERROR_SUCCESS
)
276 /* If enumerator is provided, call directly SETUP_CreateDevicesListFromEnumerator.
277 * Else, enumerate all enumerators and call SETUP_CreateDevicesListFromEnumerator
286 KEY_ENUMERATE_SUB_KEYS
,
288 if (rc
!= ERROR_SUCCESS
)
290 if (rc
== ERROR_FILE_NOT_FOUND
)
291 rc
= ERROR_INVALID_DATA
;
294 rc
= SETUP_CreateDevicesListFromEnumerator(list
, Class
, Enumerator
, hEnumeratorKey
);
298 /* Enumerate enumerators */
302 dwLength
= sizeof(KeyBuffer
) / sizeof(KeyBuffer
[0]);
303 rc
= RegEnumKeyExW(hEnumKey
, i
, KeyBuffer
, &dwLength
, NULL
, NULL
, NULL
, NULL
);
304 if (rc
== ERROR_NO_MORE_ITEMS
)
306 else if (rc
!= ERROR_SUCCESS
)
311 if (hEnumeratorKey
!= NULL
)
312 RegCloseKey(hEnumeratorKey
);
313 rc
= RegOpenKeyExW(hEnumKey
, KeyBuffer
, 0, KEY_ENUMERATE_SUB_KEYS
, &hEnumeratorKey
);
314 if (rc
!= ERROR_SUCCESS
)
317 /* Call SETUP_CreateDevicesListFromEnumerator */
318 rc
= SETUP_CreateDevicesListFromEnumerator(list
, Class
, KeyBuffer
, hEnumeratorKey
);
319 if (rc
!= ERROR_SUCCESS
)
326 if (HKLM
!= HKEY_LOCAL_MACHINE
)
328 if (hEnumKey
!= NULL
)
329 RegCloseKey(hEnumKey
);
330 if (hEnumeratorKey
!= NULL
)
331 RegCloseKey(hEnumeratorKey
);
340 LPWSTR Buffer
= NULL
;
341 DWORD dwRegType
, dwLength
;
345 /* Read icon registry key */
346 rc
= RegQueryValueExW(hClassKey
, REGSTR_VAL_INSICON
, NULL
, &dwRegType
, NULL
, &dwLength
);
347 if (rc
!= ERROR_SUCCESS
)
351 } else if (dwRegType
!= REG_SZ
)
353 SetLastError(ERROR_INVALID_INDEX
);
356 Buffer
= MyMalloc(dwLength
+ sizeof(WCHAR
));
359 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
362 rc
= RegQueryValueExW(hClassKey
, REGSTR_VAL_INSICON
, NULL
, NULL
, (LPBYTE
)Buffer
, &dwLength
);
363 if (rc
!= ERROR_SUCCESS
)
368 /* make sure the returned buffer is NULL-terminated */
369 Buffer
[dwLength
/ sizeof(WCHAR
)] = 0;
371 /* Transform icon value to a INT */
372 *ImageIndex
= atoiW(Buffer
);
380 /***********************************************************************
381 * SetupDiGetClassImageIndex (SETUPAPI.@)
384 SetupDiGetClassImageIndex(
385 IN PSP_CLASSIMAGELIST_DATA ClassImageListData
,
386 IN CONST GUID
*ClassGuid
,
389 struct ClassImageList
*list
;
392 TRACE("%p %s %p\n", ClassImageListData
, debugstr_guid(ClassGuid
), ImageIndex
);
394 if (!ClassImageListData
|| !ClassGuid
|| !ImageIndex
)
395 SetLastError(ERROR_INVALID_PARAMETER
);
396 else if (ClassImageListData
->cbSize
!= sizeof(SP_CLASSIMAGELIST_DATA
))
397 SetLastError(ERROR_INVALID_USER_BUFFER
);
398 else if ((list
= (struct ClassImageList
*)ClassImageListData
->Reserved
) == NULL
)
399 SetLastError(ERROR_INVALID_USER_BUFFER
);
400 else if (list
->magic
!= SETUP_CLASS_IMAGE_LIST_MAGIC
)
401 SetLastError(ERROR_INVALID_USER_BUFFER
);
402 else if (!ImageIndex
)
403 SetLastError(ERROR_INVALID_PARAMETER
);
408 for (i
= 0; i
< list
->NumberOfGuids
; i
++)
410 if (IsEqualIID(ClassGuid
, &list
->Guids
[i
]))
414 if (i
== list
->NumberOfGuids
|| list
->IconIndexes
[i
] < 0)
415 SetLastError(ERROR_FILE_NOT_FOUND
);
418 *ImageIndex
= list
->IconIndexes
[i
];
423 TRACE("Returning %d\n", ret
);
427 /***********************************************************************
428 * SetupDiGetClassImageList(SETUPAPI.@)
431 SetupDiGetClassImageList(
432 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData
)
434 return SetupDiGetClassImageListExW(ClassImageListData
, NULL
, NULL
);
437 /***********************************************************************
438 * SetupDiGetClassImageListExA(SETUPAPI.@)
441 SetupDiGetClassImageListExA(
442 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData
,
443 IN PCSTR MachineName OPTIONAL
,
446 PWSTR MachineNameW
= NULL
;
451 MachineNameW
= pSetupMultiByteToUnicode(MachineName
, CP_ACP
);
452 if (MachineNameW
== NULL
)
456 ret
= SetupDiGetClassImageListExW(ClassImageListData
, MachineNameW
, Reserved
);
458 MyFree(MachineNameW
);
464 SETUP_GetClassIconInfo(IN CONST GUID
*ClassGuid
, OUT PINT OutIndex
, OUT LPWSTR
*OutDllName
)
466 LPWSTR Buffer
= NULL
;
467 INT iconIndex
= -UNKNOWN_ICON_INDEX
;
468 HKEY hKey
= INVALID_HANDLE_VALUE
;
473 hKey
= SetupDiOpenClassRegKey(ClassGuid
, KEY_QUERY_VALUE
);
474 if (hKey
!= INVALID_HANDLE_VALUE
)
476 SETUP_GetIconIndex(hKey
, &iconIndex
);
482 /* Look up icon in dll specified by Installer32 or EnumPropPages32 key */
485 DWORD dwRegType
, dwLength
;
486 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_INSTALLER_32
, NULL
, &dwRegType
, NULL
, &dwLength
);
487 if (rc
== ERROR_SUCCESS
&& dwRegType
== REG_SZ
)
489 Buffer
= MyMalloc(dwLength
+ sizeof(WCHAR
));
492 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
495 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_INSTALLER_32
, NULL
, NULL
, (LPBYTE
)Buffer
, &dwLength
);
496 if (rc
!= ERROR_SUCCESS
)
501 /* make sure the returned buffer is NULL-terminated */
502 Buffer
[dwLength
/ sizeof(WCHAR
)] = 0;
505 (ERROR_SUCCESS
== (rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, &dwRegType
, NULL
, &dwLength
))
506 && dwRegType
== REG_SZ
)
508 Buffer
= MyMalloc(dwLength
+ sizeof(WCHAR
));
511 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
514 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, NULL
, (LPBYTE
)Buffer
, &dwLength
);
515 if (rc
!= ERROR_SUCCESS
)
520 /* make sure the returned buffer is NULL-terminated */
521 Buffer
[dwLength
/ sizeof(WCHAR
)] = 0;
525 /* Unable to find where to load the icon */
526 SetLastError(ERROR_FILE_NOT_FOUND
);
529 Comma
= strchrW(Buffer
, ',');
532 SetLastError(ERROR_GEN_FAILURE
);
536 *OutDllName
= Buffer
;
540 /* Look up icon in setupapi.dll */
541 iconIndex
= -iconIndex
;
545 *OutIndex
= iconIndex
;
548 TRACE("Icon index %d, dll name %s\n", iconIndex
, debugstr_w(*OutDllName
? *OutDllName
: SetupapiDll
));
552 if (hKey
!= INVALID_HANDLE_VALUE
)
559 /***********************************************************************
560 * SetupDiGetClassImageListExW(SETUPAPI.@)
563 SetupDiGetClassImageListExW(
564 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData
,
565 IN PCWSTR MachineName OPTIONAL
,
570 TRACE("%p %p %p\n", ClassImageListData
, debugstr_w(MachineName
), Reserved
);
572 if (!ClassImageListData
)
573 SetLastError(ERROR_INVALID_PARAMETER
);
574 else if (ClassImageListData
->cbSize
!= sizeof(SP_CLASSIMAGELIST_DATA
))
575 SetLastError(ERROR_INVALID_USER_BUFFER
);
577 SetLastError(ERROR_INVALID_PARAMETER
);
580 struct ClassImageList
*list
= NULL
;
583 DWORD ilMask
, bkColor
;
589 /* Get list of all class GUIDs in given computer */
590 ret
= SetupDiBuildClassInfoListExW(
597 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
600 size
= sizeof(struct ClassImageList
)
601 + (sizeof(GUID
) + sizeof(INT
)) * RequiredSize
;
602 list
= HeapAlloc(GetProcessHeap(), 0, size
);
605 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
608 list
->magic
= SETUP_CLASS_IMAGE_LIST_MAGIC
;
609 list
->NumberOfGuids
= RequiredSize
;
610 list
->Guids
= (GUID
*)(list
+ 1);
611 list
->IconIndexes
= (INT
*)((ULONG_PTR
)(list
+ 1) + sizeof(GUID
) * RequiredSize
);
613 ret
= SetupDiBuildClassInfoListExW(
622 else if (RequiredSize
!= list
->NumberOfGuids
)
624 /* Hm. Class list changed since last call. Ignore
625 * this case as it should be very rare */
626 SetLastError(ERROR_GEN_FAILURE
);
631 /* Prepare a HIMAGELIST */
632 InitCommonControls();
638 bpp
= GetDeviceCaps(hDC
, BITSPIXEL
);
639 ReleaseDC(NULL
, hDC
);
646 ilMask
= ILC_COLOR16
;
648 ilMask
= ILC_COLOR24
;
650 ilMask
= ILC_COLOR32
;
656 ClassImageListData
->ImageList
= ImageList_Create(16, 16, ilMask
, 100, 10);
657 if (!ClassImageListData
->ImageList
)
660 ClassImageListData
->Reserved
= (ULONG_PTR
)list
;
662 /* For some reason, Windows sets the list background to COLOR_WINDOW */
663 bkColor
= GetSysColor(COLOR_WINDOW
);
664 ImageList_SetBkColor(ClassImageListData
->ImageList
, bkColor
);
666 /* Now, we "simply" need to load icons associated with all class guids,
667 * and put their index in the image list in the IconIndexes array */
668 for (i
= 0; i
< list
->NumberOfGuids
; i
++)
671 LPWSTR DllName
= NULL
;
673 if (SETUP_GetClassIconInfo(&list
->Guids
[i
], &miniIconIndex
, &DllName
))
675 if (DllName
&& ExtractIconExW(DllName
, -miniIconIndex
, NULL
, &hIcon
, 1) == 1)
677 list
->IconIndexes
[i
] = ImageList_AddIcon(ClassImageListData
->ImageList
, hIcon
);
681 hIcon
= LoadImage(hInstance
, MAKEINTRESOURCE(miniIconIndex
), IMAGE_ICON
, 16, 16, LR_DEFAULTCOLOR
);
682 list
->IconIndexes
[i
] = ImageList_AddIcon(ClassImageListData
->ImageList
, hIcon
);
688 list
->IconIndexes
[i
] = -1;
695 list
->IconIndexes
[i
] = -1; /* Special value to indicate that the icon is unavailable */
699 /* Finally, add the overlay icons to the image list */
700 for (i
= 0; i
< 2; i
++)
702 hIcon
= LoadImage(hInstance
, MAKEINTRESOURCE(500 + i
), IMAGE_ICON
, 16, 16, LR_DEFAULTCOLOR
);
705 idx
= ImageList_AddIcon(ClassImageListData
->ImageList
, hIcon
);
707 ImageList_SetOverlayImage(ClassImageListData
->ImageList
, idx
, i
);
717 if (ClassImageListData
->Reserved
)
718 SetupDiDestroyClassImageList(ClassImageListData
);
724 TRACE("Returning %d\n", ret
);
728 /***********************************************************************
729 * SetupDiGetClassInstallParamsA(SETUPAPI.@)
732 SetupDiGetClassInstallParamsA(
733 IN HDEVINFO DeviceInfoSet
,
734 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
735 OUT PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
736 IN DWORD ClassInstallParamsSize
,
737 OUT PDWORD RequiredSize OPTIONAL
)
739 FIXME("SetupDiGetClassInstallParamsA(%p %p %p %lu %p) Stub\n",
740 DeviceInfoSet
, DeviceInfoData
, ClassInstallParams
, ClassInstallParamsSize
, RequiredSize
);
744 /***********************************************************************
745 * SetupDiGetClassInstallParamsW(SETUPAPI.@)
748 SetupDiGetClassInstallParamsW(
749 IN HDEVINFO DeviceInfoSet
,
750 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
751 OUT PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
752 IN DWORD ClassInstallParamsSize
,
753 OUT PDWORD RequiredSize OPTIONAL
)
755 FIXME("SetupDiGetClassInstallParamsW(%p %p %p %lu %p) Stub\n",
756 DeviceInfoSet
, DeviceInfoData
, ClassInstallParams
, ClassInstallParamsSize
, RequiredSize
);
760 /***********************************************************************
761 * SetupDiLoadClassIcon(SETUPAPI.@)
764 SetupDiLoadClassIcon(
765 IN CONST GUID
*ClassGuid
,
766 OUT HICON
*LargeIcon OPTIONAL
,
767 OUT PINT MiniIconIndex OPTIONAL
)
770 LPWSTR DllName
= NULL
;
776 if(!SETUP_GetClassIconInfo(ClassGuid
, &iconIndex
, &DllName
))
779 if (DllName
&& ExtractIconExW(DllName
, -iconIndex
, &hIcon
, NULL
, 1) == 1 && hIcon
!= NULL
)
785 /* load the default unknown device icon if ExtractIcon failed */
787 iconIndex
= UNKNOWN_ICON_INDEX
;
789 hIcon
= LoadImage(hInstance
, MAKEINTRESOURCE(iconIndex
), IMAGE_ICON
, 32, 32, LR_DEFAULTCOLOR
);
797 *MiniIconIndex
= iconIndex
;
807 TRACE("Returning %d\n", ret
);
811 /***********************************************************************
812 * SetupDiInstallClassExW (SETUPAPI.@)
815 SETUP_CreateClassKey(HINF hInf
);
817 SetupDiInstallClassExW(
818 IN HWND hwndParent OPTIONAL
,
819 IN PCWSTR InfFileName OPTIONAL
,
821 IN HSPFILEQ FileQueue OPTIONAL
,
822 IN CONST GUID
*InterfaceClassGuid OPTIONAL
,
828 TRACE("%p %s 0x%lx %p %s %p %p\n", hwndParent
, debugstr_w(InfFileName
), Flags
,
829 FileQueue
, debugstr_guid(InterfaceClassGuid
), Reserved1
, Reserved2
);
833 FIXME("Case not implemented: InfFileName NULL\n");
834 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
836 else if (Flags
& ~(DI_NOVCP
| DI_NOBROWSE
| DI_FORCECOPY
| DI_QUIETINSTALL
))
838 TRACE("Unknown flags: 0x%08lx\n", Flags
& ~(DI_NOVCP
| DI_NOBROWSE
| DI_FORCECOPY
| DI_QUIETINSTALL
));
839 SetLastError(ERROR_INVALID_FLAGS
);
841 else if ((Flags
& DI_NOVCP
) && FileQueue
== NULL
)
842 SetLastError(ERROR_INVALID_PARAMETER
);
843 else if (Reserved1
!= NULL
)
844 SetLastError(ERROR_INVALID_PARAMETER
);
845 else if (Reserved2
!= NULL
)
846 SetLastError(ERROR_INVALID_PARAMETER
);
849 HDEVINFO hDeviceInfo
= INVALID_HANDLE_VALUE
;
850 SP_DEVINSTALL_PARAMS_W InstallParams
;
851 WCHAR SectionName
[MAX_PATH
];
852 HINF hInf
= INVALID_HANDLE_VALUE
;
853 HKEY hRootKey
= INVALID_HANDLE_VALUE
;
854 PVOID callback_context
= NULL
;
856 hDeviceInfo
= SetupDiCreateDeviceInfoList(NULL
, NULL
);
857 if (hDeviceInfo
== INVALID_HANDLE_VALUE
)
860 InstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS
);
861 if (!SetupDiGetDeviceInstallParamsW(hDeviceInfo
, NULL
, &InstallParams
))
864 InstallParams
.Flags
&= ~(DI_NOVCP
| DI_NOBROWSE
| DI_QUIETINSTALL
);
865 InstallParams
.Flags
|= Flags
& (DI_NOVCP
| DI_NOBROWSE
| DI_QUIETINSTALL
);
866 if (Flags
& DI_NOVCP
)
867 InstallParams
.FileQueue
= FileQueue
;
868 if (!SetupDiSetDeviceInstallParamsW(hDeviceInfo
, NULL
, &InstallParams
))
871 /* Open the .inf file */
872 hInf
= SetupOpenInfFileW(
877 if (hInf
== INVALID_HANDLE_VALUE
)
880 /* Try to append a layout file */
881 SetupOpenAppendInfFileW(NULL
, hInf
, NULL
);
883 if (InterfaceClassGuid
)
885 /* Retrieve the actual section name */
886 ret
= SetupDiGetActualSectionToInstallW(
896 /* Open registry key related to this interface */
897 /* FIXME: What happens if the key doesn't exist? */
898 hRootKey
= SetupDiOpenClassRegKeyExW(InterfaceClassGuid
, KEY_ENUMERATE_SUB_KEYS
, DIOCR_INTERFACE
, NULL
, NULL
);
899 if (hRootKey
== INVALID_HANDLE_VALUE
)
902 /* SetupDiCreateDeviceInterface??? */
903 FIXME("Installing an interface is not implemented\n");
904 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
908 /* Create or open the class registry key 'HKLM\CurrentControlSet\Class\{GUID}' */
909 hRootKey
= SETUP_CreateClassKey(hInf
);
910 if (hRootKey
== INVALID_HANDLE_VALUE
)
913 /* Retrieve the actual section name */
914 ret
= SetupDiGetActualSectionToInstallW(
918 MAX_PATH
- strlenW(DotServices
),
924 callback_context
= SetupInitDefaultQueueCallback(hwndParent
);
925 if (!callback_context
)
928 ret
= SetupInstallFromInfSectionW(
932 SPINST_REGISTRY
| SPINST_FILES
| SPINST_BITREG
| SPINST_INIFILES
| SPINST_INI2REG
,
934 NULL
, /* FIXME: SourceRootPath */
935 !(Flags
& DI_NOVCP
) && (Flags
& DI_FORCECOPY
) ? SP_COPY_FORCE_IN_USE
: 0, /* CopyFlags */
936 SetupDefaultQueueCallbackW
,
943 /* OPTIONAL: Install .Services section */
944 lstrcatW(SectionName
, DotServices
);
945 SetupInstallServicesFromInfSectionExW(
957 if (hDeviceInfo
!= INVALID_HANDLE_VALUE
)
958 SetupDiDestroyDeviceInfoList(hDeviceInfo
);
959 if (hInf
!= INVALID_HANDLE_VALUE
)
960 SetupCloseInfFile(hInf
);
961 if (hRootKey
!= INVALID_HANDLE_VALUE
)
962 RegCloseKey(hRootKey
);
963 SetupTermDefaultQueueCallback(callback_context
);
966 TRACE("Returning %d\n", ret
);
970 /***********************************************************************
971 * Helper functions for SetupDiSetClassInstallParamsW
974 SETUP_PropertyChangeHandler(
975 IN HDEVINFO DeviceInfoSet
,
976 IN PSP_DEVINFO_DATA DeviceInfoData
,
977 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
978 IN DWORD ClassInstallParamsSize
)
980 PSP_PROPCHANGE_PARAMS PropChangeParams
= (PSP_PROPCHANGE_PARAMS
)ClassInstallParams
;
984 SetLastError(ERROR_INVALID_PARAMETER
);
985 else if (ClassInstallParamsSize
!= sizeof(SP_PROPCHANGE_PARAMS
))
986 SetLastError(ERROR_INVALID_PARAMETER
);
987 else if (PropChangeParams
&& PropChangeParams
->StateChange
!= DICS_ENABLE
988 && PropChangeParams
->StateChange
!= DICS_DISABLE
&& PropChangeParams
->StateChange
!= DICS_PROPCHANGE
989 && PropChangeParams
->StateChange
!= DICS_START
&& PropChangeParams
->StateChange
!= DICS_STOP
)
990 SetLastError(ERROR_INVALID_FLAGS
);
991 else if (PropChangeParams
&& PropChangeParams
->Scope
!= DICS_FLAG_GLOBAL
992 && PropChangeParams
->Scope
!= DICS_FLAG_CONFIGSPECIFIC
)
993 SetLastError(ERROR_INVALID_FLAGS
);
994 else if (PropChangeParams
995 && (PropChangeParams
->StateChange
== DICS_START
|| PropChangeParams
->StateChange
== DICS_STOP
)
996 && PropChangeParams
->Scope
!= DICS_FLAG_CONFIGSPECIFIC
)
997 SetLastError(ERROR_INVALID_USER_BUFFER
);
1000 PSP_PROPCHANGE_PARAMS
*CurrentPropChangeParams
;
1001 struct DeviceInfo
*deviceInfo
= (struct DeviceInfo
*)DeviceInfoData
->Reserved
;
1002 CurrentPropChangeParams
= &deviceInfo
->ClassInstallParams
.PropChangeParams
;
1004 if (*CurrentPropChangeParams
)
1006 MyFree(*CurrentPropChangeParams
);
1007 *CurrentPropChangeParams
= NULL
;
1009 if (PropChangeParams
)
1011 *CurrentPropChangeParams
= MyMalloc(ClassInstallParamsSize
);
1012 if (!*CurrentPropChangeParams
)
1014 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1017 memcpy(*CurrentPropChangeParams
, PropChangeParams
, ClassInstallParamsSize
);
1027 SETUP_PropertyAddPropertyAdvancedHandler(
1028 IN HDEVINFO DeviceInfoSet
,
1029 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
1030 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
1031 IN DWORD ClassInstallParamsSize
)
1033 PSP_ADDPROPERTYPAGE_DATA AddPropertyPageData
= (PSP_ADDPROPERTYPAGE_DATA
)ClassInstallParams
;
1036 if (ClassInstallParamsSize
!= sizeof(SP_PROPCHANGE_PARAMS
))
1037 SetLastError(ERROR_INVALID_PARAMETER
);
1038 else if (AddPropertyPageData
&& AddPropertyPageData
->Flags
!= 0)
1039 SetLastError(ERROR_INVALID_FLAGS
);
1040 else if (AddPropertyPageData
&& AddPropertyPageData
->NumDynamicPages
>= MAX_INSTALLWIZARD_DYNAPAGES
)
1041 SetLastError(ERROR_INVALID_USER_BUFFER
);
1044 PSP_ADDPROPERTYPAGE_DATA
*CurrentAddPropertyPageData
;
1045 if (!DeviceInfoData
)
1047 struct DeviceInfoSet
*list
= (struct DeviceInfoSet
*)DeviceInfoSet
;
1048 CurrentAddPropertyPageData
= &list
->ClassInstallParams
.AddPropertyPageData
;
1052 struct DeviceInfo
*deviceInfo
= (struct DeviceInfo
*)DeviceInfoData
->Reserved
;
1053 CurrentAddPropertyPageData
= &deviceInfo
->ClassInstallParams
.AddPropertyPageData
;
1055 if (*CurrentAddPropertyPageData
)
1057 MyFree(*CurrentAddPropertyPageData
);
1058 *CurrentAddPropertyPageData
= NULL
;
1060 if (AddPropertyPageData
)
1062 *CurrentAddPropertyPageData
= MyMalloc(ClassInstallParamsSize
);
1063 if (!*CurrentAddPropertyPageData
)
1065 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1068 memcpy(*CurrentAddPropertyPageData
, AddPropertyPageData
, ClassInstallParamsSize
);
1077 /***********************************************************************
1078 * SetupDiSetClassInstallParamsW (SETUPAPI.@)
1081 SetupDiSetClassInstallParamsW(
1082 IN HDEVINFO DeviceInfoSet
,
1083 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
1084 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL
,
1085 IN DWORD ClassInstallParamsSize
)
1087 struct DeviceInfoSet
*list
;
1090 TRACE("%p %p %p %lu\n", DeviceInfoSet
, DeviceInfoData
,
1091 ClassInstallParams
, ClassInstallParamsSize
);
1094 SetLastError(ERROR_INVALID_PARAMETER
);
1095 else if (DeviceInfoSet
== (HDEVINFO
)INVALID_HANDLE_VALUE
)
1096 SetLastError(ERROR_INVALID_HANDLE
);
1097 else if ((list
= (struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEVICE_INFO_SET_MAGIC
)
1098 SetLastError(ERROR_INVALID_HANDLE
);
1099 else if (DeviceInfoData
&& DeviceInfoData
->cbSize
!= sizeof(SP_DEVINFO_DATA
))
1100 SetLastError(ERROR_INVALID_USER_BUFFER
);
1101 else if (ClassInstallParams
&& ClassInstallParams
->cbSize
!= sizeof(SP_CLASSINSTALL_HEADER
))
1102 SetLastError(ERROR_INVALID_USER_BUFFER
);
1103 else if (ClassInstallParams
&& ClassInstallParamsSize
< sizeof(SP_CLASSINSTALL_HEADER
))
1104 SetLastError(ERROR_INVALID_PARAMETER
);
1105 else if (!ClassInstallParams
&& ClassInstallParamsSize
!= 0)
1106 SetLastError(ERROR_INVALID_PARAMETER
);
1109 SP_DEVINSTALL_PARAMS_W InstallParams
;
1112 InstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS_W
);
1113 Result
= SetupDiGetDeviceInstallParamsW(DeviceInfoSet
, DeviceInfoData
, &InstallParams
);
1117 if (ClassInstallParams
)
1120 /* Check parameters in ClassInstallParams */
1121 for (i
= 0; i
< sizeof(InstallParamsData
) / sizeof(InstallParamsData
[0]); i
++)
1123 if (InstallParamsData
[i
].Function
== ClassInstallParams
->InstallFunction
)
1125 ret
= InstallParamsData
[i
].UpdateHandler(
1129 ClassInstallParamsSize
);
1132 InstallParams
.Flags
|= DI_CLASSINSTALLPARAMS
;
1133 ret
= SetupDiSetDeviceInstallParamsW(DeviceInfoSet
, DeviceInfoData
, &InstallParams
);
1138 ERR("InstallFunction %u has no associated update handler\n", ClassInstallParams
->InstallFunction
);
1139 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1144 InstallParams
.Flags
&= ~DI_CLASSINSTALLPARAMS
;
1145 ret
= SetupDiSetDeviceInstallParamsW(DeviceInfoSet
, DeviceInfoData
, &InstallParams
);
1150 TRACE("Returning %d\n", ret
);
1154 /***********************************************************************
1155 * SetupDiGetClassDevPropertySheetsA(SETUPAPI.@)
1158 SetupDiGetClassDevPropertySheetsA(
1159 IN HDEVINFO DeviceInfoSet
,
1160 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
1161 IN LPPROPSHEETHEADERA PropertySheetHeader
,
1162 IN DWORD PropertySheetHeaderPageListSize
,
1163 OUT PDWORD RequiredSize OPTIONAL
,
1164 IN DWORD PropertySheetType
)
1166 PROPSHEETHEADERW psh
;
1169 TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet
, DeviceInfoData
,
1170 PropertySheetHeader
, PropertySheetHeaderPageListSize
,
1171 RequiredSize
, PropertySheetType
);
1173 psh
.dwFlags
= PropertySheetHeader
->dwFlags
;
1174 psh
.phpage
= PropertySheetHeader
->phpage
;
1175 psh
.nPages
= PropertySheetHeader
->nPages
;
1177 ret
= SetupDiGetClassDevPropertySheetsW(DeviceInfoSet
, DeviceInfoData
, PropertySheetHeader
? &psh
: NULL
,
1178 PropertySheetHeaderPageListSize
, RequiredSize
,
1182 PropertySheetHeader
->nPages
= psh
.nPages
;
1185 TRACE("Returning %d\n", ret
);
1189 struct ClassDevPropertySheetsData
1191 LPPROPSHEETHEADERW PropertySheetHeader
;
1192 DWORD PropertySheetHeaderPageListSize
;
1193 DWORD NumberOfPages
;
1198 SETUP_GetClassDevPropertySheetsCallback(
1199 IN HPROPSHEETPAGE hPropSheetPage
,
1200 IN OUT LPARAM lParam
)
1202 struct ClassDevPropertySheetsData
*PropPageData
;
1204 PropPageData
= (struct ClassDevPropertySheetsData
*)lParam
;
1206 PropPageData
->NumberOfPages
++;
1208 if (PropPageData
->PropertySheetHeader
->nPages
< PropPageData
->PropertySheetHeaderPageListSize
)
1210 PropPageData
->PropertySheetHeader
->phpage
[PropPageData
->PropertySheetHeader
->nPages
] = hPropSheetPage
;
1211 PropPageData
->PropertySheetHeader
->nPages
++;
1215 return PropPageData
->DontCancel
;
1218 /***********************************************************************
1219 * SetupDiGetClassDevPropertySheetsW(SETUPAPI.@)
1222 SetupDiGetClassDevPropertySheetsW(
1223 IN HDEVINFO DeviceInfoSet
,
1224 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
,
1225 IN OUT LPPROPSHEETHEADERW PropertySheetHeader
,
1226 IN DWORD PropertySheetHeaderPageListSize
,
1227 OUT PDWORD RequiredSize OPTIONAL
,
1228 IN DWORD PropertySheetType
)
1230 struct DeviceInfoSet
*list
;
1233 TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet
, DeviceInfoData
,
1234 PropertySheetHeader
, PropertySheetHeaderPageListSize
,
1235 RequiredSize
, PropertySheetType
);
1238 SetLastError(ERROR_INVALID_HANDLE
);
1239 else if (((struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEVICE_INFO_SET_MAGIC
)
1240 SetLastError(ERROR_INVALID_HANDLE
);
1241 else if ((list
= (struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEVICE_INFO_SET_MAGIC
)
1242 SetLastError(ERROR_INVALID_HANDLE
);
1243 else if (!PropertySheetHeader
)
1244 SetLastError(ERROR_INVALID_PARAMETER
);
1245 else if (PropertySheetHeader
->dwFlags
& PSH_PROPSHEETPAGE
)
1246 SetLastError(ERROR_INVALID_FLAGS
);
1247 else if (DeviceInfoData
&& DeviceInfoData
->cbSize
!= sizeof(SP_DEVINFO_DATA
))
1248 SetLastError(ERROR_INVALID_USER_BUFFER
);
1249 else if (!DeviceInfoData
&& IsEqualIID(&list
->ClassGuid
, &GUID_NULL
))
1250 SetLastError(ERROR_INVALID_PARAMETER
);
1251 else if (PropertySheetType
!= DIGCDP_FLAG_ADVANCED
1252 && PropertySheetType
!= DIGCDP_FLAG_BASIC
1253 && PropertySheetType
!= DIGCDP_FLAG_REMOTE_ADVANCED
1254 && PropertySheetType
!= DIGCDP_FLAG_REMOTE_BASIC
)
1255 SetLastError(ERROR_INVALID_PARAMETER
);
1258 HKEY hKey
= INVALID_HANDLE_VALUE
;
1259 SP_PROPSHEETPAGE_REQUEST Request
;
1260 LPWSTR PropPageProvider
= NULL
;
1261 HMODULE hModule
= NULL
;
1262 PROPERTY_PAGE_PROVIDER pPropPageProvider
= NULL
;
1263 struct ClassDevPropertySheetsData PropPageData
;
1264 DWORD dwLength
, dwRegType
;
1265 DWORD InitialNumberOfPages
;
1269 hKey
= SetupDiOpenDevRegKey(DeviceInfoSet
, DeviceInfoData
, DICS_FLAG_GLOBAL
, 0, DIREG_DRV
, KEY_QUERY_VALUE
);
1272 hKey
= SetupDiOpenClassRegKeyExW(&list
->ClassGuid
, KEY_QUERY_VALUE
,
1273 DIOCR_INSTALLER
, list
->MachineName
+ 2, NULL
);
1275 if (hKey
== INVALID_HANDLE_VALUE
)
1278 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, &dwRegType
, NULL
, &dwLength
);
1279 if (rc
== ERROR_FILE_NOT_FOUND
)
1281 /* No registry key. As it is optional, don't say it's a bad error */
1287 else if (rc
!= ERROR_SUCCESS
&& dwRegType
!= REG_SZ
)
1293 PropPageProvider
= HeapAlloc(GetProcessHeap(), 0, dwLength
+ sizeof(WCHAR
));
1294 if (!PropPageProvider
)
1296 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1299 rc
= RegQueryValueExW(hKey
, REGSTR_VAL_ENUMPROPPAGES_32
, NULL
, NULL
, (LPBYTE
)PropPageProvider
, &dwLength
);
1300 if (rc
!= ERROR_SUCCESS
)
1305 PropPageProvider
[dwLength
/ sizeof(WCHAR
)] = 0;
1307 rc
= GetFunctionPointer(PropPageProvider
, &hModule
, (PVOID
*)&pPropPageProvider
);
1308 if (rc
!= ERROR_SUCCESS
)
1310 SetLastError(ERROR_INVALID_PROPPAGE_PROVIDER
);
1316 struct DeviceInfo
*devInfo
= (struct DeviceInfo
*)DeviceInfoData
->Reserved
;
1318 if (devInfo
->hmodDevicePropPageProvider
== NULL
)
1320 devInfo
->hmodDevicePropPageProvider
= hModule
;
1321 devInfo
->pDevicePropPageProvider
= pPropPageProvider
;
1326 struct DeviceInfoSet
*devInfoSet
= (struct DeviceInfoSet
*)DeviceInfoSet
;
1328 if (devInfoSet
->hmodClassPropPageProvider
== NULL
)
1330 devInfoSet
->hmodClassPropPageProvider
= hModule
;
1331 devInfoSet
->pClassPropPageProvider
= pPropPageProvider
;
1335 InitialNumberOfPages
= PropertySheetHeader
->nPages
;
1337 Request
.cbSize
= sizeof(SP_PROPSHEETPAGE_REQUEST
);
1338 Request
.PageRequested
= SPPSR_ENUM_ADV_DEVICE_PROPERTIES
;
1339 Request
.DeviceInfoSet
= DeviceInfoSet
;
1340 Request
.DeviceInfoData
= DeviceInfoData
;
1342 PropPageData
.PropertySheetHeader
= PropertySheetHeader
;
1343 PropPageData
.PropertySheetHeaderPageListSize
= PropertySheetHeaderPageListSize
;
1344 PropPageData
.NumberOfPages
= 0;
1345 PropPageData
.DontCancel
= (RequiredSize
!= NULL
) ? TRUE
: FALSE
;
1347 pPropPageProvider(&Request
, SETUP_GetClassDevPropertySheetsCallback
, (LPARAM
)&PropPageData
);
1350 *RequiredSize
= PropPageData
.NumberOfPages
;
1352 if (InitialNumberOfPages
+ PropPageData
.NumberOfPages
<= PropertySheetHeaderPageListSize
)
1358 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1362 if (hKey
!= INVALID_HANDLE_VALUE
)
1364 HeapFree(GetProcessHeap(), 0, PropPageProvider
);
1367 TRACE("Returning %d\n", ret
);