Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1927 lines
62 KiB

/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
devinst.c
Abstract:
Device Installer routines.
Author:
Lonny McMichael (lonnym) 1-Aug-1995
Revision History:
--*/
#include "setupntp.h"
#pragma hdrstop
#ifdef UNICODE
//
// ANSI version
//
BOOL
WINAPI
SetupDiGetDeviceInstallParamsA(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
OUT PSP_DEVINSTALL_PARAMS_A DeviceInstallParams
)
{
SP_DEVINSTALL_PARAMS_W deviceInstallParams;
DWORD rc;
BOOL b;
deviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
b = SetupDiGetDeviceInstallParamsW(DeviceInfoSet,DeviceInfoData,&deviceInstallParams);
rc = GetLastError();
if(b) {
rc = pSetupDiDevInstParamsUnicodeToAnsi(&deviceInstallParams,DeviceInstallParams);
if(rc != NO_ERROR) {
b = FALSE;
}
}
SetLastError(rc);
return(b);
}
#else
//
// Unicode version
//
BOOL
WINAPI
SetupDiGetDeviceInstallParamsW(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
OUT PSP_DEVINSTALL_PARAMS_W DeviceInstallParams
)
{
UNREFERENCED_PARAMETER(DeviceInfoSet);
UNREFERENCED_PARAMETER(DeviceInfoData);
UNREFERENCED_PARAMETER(DeviceInstallParams);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return(FALSE);
}
#endif
BOOL
WINAPI
SetupDiGetDeviceInstallParams(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
OUT PSP_DEVINSTALL_PARAMS DeviceInstallParams
)
/*++
Routine Description:
This routine retrieves installation parameters for a device information set
(globally), or a particular device information element.
Arguments:
DeviceInfoSet - Supplies a handle to the device information set containing
installation parameters to be retrieved.
DeviceInfoData - Optionally, supplies the address of a SP_DEVINFO_DATA
structure containing installation parameters to be retrieved. If this
parameter is not specified, then the installation parameters retrieved
will be associated with the device information set itself (for the global
class driver list).
DeviceInstallParams - Supplies the address of a SP_DEVINSTALL_PARAMS structure
that will receive the installation parameters. The cbSize field of this
structure must be set to the size, in bytes, of a SP_DEVINSTALL_PARAMS
structure before calling this API.
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;
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
Err = NO_ERROR;
try {
if(DeviceInfoData) {
//
// Then we are to retrieve installation parameters for a particular
// device.
//
if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
DeviceInfoData,
NULL))) {
Err = ERROR_INVALID_PARAMETER;
} else {
Err = GetDevInstallParams(pDeviceInfoSet,
&(DevInfoElem->InstallParamBlock),
DeviceInstallParams
);
}
} else {
//
// Retrieve installation parameters for the global class driver list.
//
Err = GetDevInstallParams(pDeviceInfoSet,
&(pDeviceInfoSet->InstallParamBlock),
DeviceInstallParams
);
}
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
}
UnlockDeviceInfoSet(pDeviceInfoSet);
SetLastError(Err);
return(Err == NO_ERROR);
}
#ifdef UNICODE
//
// ANSI version
//
BOOL
WINAPI
SetupDiGetClassInstallParamsA(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
OUT PSP_CLASSINSTALL_HEADER ClassInstallParams, OPTIONAL
IN DWORD ClassInstallParamsSize,
OUT PDWORD RequiredSize OPTIONAL
)
{
PDEVICE_INFO_SET pDeviceInfoSet;
PDEVINFO_ELEM DevInfoElem;
PDEVINSTALL_PARAM_BLOCK InstallParamBlock;
DI_FUNCTION Function;
SP_SELECTDEVICE_PARAMS_W SelectDeviceParams;
SP_SELECTDEVICE_PARAMS_A SelectDeviceParamsA;
DWORD requiredSize;
DWORD Err;
BOOL b;
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
Err = NO_ERROR;
try {
if(DeviceInfoData) {
//
// Then we are to retrieve installation parameters for a particular
// device.
//
if(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,DeviceInfoData,NULL)) {
InstallParamBlock = &DevInfoElem->InstallParamBlock;
} else {
Err = ERROR_INVALID_PARAMETER;
}
} else {
//
// Retrieve installation parameters for the global class driver list.
//
InstallParamBlock = &pDeviceInfoSet->InstallParamBlock;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
}
if(Err == NO_ERROR) {
if(InstallParamBlock->ClassInstallHeader) {
Function = InstallParamBlock->ClassInstallHeader->InstallFunction;
} else {
Err = ERROR_NO_CLASSINSTALL_PARAMS;
}
}
UnlockDeviceInfoSet(pDeviceInfoSet);
if(Err == NO_ERROR) {
//
// For DIF_SELECTDEVICE we need special processing since
// the structure that goes with it is ansi/unicode specific.
//
if(Function == DIF_SELECTDEVICE) {
b = SetupDiGetClassInstallParamsW(
DeviceInfoSet,
DeviceInfoData,
(PSP_CLASSINSTALL_HEADER)&SelectDeviceParams,
sizeof(SP_SELECTDEVICE_PARAMS_W),
&requiredSize
);
if(b) {
Err = pSetupDiSelDevParamsUnicodeToAnsi(&SelectDeviceParams,&SelectDeviceParamsA);
if(Err == NO_ERROR) {
try {
if(ClassInstallParams) {
if((ClassInstallParamsSize < sizeof(SP_CLASSINSTALL_HEADER)) ||
(ClassInstallParams->cbSize != sizeof(SP_CLASSINSTALL_HEADER))) {
Err = ERROR_INVALID_USER_BUFFER;
}
} else if(ClassInstallParamsSize) {
Err = ERROR_INVALID_USER_BUFFER;
}
if(Err == NO_ERROR) {
//
// Store required size in output parameter (if requested).
//
if(RequiredSize) {
*RequiredSize = sizeof(SP_SELECTDEVICE_PARAMS_A);
}
//
// See if supplied buffer is large enough.
//
if(ClassInstallParamsSize < sizeof(SP_SELECTDEVICE_PARAMS_A)) {
Err = ERROR_INSUFFICIENT_BUFFER;
} else {
CopyMemory(
ClassInstallParams,
&SelectDeviceParamsA,
sizeof(SP_SELECTDEVICE_PARAMS_A)
);
}
}
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
}
}
} else {
Err = GetLastError();
}
} else {
b = SetupDiGetClassInstallParamsW(
DeviceInfoSet,
DeviceInfoData,
ClassInstallParams,
ClassInstallParamsSize,
RequiredSize
);
if(b) {
Err = NO_ERROR;
} else {
Err = GetLastError();
}
}
}
SetLastError(Err);
return(Err == NO_ERROR);
}
#else
//
// Unicode version
//
BOOL
WINAPI
SetupDiGetClassInstallParamsW(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
OUT PSP_CLASSINSTALL_HEADER ClassInstallParams, OPTIONAL
IN DWORD ClassInstallParamsSize,
OUT PDWORD RequiredSize OPTIONAL
)
{
UNREFERENCED_PARAMETER(DeviceInfoSet);
UNREFERENCED_PARAMETER(DeviceInfoData);
UNREFERENCED_PARAMETER(ClassInstallParams);
UNREFERENCED_PARAMETER(ClassInstallParamsSize);
UNREFERENCED_PARAMETER(RequiredSize);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return(FALSE);
}
#endif
BOOL
WINAPI
SetupDiGetClassInstallParams(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
OUT PSP_CLASSINSTALL_HEADER ClassInstallParams, OPTIONAL
IN DWORD ClassInstallParamsSize,
OUT PDWORD RequiredSize OPTIONAL
)
/*++
Routine Description:
This routine retrieves class installer parameters for a device information set
(globally), or a particular device information element. These parameters are
specific to a particular device installer function code (DI_FUNCTION) that will
be stored in the ClassInstallHeader field located at the beginning of the
parameter buffer.
Arguments:
DeviceInfoSet - Supplies a handle to the device information set containing
class installer parameters to be retrieved.
DeviceInfoData - Optionally, supplies the address of a SP_DEVINFO_DATA
structure containing class installer parameters to be retrieved. If this
parameter is not specified, then the class installer parameters retrieved
will be associated with the device information set itself (for the global
class driver list).
ClassInstallParams - Optionally, supplies the address of a buffer containing a
class install header structure. This structure must have its cbSize field
set to sizeof(SP_CLASSINSTALL_HEADER) on input, or the buffer is considered
to be invalid. On output, the InstallFunction field will be filled in with
the DI_FUNCTION code for the class install parameters being retrieved, and
if the buffer is large enough, it will receive the class installer parameters
structure specific to that function code.
If this parameter is not specified, then ClassInstallParamsSize must be zero.
This would be done if the caller simply wants to determine how large a buffer
is required.
ClassInstallParamsSize - Supplies the size, in bytes, of the ClassInstallParams
buffer, or zero, if ClassInstallParams is not supplied. If the buffer is
supplied, it must be _at least_ as large as sizeof(SP_CLASSINSTALL_HEADER).
RequiredSize - Optionally, supplies the address of a variable that receives
the number of bytes required to store the class installer parameters.
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;
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
Err = NO_ERROR;
try {
if(DeviceInfoData) {
//
// Then we are to retrieve installation parameters for a particular
// device.
//
if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
DeviceInfoData,
NULL))) {
Err = ERROR_INVALID_PARAMETER;
} else {
Err = GetClassInstallParams(&(DevInfoElem->InstallParamBlock),
ClassInstallParams,
ClassInstallParamsSize,
RequiredSize
);
}
} else {
//
// Retrieve installation parameters for the global class driver list.
//
Err = GetClassInstallParams(&(pDeviceInfoSet->InstallParamBlock),
ClassInstallParams,
ClassInstallParamsSize,
RequiredSize
);
}
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
}
UnlockDeviceInfoSet(pDeviceInfoSet);
SetLastError(Err);
return(Err == NO_ERROR);
}
BOOL
WINAPI
_SetupDiSetDeviceInstallParams(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
IN PSP_DEVINSTALL_PARAMS DeviceInstallParams,
IN BOOL MsgHandlerIsNativeCharWidth
)
{
PDEVICE_INFO_SET pDeviceInfoSet;
DWORD Err;
PDEVINFO_ELEM DevInfoElem;
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
Err = NO_ERROR;
try {
if(DeviceInfoData) {
//
// Then we are to set installation parameters for a particular
// device.
//
if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
DeviceInfoData,
NULL))) {
Err = ERROR_INVALID_PARAMETER;
} else {
Err = SetDevInstallParams(pDeviceInfoSet,
DeviceInstallParams,
&(DevInfoElem->InstallParamBlock),
MsgHandlerIsNativeCharWidth
);
}
} else {
//
// Set installation parameters for the global class driver list.
//
Err = SetDevInstallParams(pDeviceInfoSet,
DeviceInstallParams,
&(pDeviceInfoSet->InstallParamBlock),
MsgHandlerIsNativeCharWidth
);
}
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
}
UnlockDeviceInfoSet(pDeviceInfoSet);
SetLastError(Err);
return(Err == NO_ERROR);
}
#ifdef UNICODE
//
// ANSI version
//
BOOL
WINAPI
SetupDiSetDeviceInstallParamsA(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
IN PSP_DEVINSTALL_PARAMS_A DeviceInstallParams
)
{
DWORD rc;
SP_DEVINSTALL_PARAMS_W deviceInstallParams;
rc = pSetupDiDevInstParamsAnsiToUnicode(DeviceInstallParams,&deviceInstallParams);
if(rc != NO_ERROR) {
SetLastError(rc);
return(FALSE);
}
return(_SetupDiSetDeviceInstallParams(DeviceInfoSet,DeviceInfoData,&deviceInstallParams,FALSE));
}
#else
//
// Unicode version
//
BOOL
WINAPI
SetupDiSetDeviceInstallParamsW(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
IN PSP_DEVINSTALL_PARAMS_W DeviceInstallParams
)
{
UNREFERENCED_PARAMETER(DeviceInfoSet);
UNREFERENCED_PARAMETER(DeviceInfoData);
UNREFERENCED_PARAMETER(DeviceInstallParams);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return(FALSE);
}
#endif
BOOL
WINAPI
SetupDiSetDeviceInstallParams(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
IN PSP_DEVINSTALL_PARAMS DeviceInstallParams
)
/*++
Routine Description:
This routine sets installation parameters for a device information set
(globally), or a particular device information element.
Arguments:
DeviceInfoSet - Supplies a handle to the device information set containing
installation parameters to be set.
DeviceInfoData - Optionally, supplies the address of a SP_DEVINFO_DATA
structure containing installation parameters to be set. If this
parameter is not specified, then the installation parameters set
will be associated with the device information set itself (for the
global class driver list).
DeviceInstallParams - Supplies the address of a SP_DEVINSTALL_PARAMS structure
containing the new values of the parameters. The cbSize field of this
structure must be set to the size, in bytes, of the structure before
calling this API.
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.
Remarks:
All parameters will be validated before any changes are made, so a return
status of FALSE indicates that no parameters were modified.
--*/
{
return(_SetupDiSetDeviceInstallParams(DeviceInfoSet,DeviceInfoData,DeviceInstallParams,TRUE));
}
#ifdef UNICODE
//
// ANSI version
//
BOOL
WINAPI
SetupDiSetClassInstallParamsA(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
IN PSP_CLASSINSTALL_HEADER ClassInstallParams, OPTIONAL
IN DWORD ClassInstallParamsSize
)
{
DWORD Err;
DI_FUNCTION Function;
SP_SELECTDEVICE_PARAMS_W SelectParams;
BOOL b;
if(!ClassInstallParams) {
//
// Just pass it on to the unicode version since there's
// no thunking to do. Note that the size must be 0.
//
if(ClassInstallParamsSize) {
SetLastError(ERROR_INVALID_PARAMETER);
return(FALSE);
}
return SetupDiSetClassInstallParamsW(
DeviceInfoSet,
DeviceInfoData,
ClassInstallParams,
ClassInstallParamsSize
);
}
Err = NO_ERROR;
try {
if(ClassInstallParams->cbSize == sizeof(SP_CLASSINSTALL_HEADER)) {
Function = ClassInstallParams->InstallFunction;
} else {
//
// Structure is invalid.
//
Err = ERROR_INVALID_PARAMETER;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
}
if(Err != NO_ERROR) {
SetLastError(Err);
return(FALSE);
}
//
// DIF_SELECTDEVICE is a special case since it has
// an structure that needs to be translated from ansi to unicode.
// Others can just be passed on to the unicode version with
// no changes to the parameters.
//
if(Function == DIF_SELECTDEVICE) {
b = FALSE;
if(ClassInstallParamsSize >= sizeof(SP_SELECTDEVICE_PARAMS_A)) {
Err = pSetupDiSelDevParamsAnsiToUnicode(
(PSP_SELECTDEVICE_PARAMS_A)ClassInstallParams,
&SelectParams
);
if(Err == NO_ERROR) {
b = SetupDiSetClassInstallParamsW(
DeviceInfoSet,
DeviceInfoData,
(PSP_CLASSINSTALL_HEADER)&SelectParams,
sizeof(SP_SELECTDEVICE_PARAMS_W)
);
Err = GetLastError();
}
} else {
Err = ERROR_INVALID_PARAMETER;
}
} else {
b = SetupDiSetClassInstallParamsW(
DeviceInfoSet,
DeviceInfoData,
ClassInstallParams,
ClassInstallParamsSize
);
Err = GetLastError();
}
SetLastError(Err);
return(b);
}
#else
//
// Unicode version
//
BOOL
WINAPI
SetupDiSetClassInstallParamsW(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
IN PSP_CLASSINSTALL_HEADER ClassInstallParams, OPTIONAL
IN DWORD ClassInstallParamsSize
)
{
UNREFERENCED_PARAMETER(DeviceInfoSet);
UNREFERENCED_PARAMETER(DeviceInfoData);
UNREFERENCED_PARAMETER(ClassInstallParams);
UNREFERENCED_PARAMETER(ClassInstallParamsSize);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return(FALSE);
}
#endif
BOOL
WINAPI
SetupDiSetClassInstallParams(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
IN PSP_CLASSINSTALL_HEADER ClassInstallParams, OPTIONAL
IN DWORD ClassInstallParamsSize
)
/*++
Routine Description:
This routine sets (or clears) class installer parameters for a device
information set (globally), or a particular device information element.
Arguments:
DeviceInfoSet - Supplies a handle to the device information set containing
class installer parameters to be set.
DeviceInfoData - Optionally, supplies the address of a SP_DEVINFO_DATA
structure containing class installer parameters to be set. If this
parameter is not specified, then the class installer parameters to be
set will be associated with the device information set itself (for the
global class driver list).
ClassInstallParams - Optionally, supplies the address of a buffer containing
the class installer parameters to be used. The SP_CLASSINSTALL_HEADER
structure at the beginning of the buffer must have its cbSize field set to
be sizeof(SP_CLASSINSTALL_HEADER), and the InstallFunction field must be
set to the DI_FUNCTION code reflecting the type of parameters supplied in
the rest of the buffer.
If this parameter is not supplied, then the current class installer parameters
(if any) will be cleared for the specified device information set or element.
ClassInstallParamsSize - Supplies the size, in bytes, of the ClassInstallParams
buffer. If the buffer is not supplied (i.e., the class installer parameters
are to be cleared), then this value must be zero.
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.
Remarks:
All parameters will be validated before any changes are made, so a return
status of FALSE indicates that no parameters were modified.
A side effect of setting class installer parameters is that the DI_CLASSINSTALLPARAMS
flag is set. If for some reason, it is desired to set the parameters, but disable
their use, then this flag must be cleared via SetupDiSetDeviceInstallParams.
If the class installer parameters are cleared, then the DI_CLASSINSTALLPARAMS flag
is reset.
--*/
{
PDEVICE_INFO_SET pDeviceInfoSet;
DWORD Err;
PDEVINFO_ELEM DevInfoElem;
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
Err = NO_ERROR;
try {
if(DeviceInfoData) {
//
// Then we are to set class installer parameters for a particular device.
//
if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
DeviceInfoData,
NULL))) {
Err = ERROR_INVALID_PARAMETER;
} else {
Err = SetClassInstallParams(pDeviceInfoSet,
ClassInstallParams,
ClassInstallParamsSize,
&(DevInfoElem->InstallParamBlock)
);
}
} else {
//
// Set class installer parameters for the global class driver list.
//
Err = SetClassInstallParams(pDeviceInfoSet,
ClassInstallParams,
ClassInstallParamsSize,
&(pDeviceInfoSet->InstallParamBlock)
);
}
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
}
UnlockDeviceInfoSet(pDeviceInfoSet);
SetLastError(Err);
return(Err == NO_ERROR);
}
BOOL
WINAPI
SetupDiCallClassInstaller(
IN DI_FUNCTION InstallFunction,
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
)
/*++
Routine Description:
This routine calls the appropriate class installer with the specified
installer function.
Arguments:
InstallFunction - Class installer function to call. This can be one
of the following values:
DIF_SELECTDEVICE - Select a driver to be installed for the device.
DIF_INSTALLDEVICE - Install the driver for the device.
DIF_PROPERTIES - Display a properties dialog for the device (must
specify a particular device in DeviceInfoData).
DIF_REMOVE - Remove the device.
DIF_FIRSTTIMESETUP - Perform first time setup initialization. This
is used only for the global class information associated with
the device information set (i.e., DeviceInfoData not specified).
DIF_SELECTCLASSDRIVERS - Select drivers for all devices of the class
associated with the device information set or element.
DIF_VALIDATECLASSDRIVERS - Ensure all devices of the class associated
with the device information set or element are ready to be installed.
DIF_INSTALLCLASSDRIVERS - Install drivers for all devices of the
class associated with the device information set or element.
DIF_CALCDISKSPACE - Compute the amount of disk space required by
drivers.
DIF_DESTROYPRIVATEDATA - Destroy any private date referenced by
the ClassInstallReserved installation parameter for the specified
device information set or element.
DIF_MOVEDEVICE - The device is being moved to a new location in the
Enum branch (this means that the device instance name will change).
DIF_DETECT - Detect any devices of class associated with the device
information set or element.
DIF_INSTALLWIZARD - Add any pages necessary to the New Device Wizard
for the class associated with the device information set or element.
DIF_DESTROYWIZARDDATA - Destroy any private data allocated due to
a DIF_INSTALLWIZARD message.
DIF_PROPERTYCHANGE - The device's properties are changing. The device
is being enabled, disabled, or has had a resource change.
DIF_DETECTVERIFY - The class installer should verify any devices it
previously detected. Non verified devices should be removed.
DIF_INSTALLDEVICEFILES - The class installer should only install the
driver files for the selected device. (DeviceInfoData must be
specified.)
DeviceInfoSet - Supplies a handle to the device information set to
perform installation for.
DeviceInfoData - Optionally, specifies a particular device information
element whose class installer is to be called. If this parameter
is not specified, then the class installer for the device information
set itself will be called (if the set has an associated class).
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.
Remarks:
This function will attempt to load and call the class installer for the
class associated with the device information element or set specified.
If there is no class installer, or the class installer returns
ERR_DI_DO_DEFAULT, then this function will call a default procedure for
the specified class installer function.
--*/
{
PDEVICE_INFO_SET pDeviceInfoSet;
BOOL b;
DWORD Err;
PDEVINFO_ELEM DevInfoElem;
PDEVINSTALL_PARAM_BLOCK InstallParamBlock;
HKEY hk;
LPGUID ClassGuid;
BOOL bRestoreMiniIconUsage = FALSE;
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
Err = ERROR_DI_DO_DEFAULT;
try {
if(DeviceInfoData) {
//
// Then we are to call the class installer for a particular
// device.
//
if(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
DeviceInfoData,
NULL)) {
InstallParamBlock = &(DevInfoElem->InstallParamBlock);
ClassGuid = &(DevInfoElem->ClassGuid);
} else {
Err = ERROR_INVALID_PARAMETER;
goto clean0;
}
} else {
InstallParamBlock = &(pDeviceInfoSet->InstallParamBlock);
ClassGuid = pDeviceInfoSet->HasClassGuid ? &(pDeviceInfoSet->ClassGuid)
: NULL;
}
//
// If the class installer has not been loaded, then load it and
// get the function address for the ClassInstall function.
//
if(!InstallParamBlock->hinstClassInstaller) {
if(ClassGuid &&
(hk = SetupDiOpenClassRegKey(ClassGuid, KEY_READ)) != INVALID_HANDLE_VALUE) {
try {
Err = GetModuleEntryPoint(hk,
pszInstaller32,
pszCiDefaultProc,
&(InstallParamBlock->hinstClassInstaller),
&(InstallParamBlock->ClassInstallerEntryPoint)
);
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_CLASS_INSTALLER;
if(InstallParamBlock->hinstClassInstaller) {
FreeLibrary(InstallParamBlock->hinstClassInstaller);
InstallParamBlock->hinstClassInstaller = NULL;
}
InstallParamBlock->ClassInstallerEntryPoint = NULL;
}
RegCloseKey(hk);
if((Err != NO_ERROR) && (Err != ERROR_DI_DO_DEFAULT)) {
if(!(InstallParamBlock->FlagsEx & DI_FLAGSEX_CI_FAILED)) {
TCHAR ClassName[MAX_CLASS_NAME_LEN];
TCHAR Title[MAX_TITLE_LEN];
if(!LoadString(MyDllModuleHandle,
IDS_DEVICEINSTALLER,
Title,
SIZECHARS(Title))) {
*Title = TEXT('\0');
}
b = SetupDiClassNameFromGuid(ClassGuid,
ClassName,
SIZECHARS(ClassName),
NULL
);
FormatMessageBox(MyDllModuleHandle,
InstallParamBlock->hwndParent,
MSG_CI_LOADFAIL_ERROR,
Title,
MB_OK,
b ? ClassName : pszUnknownClassParens
);
InstallParamBlock->FlagsEx |= DI_FLAGSEX_CI_FAILED;
}
Err = ERROR_INVALID_CLASS_INSTALLER;
goto clean0;
}
}
}
//
// If there is a class installer entry point, then call it.
//
if(InstallParamBlock->ClassInstallerEntryPoint) {
//
// We must first release the HDEVINFO lock, or otherwise we won't be
// able to do cool things like multi-threading the Select Device dialog.
//
UnlockDeviceInfoSet(pDeviceInfoSet);
pDeviceInfoSet = NULL;
Err = InstallParamBlock->ClassInstallerEntryPoint(InstallFunction,
DeviceInfoSet,
DeviceInfoData
);
}
if(Err != ERROR_DI_DO_DEFAULT) {
goto clean0;
}
//
// Now we need to retrieve the parameter block all over again (we don't
// know what the class installer function might have done).
//
// First, re-acquire the lock on the HDEVINFO, if we released it above in order
// to call the class installer.
//
if(!pDeviceInfoSet) {
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
Err = ERROR_INVALID_HANDLE;
goto clean0;
}
}
if(DeviceInfoData) {
if(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
DeviceInfoData,
NULL)) {
InstallParamBlock = &(DevInfoElem->InstallParamBlock);
} else {
//
// The device information element appears to have been
// destroyed--treat this as if the DI_NODI_DEFAULTACTION
// flag was set.
//
goto clean0;
}
} else {
InstallParamBlock = &(pDeviceInfoSet->InstallParamBlock);
}
if(InstallParamBlock->Flags & DI_NODI_DEFAULTACTION) {
//
// We shouldn't provide a default action--just return the class installer result.
//
goto clean0;
}
Err = NO_ERROR;
if((InstallFunction == DIF_SELECTDEVICE) && !(InstallParamBlock->Flags & DI_NOSELECTICONS)) {
//
// We don't want to display mini-icons in the default Select Device case.
// Temporarily set the flag that prevents this.
//
InstallParamBlock->Flags |= DI_NOSELECTICONS;
bRestoreMiniIconUsage = TRUE;
}
//
// Now, release the HDEVINFO lock before calling the appropriate handler routine.
//
UnlockDeviceInfoSet(pDeviceInfoSet);
pDeviceInfoSet = NULL;
switch(InstallFunction) {
case DIF_SELECTDEVICE :
b = SetupDiSelectDevice(DeviceInfoSet, DeviceInfoData);
//
// If we need to reset the DI_NOSELECTICONS flag we set above, then re-acquire
// the lock and do that now.
//
if(bRestoreMiniIconUsage &&
(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
if(DeviceInfoData) {
if(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
DeviceInfoData,
NULL)) {
InstallParamBlock = &(DevInfoElem->InstallParamBlock);
} else {
InstallParamBlock = NULL;
}
} else {
InstallParamBlock = &(pDeviceInfoSet->InstallParamBlock);
}
if(InstallParamBlock) {
InstallParamBlock->Flags &= ~DI_NOSELECTICONS;
}
}
break;
case DIF_INSTALLDEVICE :
b = SetupDiInstallDevice(DeviceInfoSet, DeviceInfoData);
break;
case DIF_INSTALLDEVICEFILES :
b = SetupDiInstallDriverFiles(DeviceInfoSet, DeviceInfoData);
break;
case DIF_REMOVE :
b = SetupDiRemoveDevice(DeviceInfoSet, DeviceInfoData);
break;
//
// These are new messages for class installers such as the Network, where the
// class installer will do all of the work. If no action is taken, ie, the
// class installer return ERROR_DI_DO_DEFAULT, then we return OK, since there
// is no default action for these cases.
//
case DIF_SELECTCLASSDRIVERS:
case DIF_VALIDATECLASSDRIVERS:
case DIF_INSTALLCLASSDRIVERS:
b = TRUE;
Err = ERROR_DI_DO_DEFAULT;
break;
case DIF_MOVEDEVICE :
b = SetupDiMoveDuplicateDevice(DeviceInfoSet, DeviceInfoData);
break;
case DIF_PROPERTYCHANGE :
b = SetupDiChangeState(DeviceInfoSet, DeviceInfoData);
break;
//
// If the DIF_ message is not one of the above, and it is not handled,
// then let the caller handle it in a default manner.
//
default :
b = TRUE;
Err = ERROR_DI_DO_DEFAULT;
break;
}
if(!b) {
Err = GetLastError();
}
clean0: ; // nothing to do.
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
//
// Access the pDeviceInfoSet variable, so that the compiler will respect our statement
// ordering w.r.t. this value. Otherwise, we wouldn't be able to know for sure whether
// we should unlock the HDEVINFO.
//
pDeviceInfoSet = pDeviceInfoSet;
}
if(pDeviceInfoSet) {
UnlockDeviceInfoSet(pDeviceInfoSet);
}
SetLastError(Err);
return (Err == NO_ERROR);
}
#ifdef UNICODE
//
// ANSI version
//
BOOL
WINAPI
SetupDiInstallClassA(
IN HWND hwndParent, OPTIONAL
IN PCSTR InfFileName,
IN DWORD Flags,
IN HSPFILEQ FileQueue OPTIONAL
)
{
PCWSTR inf;
DWORD rc;
BOOL b;
rc = CaptureAndConvertAnsiArg(InfFileName,&inf);
if(rc != NO_ERROR) {
SetLastError(rc);
return(FALSE);
}
b = SetupDiInstallClassW(hwndParent,inf,Flags,FileQueue);
rc = GetLastError();
MyFree(inf);
SetLastError(rc);
return(b);
}
#else
//
// Unicode stub
//
BOOL
WINAPI
SetupDiInstallClassW(
IN HWND hwndParent, OPTIONAL
IN PCWSTR InfFileName,
IN DWORD Flags,
IN HSPFILEQ FileQueue OPTIONAL
)
{
UNREFERENCED_PARAMETER(hwndParent);
UNREFERENCED_PARAMETER(InfFileName);
UNREFERENCED_PARAMETER(Flags);
UNREFERENCED_PARAMETER(FileQueue);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return(FALSE);
}
#endif
BOOL
WINAPI
SetupDiInstallClass(
IN HWND hwndParent, OPTIONAL
IN PCTSTR InfFileName,
IN DWORD Flags,
IN HSPFILEQ FileQueue OPTIONAL
)
/*++
Routine Description:
This routine installs the [ClassInstall32] section of the specified INF.
Arguments:
hwndParent - Optionally, supplies the handle of the parent window for any
UI brought up as a result of installing this class.
InfFileName - Supplies the name of the INF file containing a [ClassInstall32]
section
Flags - Flags that control the installation. May be a combination of the following:
DI_NOVCP - This flag should be specified if HSPFILEQ is supplied. This
instructs SetupInstallFromInfSection to not create a queue of its
own, and instead to use the caller-supplied one. If this flag is
specified, then no file copying will be done.
DI_NOBROWSE - This flag should be specified if no file browsing should
be allowed in the event a copy operation cannot find a specified
file. If the user supplies their own file queue, then this flag is
ignored.
DI_FORCECOPY - This flag should be specified if the files should always
be copied, even if they're already present on the user's machine
(i.e., don't ask the user if they want to keep their existing files).
If the user supplies their own file queue, then this flag is ignored.
DI_QUIETINSTALL - This flag should be specified if UI should be suppressed
unless absolutely necessary (i.e., no progress dialog). If the user
supplies their own queue, then this flag is ignored.
FileQueue - If the DI_NOVCP flag is specified, then this parameter supplies a handle
to a file queue where file operations are to be queued (but not committed).
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.
Remarks:
This API is generally called by the Device Manager when it installs a device
of a new class.
--*/
{
HINF hInf;
DWORD Err, ScanQueueResult;
TCHAR ClassInstallSectionName[MAX_SECT_NAME_LEN];
GUID ClassGuid;
HKEY hKey;
PSP_FILE_CALLBACK MsgHandler;
PVOID MsgHandlerContext;
BOOL KeyNewlyCreated;
PCTSTR GuidString, ClassName;
BOOL CloseFileQueue;
PTSTR SectionExtension;
//
// Validate the flags.
//
if(Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL)) {
SetLastError(ERROR_INVALID_FLAGS);
return FALSE;
}
//
// Make sure that the user supplied us with a file queue, if necessary.
//
if((Flags & DI_NOVCP) && (!FileQueue || (FileQueue == INVALID_HANDLE_VALUE))) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if(hwndParent && !IsWindow(hwndParent)) {
hwndParent = NULL;
}
if((hInf = SetupOpenInfFile(InfFileName,
NULL,
INF_STYLE_WIN4,
NULL)) == INVALID_HANDLE_VALUE) {
//
// Last error is already set--just return failure.
//
return FALSE;
}
Err = NO_ERROR;
MsgHandlerContext = NULL;
hKey = NULL;
KeyNewlyCreated = FALSE;
CloseFileQueue = FALSE;
try {
//
// Retrieve the class GUID from the INF. If it has no class GUID, then
// we can't install from it (even if it specifies the class name).
//
// We utilize the fact that an INF handle is really a LOADED_INF pointer,
// combined with the fact that no one else will ever access this handle
// (hence no synchronization issues). This permits us to retrieve this
// version datum much more efficiently.
//
if(!(GuidString = pSetupGetVersionDatum(&((PLOADED_INF)hInf)->VersionBlock,
pszClassGuid))
|| (pSetupGuidFromString(GuidString, &ClassGuid) != NO_ERROR)) {
Err = ERROR_INVALID_CLASS;
goto clean0;
}
//
// First, attempt to open the key (i.e., not create it). If that fails,
// then we'll try to create it. That way, we can keep track of whether
// clean-up is required if an error occurs.
//
if(CM_Open_Class_Key(&ClassGuid,
NULL,
KEY_ALL_ACCESS,
RegDisposition_OpenExisting,
&hKey,
0) != CR_SUCCESS) {
//
// The key doesn't already exist--we've got to create it. We'll need
// to get the class name out of the INF as well.
//
if(!(ClassName = pSetupGetVersionDatum(&((PLOADED_INF)hInf)->VersionBlock,
pszClass))) {
Err = ERROR_INVALID_CLASS;
goto clean0;
}
if(CM_Open_Class_Key(&ClassGuid,
ClassName,
KEY_ALL_ACCESS,
RegDisposition_OpenAlways,
&hKey,
0) != CR_SUCCESS) {
hKey = NULL; // make sure it's still NULL
Err = ERROR_INVALID_DATA;
goto clean0;
}
KeyNewlyCreated = TRUE;
}
//
// Append the layout INF, if necessary.
//
SetupOpenAppendInfFile(NULL, hInf, NULL);
//
// Get the 'real' (potentially OS/architecture-specific) class install
// section name.
//
SetupDiGetActualSectionToInstall(hInf,
pszClassInstall32,
ClassInstallSectionName,
SIZECHARS(ClassInstallSectionName),
NULL,
&SectionExtension
);
//
// If this is the undecorated name, then make sure that the section actually exists.
//
if(!SectionExtension && (SetupGetLineCount(hInf, ClassInstallSectionName) == -1)) {
Err = ERROR_SECTION_NOT_FOUND;
goto clean0;
}
if(!(Flags & DI_NOVCP)) {
//
// Since we may need to check the queued files to determine whether file copy
// is necessary, we have to open our own queue, and commit it ourselves.
//
if((FileQueue = SetupOpenFileQueue()) != INVALID_HANDLE_VALUE) {
CloseFileQueue = TRUE;
} else {
Err = ERROR_NOT_ENOUGH_MEMORY;
goto clean0;
}
if(!(MsgHandlerContext = SetupInitDefaultQueueCallbackEx(
hwndParent,
(Flags & DI_QUIETINSTALL)
? INVALID_HANDLE_VALUE : NULL,
0,
0,
NULL))) {
Err = ERROR_NOT_ENOUGH_MEMORY;
SetupCloseFileQueue(FileQueue);
CloseFileQueue = FALSE;
goto clean0;
}
MsgHandler = SetupDefaultQueueCallback;
}
Err = pSetupInstallFiles(hInf,
NULL,
ClassInstallSectionName,
NULL,
NULL,
NULL,
(Flags & DI_NOBROWSE) ? SP_COPY_NOBROWSE : 0,
NULL,
FileQueue,
//
// This flag is ignored by pSetupInstallFiles
// because we don't pass a callback here and we
// pass a user-defined file queue. (In other words
// we're not committing the queue so there's no
// callback function to deal with, and the callback
// would be the guy who would care about ansi vs unicode.)
//
TRUE
);
if(CloseFileQueue) {
if(Err == NO_ERROR) {
//
// We successfully queued up the file operations--now we need to commit
// the queue. First off, though, we should check to see if the files are
// already there. (If the 'force copy' flag is set, or if the INF is from
// an OEM location, then we don't care if the files are already there--we
// always need to copy them in that case.)
//
if((Flags & DI_FORCECOPY) || ((PLOADED_INF)hInf)->InfSourcePath) {
//
// always copy the files.
//
ScanQueueResult = 0;
} else {
//
// Determine whether the queue actually needs to be committed.
//
// ScanQueueResult can have 1 of 3 values:
//
// 0: User wants new files or some files were missing;
// Must commit queue.
//
// 1: User wants to use existing files and queue is empty;
// Can skip committing queue.
//
// 2: User wants to use existing files but del/ren queues not empty.
// Must commit queue. The copy queue will have been emptied,
// so only del/ren functions will be performed.
//
//
if(!SetupScanFileQueue(FileQueue,
SPQ_SCAN_FILE_VALIDITY | SPQ_SCAN_INFORM_USER,
hwndParent,
NULL,
NULL,
&ScanQueueResult)) {
Err = GetLastError();
ScanQueueResult = 1; // skip queue commit.
}
}
if(ScanQueueResult != 1) {
//
// Copy enqueued files. In this case the callback is
// SetupDefaultQueueCallback, so we know it's native char width.
//
if(!_SetupCommitFileQueue(hwndParent,
FileQueue,
MsgHandler,
MsgHandlerContext,
TRUE)) {
Err = GetLastError();
}
}
}
//
// Close our file queue handle.
//
SetupCloseFileQueue(FileQueue);
CloseFileQueue = FALSE;
}
//
// Terminate the default queue callback, if it was created. (Do this before
// checking the return status of the file copying.)
//
if(MsgHandlerContext) {
SetupTermDefaultQueueCallback(MsgHandlerContext);
MsgHandlerContext = NULL;
}
if(Err != NO_ERROR) {
goto clean0;
}
//
// If we get to here, then the file copying was successful--now we can perform
// the rest of the installation. We don't pass a callback so we don't worry
// about ansi vs unicode issues here.
//
if(!SetupInstallFromInfSection(NULL,
hInf,
ClassInstallSectionName,
SPINST_INIFILES
| SPINST_REGISTRY
| SPINST_INI2REG,
hKey,
NULL,
0,
NULL,
NULL,
INVALID_HANDLE_VALUE,
NULL)) {
Err = GetLastError();
goto clean0;
}
clean0: ; // nothing to do.
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
if(MsgHandlerContext) {
SetupTermDefaultQueueCallback(MsgHandlerContext);
}
if(CloseFileQueue) {
SetupCloseFileQueue(FileQueue);
}
//
// Reference the following variables so that the compiler will respect our statement
// order w.r.t. assignment.
//
hKey = hKey;
KeyNewlyCreated = KeyNewlyCreated;
}
if(hKey) {
RegCloseKey(hKey);
if((Err != NO_ERROR) && (KeyNewlyCreated)) {
//
// We hit an error, and the key didn't previously exist, so we want to
// remove it.
//
CM_Delete_Class_Key(&ClassGuid, CM_DELETE_CLASS_SUBKEYS);
}
}
SetupCloseInfFile(hInf);
SetLastError(Err);
return(Err == NO_ERROR);
}
#ifdef UNICODE
//
// ANSI version
//
BOOL
WINAPI
SetupDiGetHwProfileFriendlyNameA(
IN DWORD HwProfile,
OUT PSTR FriendlyName,
IN DWORD FriendlyNameSize,
OUT PDWORD RequiredSize OPTIONAL
)
{
WCHAR name[MAX_PROFILE_LEN];
PSTR nameA;
BOOL b;
DWORD rc;
DWORD requiredSize;
b = SetupDiGetHwProfileFriendlyNameW(HwProfile,name,MAX_PROFILE_LEN,&requiredSize);
rc = GetLastError();
if(b) {
if(nameA = UnicodeToAnsi(name)) {
requiredSize = lstrlenA(nameA) + 1;
if(RequiredSize) {
try {
*RequiredSize = requiredSize;
} except(EXCEPTION_EXECUTE_HANDLER) {
rc = ERROR_INVALID_PARAMETER;
b = FALSE;
}
}
if(b) {
if(requiredSize > FriendlyNameSize) {
rc = ERROR_INSUFFICIENT_BUFFER;
b = FALSE;
} else {
if(!lstrcpyA(FriendlyName,nameA)) {
//
// lstrcpy faulted, caller passed in bogus buffer.
//
rc = ERROR_INVALID_USER_BUFFER;
b = FALSE;
}
}
}
MyFree(nameA);
} else {
rc = ERROR_NOT_ENOUGH_MEMORY;
b = FALSE;
}
}
SetLastError(rc);
return(b);
}
#else
//
// Unicode stub
//
BOOL
WINAPI
SetupDiGetHwProfileFriendlyNameW(
IN DWORD HwProfile,
OUT PWSTR FriendlyName,
IN DWORD FriendlyNameSize,
OUT PDWORD RequiredSize OPTIONAL
)
{
UNREFERENCED_PARAMETER(HwProfile);
UNREFERENCED_PARAMETER(FriendlyName);
UNREFERENCED_PARAMETER(FriendlyNameSize);
UNREFERENCED_PARAMETER(RequiredSize);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return(FALSE);
}
#endif
BOOL
WINAPI
SetupDiGetHwProfileFriendlyName(
IN DWORD HwProfile,
OUT PTSTR FriendlyName,
IN DWORD FriendlyNameSize,
OUT PDWORD RequiredSize OPTIONAL
)
/*++
Routine Description:
This routine retrieves the friendly name associated with a hardware profile ID.
Arguments:
HwProfile - Supplies the hardware profile ID whose friendly name is to be
retrieved. If this parameter is 0, then the friendly name for the
current hardware profile is retrieved.
FriendlyName - Supplies the address of a character buffer that receives the
friendly name of the hardware profile.
FriendlyNameSize - Supplies the size, in characters, of the FriendlyName buffer.
RequiredSize - Optionally, supplies the address of a variable that receives the
number of characters required to store the friendly name (including
terminating NULL).
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.
--*/
{
DWORD Err = ERROR_INVALID_HWPROFILE;
HWPROFILEINFO HwProfInfo;
ULONG i;
CONFIGRET cr;
DWORD NameLen;
//
// If a hardware profile ID of 0 is specified, then retrieve information
// about the current hardware profile, otherwise, enumerate the hardware
// profiles, looking for the one specified.
//
if(HwProfile) {
i = 0;
} else {
i = 0xFFFFFFFF;
}
do {
if((cr = CM_Get_Hardware_Profile_Info(i, &HwProfInfo, 0)) == CR_SUCCESS) {
//
// Hardware profile info retrieved--see if it's what we're looking for.
//
if(!HwProfile || (HwProfInfo.HWPI_ulHWProfile == HwProfile)) {
try {
NameLen = lstrlen(HwProfInfo.HWPI_szFriendlyName) + 1;
if(RequiredSize) {
*RequiredSize = NameLen;
}
if(NameLen > FriendlyNameSize) {
Err = ERROR_INSUFFICIENT_BUFFER;
} else {
Err = NO_ERROR;
CopyMemory(FriendlyName,
HwProfInfo.HWPI_szFriendlyName,
NameLen * sizeof(TCHAR)
);
}
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
}
break;
}
//
// This wasn't the profile we wanted--go on to the next one.
//
i++;
} else if(!HwProfile || (cr != CR_NO_SUCH_VALUE)) {
//
// We should abort on any error other than CR_NO_SUCH_VALUE, otherwise
// we might loop forever!
//
Err = ERROR_INVALID_DATA;
break;
}
} while(cr != CR_NO_SUCH_VALUE);
SetLastError(Err);
return (Err == NO_ERROR);
}
BOOL
WINAPI
SetupDiGetHwProfileList(
OUT PDWORD HwProfileList,
IN DWORD HwProfileListSize,
OUT PDWORD RequiredSize,
OUT PDWORD CurrentlyActiveIndex OPTIONAL
)
/*++
Routine Description:
This routine retrieves a list of all currently-defined hardware profile IDs.
Arguments:
HwProfileList - Supplies the address of an array of DWORDs that will receive
the list of currently defined hardware profile IDs.
HwProfileListSize - Supplies the number of DWORDs in the HwProfileList array.
RequiredSize - Supplies the address of a variable that receives the number
of hardware profiles currently defined. If this number is larger than
HwProfileListSize, then the list will be truncated to fit the array size,
and this value will indicate the array size that would be required to store
the entire list (the function will fail, with GetLastError returning
ERROR_INSUFFICIENT_BUFFER in that case).
CurrentlyActiveIndex - Optionally, supplies the address of a variable that
receives the index within the HwProfileList array of the currently active
hardware profile.
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.
--*/
{
DWORD Err = NO_ERROR;
DWORD CurHwProfile;
HWPROFILEINFO HwProfInfo;
ULONG i;
CONFIGRET cr;
//
// First retrieve the currently active hardware profile ID, so we'll know what
// to look for when we're enumerating all profiles (only need to do this if the
// user wants the index of the currently active hardware profile).
//
if(CurrentlyActiveIndex) {
if(CM_Get_Hardware_Profile_Info(0xFFFFFFFF, &HwProfInfo, 0) == CR_SUCCESS) {
//
// Store away the hardware profile ID.
//
CurHwProfile = HwProfInfo.HWPI_ulHWProfile;
} else {
//
// Something bad is wrong when you can't retrieve the default hardware
// profile!
//
Err = ERROR_INVALID_DATA;
goto clean0;
}
}
try {
//
// Enumerate the hardware profiles, retrieving the ID for each.
//
i = 0;
do {
if((cr = CM_Get_Hardware_Profile_Info(i, &HwProfInfo, 0)) == CR_SUCCESS) {
if(i < HwProfileListSize) {
HwProfileList[i] = HwProfInfo.HWPI_ulHWProfile;
}
if(CurrentlyActiveIndex && (HwProfInfo.HWPI_ulHWProfile == CurHwProfile)) {
*CurrentlyActiveIndex = i;
//
// Clear the CurrentlyActiveIndex pointer, so we once we find the
// currently active profile, we won't have to keep comparing.
//
CurrentlyActiveIndex = NULL;
}
i++;
}
} while(cr == CR_SUCCESS);
if(cr == CR_NO_MORE_HW_PROFILES) {
//
// Then we enumerated all hardware profiles. Now see if we had enough
// buffer to hold them all.
//
*RequiredSize = i;
if(i > HwProfileListSize) {
Err = ERROR_INSUFFICIENT_BUFFER;
}
} else {
//
// Something else happened (probably a key not present).
//
Err = ERROR_INVALID_DATA;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
}
clean0:
SetLastError(Err);
return (Err == NO_ERROR);
}