872 lines
31 KiB
C
872 lines
31 KiB
C
/*++
|
|
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
devprop.c
|
|
|
|
Abstract:
|
|
|
|
Device Installer functions for property sheet support.
|
|
|
|
Author:
|
|
|
|
Lonny McMichael (lonnym) 07-Sep-1995
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
//
|
|
// Private routine prototypes.
|
|
//
|
|
BOOL
|
|
CALLBACK
|
|
pSetupAddPropPage(
|
|
IN HPROPSHEETPAGE hPage,
|
|
IN LPARAM lParam
|
|
);
|
|
|
|
|
|
//
|
|
// Define the context structure that gets passed to pSetupAddPropPage as lParam.
|
|
//
|
|
typedef struct _SP_PROPPAGE_ADDPROC_CONTEXT {
|
|
|
|
BOOL NoCancelOnFailure; // input
|
|
LPPROPSHEETHEADER PropertySheetHeader; // input
|
|
DWORD PageListSize; // input
|
|
DWORD NumPages; // output
|
|
|
|
} SP_PROPPAGE_ADDPROC_CONTEXT, *PSP_PROPPAGE_ADDPROC_CONTEXT;
|
|
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// ANSI version
|
|
//
|
|
BOOL
|
|
WINAPI
|
|
SetupDiGetClassDevPropertySheetsA(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
|
|
IN LPPROPSHEETHEADERA PropertySheetHeader,
|
|
IN DWORD PropertySheetHeaderPageListSize,
|
|
OUT PDWORD RequiredSize, OPTIONAL
|
|
IN DWORD PropertySheetType
|
|
)
|
|
{
|
|
PROPSHEETHEADERW UnicodePropertySheetHeader;
|
|
DWORD Err = NO_ERROR;
|
|
|
|
//
|
|
// Make sure we're running interactively.
|
|
//
|
|
if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
|
|
SetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// None of the fields that we care about in this structure contain
|
|
// characters. Thus, we'll simply copy over the fields we need into
|
|
// our unicode property sheet header, and pass that into the W-API.
|
|
//
|
|
// The fields that we care about are the following:
|
|
//
|
|
// dwFlags (in)
|
|
// nPages (in/out)
|
|
// phpage (in/out)
|
|
//
|
|
ZeroMemory(&UnicodePropertySheetHeader, sizeof(UnicodePropertySheetHeader));
|
|
|
|
try {
|
|
|
|
UnicodePropertySheetHeader.dwFlags = PropertySheetHeader->dwFlags;
|
|
UnicodePropertySheetHeader.nPages = PropertySheetHeader->nPages;
|
|
UnicodePropertySheetHeader.phpage = PropertySheetHeader->phpage;
|
|
|
|
if(SetupDiGetClassDevPropertySheetsW(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
&UnicodePropertySheetHeader,
|
|
PropertySheetHeaderPageListSize,
|
|
RequiredSize,
|
|
PropertySheetType)) {
|
|
|
|
PropertySheetHeader->nPages = UnicodePropertySheetHeader.nPages;
|
|
PropertySheetHeader->phpage = UnicodePropertySheetHeader.phpage;
|
|
|
|
} else {
|
|
Err = GetLastError();
|
|
}
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
SetLastError(Err);
|
|
return(Err == NO_ERROR);
|
|
}
|
|
#else
|
|
//
|
|
// Unicode stub
|
|
//
|
|
BOOL
|
|
WINAPI
|
|
SetupDiGetClassDevPropertySheetsW(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
|
|
IN LPPROPSHEETHEADERW PropertySheetHeader,
|
|
IN DWORD PropertySheetHeaderPageListSize,
|
|
OUT PDWORD RequiredSize, OPTIONAL
|
|
IN DWORD PropertySheetType
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(DeviceInfoSet);
|
|
UNREFERENCED_PARAMETER(DeviceInfoData);
|
|
UNREFERENCED_PARAMETER(PropertySheetHeader);
|
|
UNREFERENCED_PARAMETER(PropertySheetHeaderPageListSize);
|
|
UNREFERENCED_PARAMETER(RequiredSize);
|
|
UNREFERENCED_PARAMETER(PropertySheetType);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupDiGetClassDevPropertySheets(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
|
|
IN LPPROPSHEETHEADER PropertySheetHeader,
|
|
IN DWORD PropertySheetHeaderPageListSize,
|
|
OUT PDWORD RequiredSize, OPTIONAL
|
|
IN DWORD PropertySheetType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine adds property sheets to the supplied property sheet
|
|
header for the device information set or element.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - Supplies a handle to the device information set for
|
|
which property sheets are to be retrieved.
|
|
|
|
DeviceInfoData - Optionally, supplies the address of a SP_DEVINFO_DATA
|
|
structure for which property sheets are to be retrieved. If this
|
|
parameter is not specified, then property sheets are retrieved based
|
|
on the global class driver list associated with the device information
|
|
set itself.
|
|
|
|
PropertySheetHeader - Supplies the property sheet header to which the
|
|
property sheets are to be added.
|
|
|
|
NOTE: PropertySheetHeader->dwFlags _must not_ have the PSH_PROPSHEETPAGE
|
|
flag set, or this API will fail with ERROR_INVALID_FLAGS.
|
|
|
|
PropertySheetHeaderPageListSize - Specifies the size of the
|
|
HPROPSHEETPAGE array pointed to by the PropertySheetHeader->phpage.
|
|
Note that this is _not_ the same value as PropertySheetHeader->nPages.
|
|
The latter specifies the number of page handles currently in the
|
|
list. The number of pages that may be added by this routine equals
|
|
PropertySheetHeaderPageListSize - PropertySheetHeader->nPages. If the
|
|
property page provider attempts to add more pages than the property
|
|
sheet header list can hold, this API will fail, and GetLastError will
|
|
return ERROR_INSUFFICIENT_BUFFER. However, any pages that have already
|
|
been added will be in the PropertySheetHeader->phpage list, and the
|
|
nPages field will contain the correct count. It is the caller's
|
|
responsibility to destroy all property page handles in this list via
|
|
DestroyPropertySheetPage (unless the caller goes ahead and uses
|
|
PropertySheetHeader in a call to PropertySheet).
|
|
|
|
RequiredSize - Optionally, supplies the address of a variable that receives
|
|
the number of property page handles added to the PropertySheetHeader. If
|
|
this API fails with ERROR_INSUFFICIENT_BUFFER, this variable will be set
|
|
to the total number of property pages that the property page provider(s)
|
|
_attempted to add_ (i.e., including those which were not successfully
|
|
added because the PropertySheetHeader->phpage array wasn't big enough).
|
|
|
|
Note: This number will not equal PropertySheetHeader->nPages upon return
|
|
if either (a) there were already property pages in the list before this
|
|
API was called, or (b) the call failed with ERROR_INSUFFICIENT_BUFFER.
|
|
|
|
PropertySheetType - Specifies what type of property sheets are to be
|
|
retrieved. May be one of the following values:
|
|
|
|
DIGCDP_FLAG_BASIC - Retrieve basic property sheets (typically, for
|
|
CPL applets).
|
|
|
|
DIGCDP_FLAG_ADVANCED - Retrieve advanced property sheets (typically,
|
|
for the Device Manager).
|
|
|
|
DIGCDP_FLAG_REMOTE_BASIC - Currently not used.
|
|
|
|
DIGCDP_FLAG_REMOTE_ADVANCED - Retrieve advanced property sheets for a device
|
|
on a remote machine (typically, for the Device
|
|
Manager).
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is TRUE.
|
|
|
|
If the function fails, the return value is FALSE. To get extended error
|
|
information, call GetLastError.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVICE_INFO_SET pDeviceInfoSet;
|
|
DWORD Err;
|
|
PDEVINFO_ELEM DevInfoElem;
|
|
PDEVINSTALL_PARAM_BLOCK InstallParamBlock;
|
|
LPGUID ClassGuid;
|
|
HKEY hk;
|
|
SP_PROPSHEETPAGE_REQUEST PropPageRequest;
|
|
SP_PROPPAGE_ADDPROC_CONTEXT PropPageAddProcContext;
|
|
SP_ADDPROPERTYPAGE_DATA PropertyPageData;
|
|
UINT OriginalPageCount;
|
|
SPFUSIONINSTANCE spFusionInstance;
|
|
|
|
//
|
|
// Make sure we're running interactively.
|
|
//
|
|
if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
|
|
SetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Make sure the caller passed us a valid PropertySheetType.
|
|
//
|
|
if((PropertySheetType != DIGCDP_FLAG_BASIC) &&
|
|
(PropertySheetType != DIGCDP_FLAG_ADVANCED) &&
|
|
(PropertySheetType != DIGCDP_FLAG_REMOTE_ADVANCED)) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
Err = NO_ERROR;
|
|
DevInfoElem = NULL;
|
|
hk = INVALID_HANDLE_VALUE;
|
|
|
|
try {
|
|
//
|
|
// Make sure the property sheet header doesn't have the PSH_PROPSHEETPAGE flag set.
|
|
//
|
|
if(PropertySheetHeader->dwFlags & PSH_PROPSHEETPAGE) {
|
|
Err = ERROR_INVALID_FLAGS;
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Also, ensure that the parts of the property sheet header we'll be dealing with
|
|
// look reasonable.
|
|
//
|
|
OriginalPageCount = PropertySheetHeader->nPages;
|
|
|
|
if((OriginalPageCount > PropertySheetHeaderPageListSize) ||
|
|
(PropertySheetHeaderPageListSize && !(PropertySheetHeader->phpage))) {
|
|
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
goto clean0;
|
|
}
|
|
|
|
if(DeviceInfoData) {
|
|
//
|
|
// Then we are to retrieve property sheets for a particular device.
|
|
//
|
|
if(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
|
|
DeviceInfoData,
|
|
NULL))
|
|
{
|
|
InstallParamBlock = &(DevInfoElem->InstallParamBlock);
|
|
ClassGuid = &(DevInfoElem->ClassGuid);
|
|
|
|
} else {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
goto clean0;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// We're retrieving (advanced) property pages for the set's class.
|
|
//
|
|
if(pDeviceInfoSet->HasClassGuid) {
|
|
InstallParamBlock = &(pDeviceInfoSet->InstallParamBlock);
|
|
ClassGuid = &(pDeviceInfoSet->ClassGuid);
|
|
} else {
|
|
Err = ERROR_NO_ASSOCIATED_CLASS;
|
|
goto clean0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Fill in a property sheet request structure for later use.
|
|
//
|
|
PropPageRequest.cbSize = sizeof(SP_PROPSHEETPAGE_REQUEST);
|
|
PropPageRequest.DeviceInfoSet = DeviceInfoSet;
|
|
PropPageRequest.DeviceInfoData = DeviceInfoData;
|
|
|
|
//
|
|
// Fill in the context structure for use later on by our AddPropPageProc
|
|
// callback.
|
|
//
|
|
PropPageAddProcContext.PropertySheetHeader = PropertySheetHeader;
|
|
PropPageAddProcContext.PageListSize = PropertySheetHeaderPageListSize;
|
|
PropPageAddProcContext.NumPages = 0;
|
|
//
|
|
// If the caller supplied the RequiredSize output parameter, then we don't
|
|
// want to abort the callback process, even if we run out of space in the
|
|
// hPage list.
|
|
//
|
|
PropPageAddProcContext.NoCancelOnFailure = RequiredSize ? TRUE : FALSE;
|
|
|
|
|
|
//
|
|
// Check if we should be getting Basic or Advanced Property Sheets.
|
|
// Essentially, CPL's will want BASIC sheets, and the Device Manager
|
|
// will want advanced sheets.
|
|
//
|
|
switch (PropertySheetType) {
|
|
|
|
case DIGCDP_FLAG_BASIC:
|
|
//
|
|
// The BasicProperties32 entrypoint is only supplied via a device's
|
|
// driver key. Thus, a device information element must be specified
|
|
// when basic property pages are requested.
|
|
//
|
|
// NOTE: this is different from setupx, which enumerates _all_ lpdi's
|
|
// in the list, retrieving basic properties for each. This doesn't
|
|
// seem to have any practical application, and if it is really
|
|
// required, then the caller can loop through each devinfo element
|
|
// themselves, and retrieve basic property pages for each one.
|
|
//
|
|
if(!DevInfoElem) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// If the basic property page provider has not been loaded, then load
|
|
// it and get the function address for the BasicProperties32 function.
|
|
//
|
|
if(!InstallParamBlock->hinstBasicPropProvider) {
|
|
|
|
hk = SetupDiOpenDevRegKey(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
DICS_FLAG_GLOBAL,
|
|
0,
|
|
DIREG_DRV,
|
|
KEY_READ
|
|
);
|
|
|
|
if(hk != INVALID_HANDLE_VALUE) {
|
|
|
|
try {
|
|
Err = GetModuleEntryPoint(hk,
|
|
pszBasicProperties32,
|
|
pszBasicPropDefaultProc,
|
|
&(InstallParamBlock->hinstBasicPropProvider),
|
|
&((FARPROC)InstallParamBlock->EnumBasicPropertiesEntryPoint),
|
|
&(InstallParamBlock->EnumBasicPropertiesFusionContext),
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
SetupapiVerifyNoProblem,
|
|
NULL,
|
|
DRIVERSIGN_NONE,
|
|
TRUE,
|
|
NULL
|
|
);
|
|
|
|
if(Err == ERROR_DI_DO_DEFAULT) {
|
|
//
|
|
// The BasicProperties32 value wasn't present--this is not an error.
|
|
//
|
|
Err = NO_ERROR;
|
|
|
|
} else if(Err != NO_ERROR) {
|
|
Err = ERROR_INVALID_PROPPAGE_PROVIDER;
|
|
}
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PROPPAGE_PROVIDER;
|
|
InstallParamBlock->EnumBasicPropertiesEntryPoint = NULL;
|
|
}
|
|
|
|
RegCloseKey(hk);
|
|
hk = INVALID_HANDLE_VALUE;
|
|
|
|
if(Err != NO_ERROR) {
|
|
goto clean0;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If there is a basic property page provider entry point, then call it.
|
|
//
|
|
if(InstallParamBlock->EnumBasicPropertiesEntryPoint) {
|
|
|
|
PropPageRequest.PageRequested = SPPSR_ENUM_BASIC_DEVICE_PROPERTIES;
|
|
|
|
//
|
|
// We must first release the HDEVINFO lock, so we don't run into any weird
|
|
// deadlock issues
|
|
//
|
|
UnlockDeviceInfoSet(pDeviceInfoSet);
|
|
pDeviceInfoSet = NULL;
|
|
|
|
spFusionEnterContext(InstallParamBlock->EnumBasicPropertiesFusionContext,
|
|
&spFusionInstance);
|
|
try {
|
|
InstallParamBlock->EnumBasicPropertiesEntryPoint(
|
|
&PropPageRequest,
|
|
pSetupAddPropPage,
|
|
(LPARAM)&PropPageAddProcContext
|
|
);
|
|
} finally {
|
|
spFusionLeaveContext(&spFusionInstance);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now use the new DIF_ADDPROPERTYPAGE_BASIC call to see if any
|
|
// class-/co-installers want to add basic property pages as well.
|
|
//
|
|
memset(&PropertyPageData, 0, sizeof(SP_ADDPROPERTYPAGE_DATA));
|
|
PropertyPageData.ClassInstallHeader.InstallFunction = DIF_ADDPROPERTYPAGE_BASIC;
|
|
PropertyPageData.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
|
|
PropertyPageData.hwndWizardDlg = PropertySheetHeader->hwndParent;
|
|
|
|
Err = DoInstallActionWithParams(DIF_ADDPROPERTYPAGE_BASIC,
|
|
DeviceInfoSet,
|
|
DeviceInfoData,
|
|
&PropertyPageData.ClassInstallHeader,
|
|
sizeof(SP_ADDPROPERTYPAGE_DATA),
|
|
INSTALLACTION_CALL_CI);
|
|
|
|
if (ERROR_DI_DO_DEFAULT == Err) {
|
|
|
|
//
|
|
// The class-/co-installers do not have any pages to add--this is not an error.
|
|
//
|
|
Err = NO_ERROR;
|
|
}
|
|
|
|
if ((NO_ERROR == Err) &&
|
|
(PropertyPageData.NumDynamicPages > 0))
|
|
{
|
|
DWORD NumPages = 0;
|
|
|
|
while (NumPages < PropertyPageData.NumDynamicPages) {
|
|
|
|
pSetupAddPropPage(PropertyPageData.DynamicPages[NumPages++],
|
|
(LPARAM)&PropPageAddProcContext
|
|
);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DIGCDP_FLAG_ADVANCED:
|
|
//
|
|
// We're retrieving advanced property pages. We want to look for EnumPropPages32
|
|
// entries in both the class key and (if we're talking about a specific device) in
|
|
// the device's driver key.
|
|
//
|
|
if(!InstallParamBlock->hinstClassPropProvider) {
|
|
|
|
hk = SetupDiOpenClassRegKey(ClassGuid, KEY_READ);
|
|
|
|
if(hk != INVALID_HANDLE_VALUE) {
|
|
|
|
try {
|
|
Err = GetModuleEntryPoint(hk,
|
|
pszEnumPropPages32,
|
|
pszEnumPropDefaultProc,
|
|
&(InstallParamBlock->hinstClassPropProvider),
|
|
&((FARPROC)InstallParamBlock->ClassEnumPropPagesEntryPoint),
|
|
&(InstallParamBlock->ClassEnumPropPagesFusionContext),
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
SetupapiVerifyNoProblem,
|
|
NULL,
|
|
DRIVERSIGN_NONE,
|
|
TRUE,
|
|
NULL
|
|
);
|
|
|
|
if(Err == ERROR_DI_DO_DEFAULT) {
|
|
//
|
|
// The EnumPropPages32 value wasn't present--this is not an error.
|
|
//
|
|
Err = NO_ERROR;
|
|
|
|
} else if(Err != NO_ERROR) {
|
|
Err = ERROR_INVALID_PROPPAGE_PROVIDER;
|
|
}
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PROPPAGE_PROVIDER;
|
|
InstallParamBlock->ClassEnumPropPagesEntryPoint = NULL;
|
|
}
|
|
|
|
RegCloseKey(hk);
|
|
hk = INVALID_HANDLE_VALUE;
|
|
|
|
if(Err != NO_ERROR) {
|
|
goto clean0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(DevInfoElem && !InstallParamBlock->hinstDevicePropProvider) {
|
|
|
|
hk = SetupDiOpenDevRegKey(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
DICS_FLAG_GLOBAL,
|
|
0,
|
|
DIREG_DRV,
|
|
KEY_READ
|
|
);
|
|
|
|
if(hk != INVALID_HANDLE_VALUE) {
|
|
|
|
try {
|
|
Err = GetModuleEntryPoint(hk,
|
|
pszEnumPropPages32,
|
|
pszEnumPropDefaultProc,
|
|
&(InstallParamBlock->hinstDevicePropProvider),
|
|
&((FARPROC)InstallParamBlock->DeviceEnumPropPagesEntryPoint),
|
|
&(InstallParamBlock->DeviceEnumPropPagesFusionContext),
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
SetupapiVerifyNoProblem,
|
|
NULL,
|
|
DRIVERSIGN_NONE,
|
|
TRUE,
|
|
NULL
|
|
);
|
|
|
|
if(Err == ERROR_DI_DO_DEFAULT) {
|
|
//
|
|
// The EnumPropPages32 value wasn't present--this is not an error.
|
|
//
|
|
Err = NO_ERROR;
|
|
|
|
} else if(Err != NO_ERROR) {
|
|
Err = ERROR_INVALID_PROPPAGE_PROVIDER;
|
|
}
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PROPPAGE_PROVIDER;
|
|
InstallParamBlock->DeviceEnumPropPagesEntryPoint = NULL;
|
|
}
|
|
|
|
RegCloseKey(hk);
|
|
hk = INVALID_HANDLE_VALUE;
|
|
|
|
if(Err != NO_ERROR) {
|
|
goto clean0;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Clear the DI_GENERALPAGE_ADDED, DI_DRIVERPAGE_ADDED, and DI_RESOURCEPAGE_ADDED flags.
|
|
//
|
|
InstallParamBlock->Flags &= ~(DI_GENERALPAGE_ADDED | DI_RESOURCEPAGE_ADDED | DI_DRIVERPAGE_ADDED);
|
|
|
|
PropPageRequest.PageRequested = SPPSR_ENUM_ADV_DEVICE_PROPERTIES;
|
|
|
|
//
|
|
// We must first release the HDEVINFO lock, so we don't run into any weird
|
|
// deadlock issues
|
|
//
|
|
UnlockDeviceInfoSet(pDeviceInfoSet);
|
|
pDeviceInfoSet = NULL;
|
|
|
|
//
|
|
// If there is an advanced property page provider for this class, then call it.
|
|
//
|
|
if(InstallParamBlock->ClassEnumPropPagesEntryPoint) {
|
|
|
|
spFusionEnterContext(InstallParamBlock->ClassEnumPropPagesFusionContext,
|
|
&spFusionInstance);
|
|
try {
|
|
InstallParamBlock->ClassEnumPropPagesEntryPoint(
|
|
&PropPageRequest,
|
|
pSetupAddPropPage,
|
|
(LPARAM)&PropPageAddProcContext
|
|
);
|
|
} finally {
|
|
spFusionLeaveContext(&spFusionInstance);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If there is an advanced property page provider for this particular device, then call it.
|
|
//
|
|
if(InstallParamBlock->DeviceEnumPropPagesEntryPoint) {
|
|
|
|
spFusionEnterContext(InstallParamBlock->DeviceEnumPropPagesFusionContext,
|
|
&spFusionInstance);
|
|
try {
|
|
InstallParamBlock->DeviceEnumPropPagesEntryPoint(
|
|
&PropPageRequest,
|
|
pSetupAddPropPage,
|
|
(LPARAM)&PropPageAddProcContext
|
|
);
|
|
} finally {
|
|
spFusionLeaveContext(&spFusionInstance);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now use the new DIF_ADDPROPERTYPAGE_ADVANCED call to see if any
|
|
// class-/co-installers want to add advanced property pages as well.
|
|
//
|
|
memset(&PropertyPageData, 0, sizeof(SP_ADDPROPERTYPAGE_DATA));
|
|
PropertyPageData.ClassInstallHeader.InstallFunction = DIF_ADDPROPERTYPAGE_ADVANCED;
|
|
PropertyPageData.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
|
|
PropertyPageData.hwndWizardDlg = PropertySheetHeader->hwndParent;
|
|
|
|
Err = DoInstallActionWithParams(DIF_ADDPROPERTYPAGE_ADVANCED,
|
|
DeviceInfoSet,
|
|
DeviceInfoData,
|
|
&PropertyPageData.ClassInstallHeader,
|
|
sizeof(SP_ADDPROPERTYPAGE_DATA),
|
|
INSTALLACTION_CALL_CI);
|
|
|
|
if (ERROR_DI_DO_DEFAULT == Err) {
|
|
|
|
//
|
|
// The class-/co-installers do not have any pages to add--this is not an error.
|
|
//
|
|
Err = NO_ERROR;
|
|
}
|
|
|
|
if ((NO_ERROR == Err) ||
|
|
(PropertyPageData.NumDynamicPages > 0))
|
|
{
|
|
DWORD NumPages = 0;
|
|
|
|
while (NumPages < PropertyPageData.NumDynamicPages) {
|
|
|
|
pSetupAddPropPage(PropertyPageData.DynamicPages[NumPages++],
|
|
(LPARAM)&PropPageAddProcContext
|
|
);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DIGCDP_FLAG_REMOTE_ADVANCED:
|
|
//
|
|
// Now use the new DIF_ADDREMOTEPROPERTYPAGE_ADVANCED call to see if any
|
|
// class-/co-installers want to add advanced property pages as well.
|
|
//
|
|
memset(&PropertyPageData, 0, sizeof(SP_ADDPROPERTYPAGE_DATA));
|
|
PropertyPageData.ClassInstallHeader.InstallFunction = DIF_ADDREMOTEPROPERTYPAGE_ADVANCED;
|
|
PropertyPageData.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
|
|
PropertyPageData.hwndWizardDlg = PropertySheetHeader->hwndParent;
|
|
|
|
Err = DoInstallActionWithParams(DIF_ADDREMOTEPROPERTYPAGE_ADVANCED,
|
|
DeviceInfoSet,
|
|
DeviceInfoData,
|
|
&PropertyPageData.ClassInstallHeader,
|
|
sizeof(SP_ADDPROPERTYPAGE_DATA),
|
|
INSTALLACTION_CALL_CI);
|
|
|
|
if (ERROR_DI_DO_DEFAULT == Err) {
|
|
|
|
//
|
|
// The class-/co-installers do not have any pages to add--this is not an error.
|
|
//
|
|
Err = NO_ERROR;
|
|
}
|
|
|
|
if ((NO_ERROR == Err) ||
|
|
(PropertyPageData.NumDynamicPages > 0))
|
|
{
|
|
DWORD NumPages = 0;
|
|
|
|
while (NumPages < PropertyPageData.NumDynamicPages) {
|
|
|
|
pSetupAddPropPage(PropertyPageData.DynamicPages[NumPages++],
|
|
(LPARAM)&PropPageAddProcContext
|
|
);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if(RequiredSize) {
|
|
*RequiredSize = PropPageAddProcContext.NumPages;
|
|
}
|
|
|
|
if((OriginalPageCount + PropPageAddProcContext.NumPages) > PropertySheetHeaderPageListSize) {
|
|
Err = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
clean0: ; // nothing to do.
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
|
|
if(hk != INVALID_HANDLE_VALUE) {
|
|
RegCloseKey(hk);
|
|
}
|
|
|
|
//
|
|
// Reference the following variable so the compiler will respect our statement ordering
|
|
// w.r.t. assignment.
|
|
//
|
|
pDeviceInfoSet = pDeviceInfoSet;
|
|
}
|
|
|
|
if(pDeviceInfoSet) {
|
|
UnlockDeviceInfoSet(pDeviceInfoSet);
|
|
}
|
|
|
|
SetLastError(Err);
|
|
return(Err == NO_ERROR);
|
|
}
|
|
|
|
|
|
BOOL
|
|
CALLBACK
|
|
pSetupAddPropPage(
|
|
IN HPROPSHEETPAGE hPage,
|
|
IN LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the callback routine that is passed to property page providers.
|
|
This routine is called for each property page that the provider wishes to
|
|
add.
|
|
|
|
Arguments:
|
|
|
|
hPage - Supplies a handle to the property page being added.
|
|
|
|
lParam - Supplies a pointer to a context structure used when adding the new
|
|
property page handle.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is TRUE.
|
|
If the function fails, the return value is FALSE.
|
|
|
|
--*/
|
|
{
|
|
PSP_PROPPAGE_ADDPROC_CONTEXT Context = (PSP_PROPPAGE_ADDPROC_CONTEXT)lParam;
|
|
|
|
//
|
|
// Regardless of whether we successfully add this new hPage, we want to keep
|
|
// a count of how many pages we were asked to add.
|
|
//
|
|
Context->NumPages++;
|
|
|
|
if(Context->PropertySheetHeader->nPages < Context->PageListSize) {
|
|
Context->PropertySheetHeader->phpage[Context->PropertySheetHeader->nPages++] = hPage;
|
|
return TRUE;
|
|
}
|
|
|
|
return Context->NoCancelOnFailure;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CALLBACK
|
|
ExtensionPropSheetPageProc(
|
|
IN LPVOID lpv,
|
|
IN LPFNADDPROPSHEETPAGE lpfnAddPropSheetPageProc,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
PSP_PROPSHEETPAGE_REQUEST PropPageRequest = (PSP_PROPSHEETPAGE_REQUEST)lpv;
|
|
HPROPSHEETPAGE hPropSheetPage = NULL;
|
|
BOOL b = FALSE;
|
|
|
|
//
|
|
// Make sure we're running interactively.
|
|
//
|
|
if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
|
|
SetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
|
|
return FALSE;
|
|
}
|
|
|
|
try {
|
|
|
|
if(PropPageRequest->cbSize != sizeof(SP_PROPSHEETPAGE_REQUEST)) {
|
|
goto clean0;
|
|
}
|
|
|
|
switch(PropPageRequest->PageRequested) {
|
|
|
|
case SPPSR_SELECT_DEVICE_RESOURCES :
|
|
|
|
if(!(hPropSheetPage = GetResourceSelectionPage(PropPageRequest->DeviceInfoSet,
|
|
PropPageRequest->DeviceInfoData))) {
|
|
goto clean0;
|
|
}
|
|
break;
|
|
|
|
default :
|
|
//
|
|
// Don't know what to do with this request.
|
|
//
|
|
goto clean0;
|
|
}
|
|
|
|
if(lpfnAddPropSheetPageProc(hPropSheetPage, lParam)) {
|
|
//
|
|
// Page successfully handed off to requestor. Reset our handle so that we don't
|
|
// try to free it.
|
|
//
|
|
hPropSheetPage = NULL;
|
|
b = TRUE;
|
|
}
|
|
|
|
clean0: ; // nothing to do
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
//
|
|
// Access the hPropSheetPage variable, so that the compiler will respect our statement
|
|
// order w.r.t. assignment.
|
|
//
|
|
hPropSheetPage = hPropSheetPage;
|
|
}
|
|
|
|
if(hPropSheetPage) {
|
|
//
|
|
// Property page was successfully created, but never handed off to requestor. Free
|
|
// it now.
|
|
//
|
|
DestroyPropertySheetPage(hPropSheetPage);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|