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.
1065 lines
32 KiB
1065 lines
32 KiB
/*++
|
|
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
rhwprof.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the server-side hardware profile APIs.
|
|
|
|
PNP_IsDockStationPresent
|
|
PNP_RequestEjectPC
|
|
PNP_HwProfFlags
|
|
PNP_GetHwProfInfo
|
|
PNP_SetHwProf
|
|
|
|
Author:
|
|
|
|
Paula Tomlinson (paulat) 7-18-1995
|
|
|
|
Environment:
|
|
|
|
User-mode only.
|
|
|
|
Revision History:
|
|
|
|
18-July-1995 paulat
|
|
|
|
Creation and initial implementation.
|
|
|
|
--*/
|
|
|
|
|
|
//
|
|
// includes
|
|
//
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
#include "umpnpi.h"
|
|
#include "umpnpdat.h"
|
|
|
|
#include <profiles.h>
|
|
|
|
|
|
//
|
|
// private prototypes
|
|
//
|
|
BOOL
|
|
IsCurrentProfile(
|
|
ULONG ulProfile
|
|
);
|
|
|
|
|
|
|
|
CONFIGRET
|
|
PNP_IsDockStationPresent(
|
|
IN handle_t hBinding,
|
|
OUT PBOOL Present
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine determines whether a docking station is currently present.
|
|
|
|
Parameters:
|
|
|
|
hBinding RPC binding handle.
|
|
|
|
Present Supplies the address of a boolean variable that is set
|
|
upon successful return to indicate whether or not a
|
|
docking station is currently present.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is CR_SUCCESS.
|
|
If the function fails, the return value is a CR failure code.
|
|
|
|
--*/
|
|
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
HKEY hCurrentDockInfo = NULL, hIDConfigDB = NULL;
|
|
DWORD dataType;
|
|
ULONG dockingState;
|
|
ULONG ejectableDocks;
|
|
ULONG size;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
|
|
try {
|
|
//
|
|
// Validate parameters.
|
|
//
|
|
if (!ARGUMENT_PRESENT(Present)) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
*Present = FALSE;
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
pszRegPathIDConfigDB,
|
|
0,
|
|
KEY_READ,
|
|
&hIDConfigDB) != ERROR_SUCCESS) {
|
|
Status = CR_REGISTRY_ERROR;
|
|
hIDConfigDB = NULL;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (RegOpenKeyEx(hIDConfigDB,
|
|
pszRegKeyCurrentDockInfo,
|
|
0,
|
|
KEY_READ,
|
|
&hCurrentDockInfo) != ERROR_SUCCESS) {
|
|
Status = CR_REGISTRY_ERROR;
|
|
hCurrentDockInfo = NULL;
|
|
goto Clean0;
|
|
}
|
|
|
|
size = sizeof (dockingState);
|
|
|
|
if ((RegQueryValueEx(hCurrentDockInfo,
|
|
pszRegValueDockingState,
|
|
0,
|
|
&dataType,
|
|
(PUCHAR) &dockingState,
|
|
&size) != ERROR_SUCCESS) ||
|
|
(dataType != REG_DWORD) ||
|
|
(size != sizeof (ULONG))) {
|
|
Status = CR_REGISTRY_ERROR;
|
|
goto Clean0;
|
|
}
|
|
|
|
if ((dockingState & HW_PROFILE_DOCKSTATE_UNKNOWN) ==
|
|
HW_PROFILE_DOCKSTATE_DOCKED) {
|
|
|
|
size = sizeof(ejectableDocks);
|
|
|
|
if ((RegQueryValueEx(hCurrentDockInfo,
|
|
pszRegValueEjectableDocks,
|
|
0,
|
|
&dataType,
|
|
(PUCHAR) &ejectableDocks,
|
|
&size) == ERROR_SUCCESS) &&
|
|
(dataType == REG_DWORD) &&
|
|
(size == sizeof(ULONG)) &&
|
|
(ejectableDocks > 0)) {
|
|
*Present = TRUE;
|
|
}
|
|
}
|
|
|
|
Clean0:
|
|
NOTHING;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
if (hIDConfigDB) {
|
|
RegCloseKey(hIDConfigDB);
|
|
}
|
|
|
|
if (hCurrentDockInfo) {
|
|
RegCloseKey(hCurrentDockInfo);
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // PNP_IsDockStationPresent
|
|
|
|
|
|
|
|
CONFIGRET
|
|
PNP_RequestEjectPC(
|
|
IN handle_t hBinding
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine requests that the PC be ejected (i.e., undocked).
|
|
|
|
Parameters:
|
|
|
|
hBinding RPC binding handle.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is CR_SUCCESS.
|
|
If the function fails, the return value is a CR failure code.
|
|
|
|
--*/
|
|
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
NTSTATUS ntStatus;
|
|
WCHAR szDockDevInst[MAX_DEVICE_ID_LEN + 1];
|
|
PLUGPLAY_CONTROL_RETRIEVE_DOCK_DATA dockData;
|
|
|
|
try {
|
|
//
|
|
// Find the dock devnode, if one exists.
|
|
//
|
|
dockData.DeviceInstance = szDockDevInst;
|
|
dockData.DeviceInstanceLength = MAX_DEVICE_ID_LEN;
|
|
|
|
ntStatus = NtPlugPlayControl(PlugPlayControlRetrieveDock,
|
|
&dockData,
|
|
sizeof(PLUGPLAY_CONTROL_RETRIEVE_DOCK_DATA));
|
|
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
Status = MapNtStatusToCmError(ntStatus);
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// Request eject on the dock devnode. Note PNP_RequestDeviceEject may
|
|
// require additional access and/or privileges, as appropriate.
|
|
//
|
|
Status = PNP_RequestDeviceEject(hBinding,
|
|
szDockDevInst,
|
|
NULL, // pVetoType
|
|
NULL, // pszVetoName
|
|
0, // ulNameLength
|
|
0); // ulFlags
|
|
|
|
Clean0:
|
|
NOTHING;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // PNP_RequestEjectPC
|
|
|
|
|
|
|
|
CONFIGRET
|
|
PNP_HwProfFlags(
|
|
IN handle_t hBinding,
|
|
IN ULONG ulAction,
|
|
IN LPCWSTR pDeviceID,
|
|
IN ULONG ulConfig,
|
|
IN OUT PULONG pulValue,
|
|
OUT PPNP_VETO_TYPE pVetoType,
|
|
OUT LPWSTR pszVetoName,
|
|
IN ULONG ulNameLength,
|
|
IN ULONG ulFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the RPC server entry point for the ConfigManager routines that
|
|
get and set the hardware profile flags.
|
|
|
|
Arguments:
|
|
|
|
hBinding RPC binding handle.
|
|
|
|
ulAction Specified whether to get or set the flag. Can be one
|
|
of the PNP_*_HWPROFFLAGS values.
|
|
|
|
pDeviceID Device instance to get/set the hw profile flag for.
|
|
|
|
ulConfig Specifies which profile to get/set the flag for. A
|
|
value of zero indicates to use the current profile.
|
|
|
|
pulValue If setting the flag, then this value on entry contains
|
|
the value to set the hardware profile flag to. If
|
|
getting the flag, then this value will return the
|
|
current hardware profile flag.
|
|
|
|
pVetoType Buffer to receive the type of veto. If this is NULL
|
|
then no veto information will be received and the OS wil
|
|
display the veto information.
|
|
|
|
pszVetoName Buffer to receive the veto information. If this is NULL
|
|
then no veto information will be received and the OS will
|
|
display the veto information.
|
|
|
|
ulNameLength Size of the pszVetoName buffer.
|
|
|
|
ulFlags Depends on the action being performed.
|
|
For PNP_GET_HWPROFFLAGS, no flags are valid.
|
|
For PNP_SET_HWPROFFLAGS, may be CM_SET_HW_PROF_FLAGS_BITS.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds it returns CR_SUCCESS. Otherwise it returns one
|
|
of the CR_* values.
|
|
|
|
--*/
|
|
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
ULONG RegStatus = ERROR_SUCCESS;
|
|
WCHAR RegStr[MAX_CM_PATH];
|
|
HKEY hKey = NULL, hDevKey = NULL;
|
|
ULONG ulValueSize = sizeof(ULONG);
|
|
ULONG ulCurrentValue, ulChange, ulDisposition;
|
|
BOOL AffectsCurrentProfile;
|
|
|
|
//
|
|
// NOTE: The device is not checked for presence or not, this flag is
|
|
// always just set or retrieved directly from the registry, as it is
|
|
// done on Windows 95
|
|
//
|
|
|
|
try {
|
|
//
|
|
// validate parameters
|
|
//
|
|
if ((ulAction != PNP_GET_HWPROFFLAGS) &&
|
|
(ulAction != PNP_SET_HWPROFFLAGS)) {
|
|
Status = CR_INVALID_DATA;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (ulAction == PNP_GET_HWPROFFLAGS) {
|
|
//
|
|
// Validate flags for PNP_GET_HWPROFFLAGS
|
|
//
|
|
if (INVALID_FLAGS(ulFlags, 0)) {
|
|
Status = CR_INVALID_FLAG;
|
|
goto Clean0;
|
|
}
|
|
|
|
} else if (ulAction == PNP_SET_HWPROFFLAGS) {
|
|
//
|
|
// Verify client "write" access
|
|
//
|
|
if (!VerifyClientAccess(hBinding,
|
|
PLUGPLAY_WRITE)) {
|
|
Status = CR_ACCESS_DENIED;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// Validate flags for PNP_SET_HWPROFFLAGS
|
|
//
|
|
if (INVALID_FLAGS(ulFlags, CM_SET_HW_PROF_FLAGS_BITS)) {
|
|
Status = CR_INVALID_FLAG;
|
|
goto Clean0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (!ARGUMENT_PRESENT(pulValue)) {
|
|
Status = CR_INVALID_POINTER;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// Validate value for PNP_SET_HWPROFFLAGS
|
|
//
|
|
if ((ulAction == PNP_SET_HWPROFFLAGS) &&
|
|
(INVALID_FLAGS(*pulValue, CSCONFIGFLAG_BITS))) {
|
|
Status = CR_INVALID_DATA;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (!IsLegalDeviceId(pDeviceID)) {
|
|
Status = CR_INVALID_DEVNODE;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// Construct the path to the Enum branch for the hardware profile
|
|
// specified.
|
|
//
|
|
|
|
if (ulConfig == 0) {
|
|
//
|
|
// a configuration value of zero implies to use the current config
|
|
// System\CCS\Hardware Profiles\Current\System\Enum
|
|
//
|
|
if (FAILED(StringCchPrintf(
|
|
RegStr,
|
|
MAX_CM_PATH,
|
|
L"%s\\%s\\%s",
|
|
pszRegPathHwProfiles,
|
|
pszRegKeyCurrent,
|
|
pszRegPathEnum))) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// use the specified profile id
|
|
// System\CCS\Hardware Profiles\xxxx\System\Enum
|
|
//
|
|
if (FAILED(StringCchPrintf(
|
|
RegStr,
|
|
MAX_CM_PATH,
|
|
L"%s\\%04u\\%s",
|
|
pszRegPathHwProfiles,
|
|
ulConfig,
|
|
pszRegPathEnum))) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------
|
|
// caller wants to retrieve the hw profile flag value
|
|
//----------------------------------------------------
|
|
|
|
if (ulAction == PNP_GET_HWPROFFLAGS) {
|
|
|
|
//
|
|
// open the profile specific enum key
|
|
//
|
|
RegStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE, RegStr, 0,
|
|
KEY_QUERY_VALUE, &hKey);
|
|
|
|
if (RegStatus != ERROR_SUCCESS) {
|
|
*pulValue = 0; // success,this is what Win95 does
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// open the enum\device-instance key under the profile key
|
|
//
|
|
RegStatus = RegOpenKeyEx( hKey, pDeviceID, 0, KEY_QUERY_VALUE, &hDevKey);
|
|
|
|
if (RegStatus != ERROR_SUCCESS) {
|
|
*pulValue = 0; // success,this is what Win95 does
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// query the profile flag
|
|
//
|
|
ulValueSize = sizeof(ULONG);
|
|
RegStatus = RegQueryValueEx( hDevKey, pszRegValueCSConfigFlags,
|
|
NULL, NULL, (LPBYTE)pulValue,
|
|
&ulValueSize);
|
|
|
|
if (RegStatus != ERROR_SUCCESS) {
|
|
|
|
*pulValue = 0;
|
|
|
|
if (RegStatus != ERROR_CANTREAD && RegStatus != ERROR_FILE_NOT_FOUND) {
|
|
Status = CR_REGISTRY_ERROR;
|
|
goto Clean0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//----------------------------------------------
|
|
// caller wants to set the hw profile flag value
|
|
//----------------------------------------------
|
|
|
|
else if (ulAction == PNP_SET_HWPROFFLAGS) {
|
|
|
|
//
|
|
// open the profile specific enum key.
|
|
//
|
|
// note that we may actually end up creating a Hardware Profile key
|
|
// here for the specified profile id, even if no such profile
|
|
// exists. ideally, we should check that such a profile exists, but
|
|
// we've been doing this for too long to change it now. the
|
|
// consolation here is that the client must be granted appropriate
|
|
// access to actually do this.
|
|
//
|
|
RegStatus = RegCreateKeyEx( HKEY_LOCAL_MACHINE, RegStr, 0, NULL,
|
|
REG_OPTION_NON_VOLATILE, KEY_QUERY_VALUE,
|
|
NULL, &hKey, &ulDisposition);
|
|
|
|
if (RegStatus != ERROR_SUCCESS) {
|
|
Status = CR_REGISTRY_ERROR;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// open the enum\device-instance key under the profile key
|
|
//
|
|
RegStatus = RegCreateKeyEx( hKey, pDeviceID, 0, NULL,
|
|
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
|
|
NULL, &hDevKey, NULL);
|
|
|
|
if (RegStatus != ERROR_SUCCESS) {
|
|
Status = CR_REGISTRY_ERROR;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// before setting, query the current profile flag
|
|
//
|
|
ulValueSize = sizeof(ulCurrentValue);
|
|
RegStatus = RegQueryValueEx( hDevKey, pszRegValueCSConfigFlags,
|
|
NULL, NULL, (LPBYTE)&ulCurrentValue,
|
|
&ulValueSize);
|
|
|
|
if (RegStatus == ERROR_CANTREAD || RegStatus == ERROR_FILE_NOT_FOUND) {
|
|
|
|
ulCurrentValue = 0; // success,this is what Win95 does
|
|
|
|
} else if (RegStatus != ERROR_SUCCESS) {
|
|
|
|
Status = CR_REGISTRY_ERROR;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// if requested flags different than current, write out to registry
|
|
//
|
|
ulChange = ulCurrentValue ^ *pulValue;
|
|
|
|
if (ulChange) {
|
|
|
|
AffectsCurrentProfile = (BOOL)(ulConfig == 0 || IsCurrentProfile(ulConfig));
|
|
|
|
//
|
|
// we're about to change the disable bit on the current profile,
|
|
// try and disable the device in the process
|
|
//
|
|
if ((ulChange & CSCONFIGFLAG_DISABLED) &&
|
|
(*pulValue & CSCONFIGFLAG_DISABLED) && AffectsCurrentProfile) {
|
|
|
|
//
|
|
// Verify client "execute" access and privilege.
|
|
//
|
|
// Note that as the PLUGPLAY_* access rights are *currently*
|
|
// granted, we know that the client should have execute
|
|
// access (because they were already granted "write" access,
|
|
// which is granted to a strict subset of groups that are
|
|
// granted "execute" access). Since this does not always
|
|
// have to be the case, we'll make the separate check for
|
|
// "execute" access here, prior to making the privilege
|
|
// check, as usual.
|
|
//
|
|
if ((!VerifyClientAccess(hBinding,
|
|
PLUGPLAY_EXECUTE)) ||
|
|
(!VerifyClientPrivilege(hBinding,
|
|
SE_LOAD_DRIVER_PRIVILEGE,
|
|
L"Device Action (disable device)"))) {
|
|
//
|
|
// The client either does not possess the privilege, or
|
|
// did not have the right to use that privilege with the
|
|
// PlugPlay service. Since they were able to modify the
|
|
// persistent state (i.e. granted "write" access),
|
|
// rather than return "access denied", we'll tell them
|
|
// that a restart is required for the change to take
|
|
// place for the device to be disabled. Set the status,
|
|
// but fall through so that the CSConfigFlags are still
|
|
// updated.
|
|
//
|
|
// (Note that when Status is set to any failure code
|
|
// other than CR_NOT_DISABLEABLE, it will always be set
|
|
// to CR_NEED_RESTART below, but we'll go ahead use that
|
|
// failure code here as well, rather than confusing the
|
|
// issue.)
|
|
//
|
|
Status = CR_NEED_RESTART;
|
|
|
|
} else {
|
|
|
|
//
|
|
// NOTE: We enter a critical section here to guard against concurrent
|
|
// read/write operations to the "DisableCount" registry value of any
|
|
// single device instance by DisableDevInst (below), and SetupDevInst,
|
|
// EnableDevInst (called by PNP_DeviceInstanceAction).
|
|
//
|
|
PNP_ENTER_SYNCHRONOUS_CALL();
|
|
|
|
//
|
|
// disable the devnode
|
|
//
|
|
Status = DisableDevInst(pDeviceID,
|
|
pVetoType,
|
|
pszVetoName,
|
|
ulNameLength,
|
|
FALSE);
|
|
|
|
PNP_LEAVE_SYNCHRONOUS_CALL();
|
|
}
|
|
|
|
if (Status == CR_NOT_DISABLEABLE) {
|
|
//
|
|
// we got refused!
|
|
// (note that this error also implies *NO* changes to the registry entry)
|
|
//
|
|
goto Clean0;
|
|
|
|
} else if (Status != CR_SUCCESS) {
|
|
//
|
|
// we can go ahead and disable after restart
|
|
//
|
|
Status = CR_NEED_RESTART;
|
|
}
|
|
}
|
|
//
|
|
// assume Status is valid and typically CR_SUCCESS or CR_NEED_RESTART
|
|
//
|
|
|
|
//
|
|
// now update the registry
|
|
//
|
|
RegStatus = RegSetValueEx( hDevKey, pszRegValueCSConfigFlags, 0,
|
|
REG_DWORD, (LPBYTE)pulValue,
|
|
sizeof(ULONG));
|
|
|
|
if (RegStatus != ERROR_SUCCESS) {
|
|
Status = CR_REGISTRY_ERROR;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (Status == CR_NEED_RESTART) {
|
|
//
|
|
// we have to RESTART due to not being able to disable device immediately
|
|
//
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// If this doesn't effect the current config, then we're done.
|
|
//
|
|
if (!AffectsCurrentProfile) {
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// are we enabling the device?
|
|
//
|
|
|
|
if ((ulChange & CSCONFIGFLAG_DISABLED) && !(*pulValue & CSCONFIGFLAG_DISABLED)) {
|
|
//
|
|
// enable the devnode
|
|
//
|
|
|
|
//
|
|
// NOTE: We enter a critical section here to guard against
|
|
// concurrent read/write operations to the "DisableCount"
|
|
// registry value of any single device instance by
|
|
// EnableDevInst (called below), SetupDevInst, and
|
|
// DisableDevInst.
|
|
//
|
|
PNP_ENTER_SYNCHRONOUS_CALL();
|
|
|
|
//
|
|
// enable the devnode
|
|
//
|
|
EnableDevInst(pDeviceID, FALSE);
|
|
|
|
PNP_LEAVE_SYNCHRONOUS_CALL();
|
|
}
|
|
|
|
//
|
|
// did the do-not-create bit change?
|
|
//
|
|
if (ulChange & CSCONFIGFLAG_DO_NOT_CREATE) {
|
|
if (*pulValue & CSCONFIGFLAG_DO_NOT_CREATE) {
|
|
//
|
|
// if subtree can be removed, remove it now
|
|
//
|
|
if (QueryAndRemoveSubTree( pDeviceID,
|
|
pVetoType,
|
|
pszVetoName,
|
|
ulNameLength,
|
|
PNP_QUERY_AND_REMOVE_NO_RESTART) != CR_SUCCESS) {
|
|
|
|
Status = CR_NEED_RESTART;
|
|
goto Clean0;
|
|
}
|
|
}
|
|
else {
|
|
//
|
|
// The DO_NOT_CREATE flag was turned off, reenumerate the devnode
|
|
//
|
|
ReenumerateDevInst(pDeviceID, TRUE, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Clean0:
|
|
NOTHING;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
if (hKey != NULL) {
|
|
RegCloseKey(hKey);
|
|
}
|
|
if (hDevKey != NULL) {
|
|
RegCloseKey(hDevKey);
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // PNP_HwProfFlags
|
|
|
|
|
|
|
|
CONFIGRET
|
|
PNP_GetHwProfInfo(
|
|
IN handle_t hBinding,
|
|
IN ULONG ulIndex,
|
|
OUT PHWPROFILEINFO pHWProfileInfo,
|
|
IN ULONG ulProfileInfoSize,
|
|
IN ULONG ulFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the RPC server entry point for the ConfigManager routine
|
|
CM_Get_Hardware_Profile_Info. It returns a structure of info for
|
|
the specified hardware profile.
|
|
|
|
Arguments:
|
|
|
|
hBinding RPC binding handle.
|
|
|
|
ulIndex Specifies which profile to use. A value of 0xFFFFFFFF
|
|
indicates to use the current profile.
|
|
|
|
pHWProfileInfo Pointer to HWPROFILEINFO struct, returns profile info
|
|
|
|
ulProfileInfoSize Specifies the size of the HWPROFILEINFO struct
|
|
|
|
ulFlags Not used, must be zero.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds it returns CR_SUCCESS. Otherwise it returns one
|
|
of the CR_* values.
|
|
|
|
--*/
|
|
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
ULONG RegStatus = ERROR_SUCCESS;
|
|
WCHAR RegStr[MAX_CM_PATH];
|
|
HKEY hKey = NULL, hDockKey = NULL, hCfgKey = NULL;
|
|
ULONG ulSize, ulDisposition;
|
|
ULONG enumIndex, targetIndex;
|
|
|
|
UNREFERENCED_PARAMETER(hBinding);
|
|
|
|
try {
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (INVALID_FLAGS(ulFlags, 0)) {
|
|
Status = CR_INVALID_FLAG;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// validate the size of the HWPROFILEINFO struct
|
|
//
|
|
if (ulProfileInfoSize != sizeof(HWPROFILEINFO)) {
|
|
Status = CR_INVALID_DATA;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// initialize the HWPROFILEINFO struct fields
|
|
//
|
|
pHWProfileInfo->HWPI_ulHWProfile = 0;
|
|
pHWProfileInfo->HWPI_szFriendlyName[0] = L'\0';
|
|
pHWProfileInfo->HWPI_dwFlags = 0;
|
|
|
|
//
|
|
// open a key to IDConfigDB (create if it doesn't already exist
|
|
//
|
|
RegStatus = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszRegPathIDConfigDB, 0,
|
|
NULL, REG_OPTION_NON_VOLATILE, KEY_QUERY_VALUE,
|
|
NULL, &hKey, &ulDisposition);
|
|
|
|
if (RegStatus != ERROR_SUCCESS) {
|
|
Status = CR_REGISTRY_ERROR;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// open a key to Hardware Profiles (create if it doesn't already exist)
|
|
//
|
|
RegStatus = RegCreateKeyEx(hKey, pszRegKeyKnownDockingStates, 0,
|
|
NULL, REG_OPTION_NON_VOLATILE,
|
|
KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, NULL,
|
|
&hDockKey, &ulDisposition);
|
|
|
|
if (RegStatus != ERROR_SUCCESS) {
|
|
Status = CR_REGISTRY_ERROR;
|
|
goto Clean0;
|
|
}
|
|
|
|
|
|
//
|
|
// a configuration value of 0xFFFFFFFF implies to use the current config
|
|
//
|
|
if (ulIndex == 0xFFFFFFFF) {
|
|
//
|
|
// get the current profile index stored under IDConfigDB
|
|
//
|
|
ulSize = sizeof(ULONG);
|
|
RegStatus = RegQueryValueEx(
|
|
hKey, pszRegValueCurrentConfig, NULL, NULL,
|
|
(LPBYTE)&pHWProfileInfo->HWPI_ulHWProfile, &ulSize);
|
|
|
|
if (RegStatus != ERROR_SUCCESS) {
|
|
Status = CR_REGISTRY_ERROR;
|
|
pHWProfileInfo->HWPI_ulHWProfile = 0;
|
|
goto Clean0;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// values other than 0xFFFFFFFF mean that we're essentially
|
|
// enumerating profiles (the value is an enumeration index)
|
|
//
|
|
else {
|
|
//
|
|
// enumerate the profile keys under Known Docking States
|
|
//
|
|
Status = CR_SUCCESS;
|
|
enumIndex = 0;
|
|
targetIndex = ulIndex;
|
|
while(enumIndex <= targetIndex) {
|
|
ulSize = MAX_CM_PATH;
|
|
RegStatus = RegEnumKeyEx(hDockKey,
|
|
enumIndex,
|
|
RegStr,
|
|
&ulSize,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
if (RegStatus == ERROR_NO_MORE_ITEMS) {
|
|
Status = CR_NO_MORE_HW_PROFILES;
|
|
goto Clean0;
|
|
} else if (RegStatus != ERROR_SUCCESS) {
|
|
Status = CR_REGISTRY_ERROR;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (_wtoi(RegStr) == 0) {
|
|
//
|
|
// we found the pristine amidst the profiles we're enumerating.
|
|
// enumerate one extra key to make up for it.
|
|
//
|
|
targetIndex++;
|
|
}
|
|
if (enumIndex == targetIndex) {
|
|
//
|
|
// this is the one we want.
|
|
//
|
|
pHWProfileInfo->HWPI_ulHWProfile = _wtoi(RegStr);
|
|
Status = CR_SUCCESS;
|
|
break;
|
|
}
|
|
enumIndex++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// open the key for this profile
|
|
//
|
|
if (FAILED(StringCchPrintf(
|
|
RegStr,
|
|
MAX_CM_PATH,
|
|
L"%04u",
|
|
pHWProfileInfo->HWPI_ulHWProfile))) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
RegStatus =
|
|
RegOpenKeyEx(
|
|
hDockKey,
|
|
RegStr,
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hCfgKey);
|
|
|
|
if (RegStatus != ERROR_SUCCESS) {
|
|
Status = CR_REGISTRY_ERROR;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// retrieve the friendly name
|
|
//
|
|
ulSize = MAX_PROFILE_LEN * sizeof(WCHAR);
|
|
RegStatus = RegQueryValueEx(
|
|
hCfgKey, pszRegValueFriendlyName, NULL, NULL,
|
|
(LPBYTE)(pHWProfileInfo->HWPI_szFriendlyName),
|
|
&ulSize);
|
|
|
|
//
|
|
// retrieve the DockState
|
|
//
|
|
#if 0
|
|
//
|
|
// KENRAY
|
|
// This is the wrong way to determine docking state caps
|
|
// You must instead check the alias tables
|
|
//
|
|
StringCchPrintf(
|
|
RegStr,
|
|
MAX_CM_PATH,
|
|
L"%04u",
|
|
pHWProfileInfo->HWPI_ulHWProfile);
|
|
|
|
ulSize = sizeof(SYSTEM_DOCK_STATE);
|
|
RegStatus = RegQueryValueEx(
|
|
hCfgKey, pszRegValueDockState, NULL, NULL,
|
|
(LPBYTE)&DockState, &ulSize);
|
|
|
|
if (RegStatus != ERROR_SUCCESS) {
|
|
pHWProfileInfo->HWPI_dwFlags = CM_HWPI_NOT_DOCKABLE;
|
|
}
|
|
else {
|
|
//
|
|
// map SYSTEM_DOCK_STATE enumerated types into CM_HWPI_ flags
|
|
//
|
|
if (DockState == SystemDocked) {
|
|
pHWProfileInfo->HWPI_dwFlags = CM_HWPI_DOCKED;
|
|
}
|
|
else if (DockState == SystemUndocked) {
|
|
pHWProfileInfo->HWPI_dwFlags = CM_HWPI_UNDOCKED;
|
|
}
|
|
else {
|
|
pHWProfileInfo->HWPI_dwFlags = CM_HWPI_NOT_DOCKABLE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
Clean0:
|
|
NOTHING;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
if (hKey != NULL) {
|
|
RegCloseKey(hKey);
|
|
}
|
|
if (hDockKey != NULL) {
|
|
RegCloseKey(hDockKey);
|
|
}
|
|
if (hCfgKey != NULL) {
|
|
RegCloseKey(hCfgKey);
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // PNP_GetHwProfInfo
|
|
|
|
|
|
|
|
CONFIGRET
|
|
PNP_SetHwProf(
|
|
IN handle_t hBinding,
|
|
IN ULONG ulHardwareProfile,
|
|
IN ULONG ulFlags
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(ulHardwareProfile);
|
|
UNREFERENCED_PARAMETER(ulFlags);
|
|
|
|
//
|
|
// Verify client "execute" access
|
|
//
|
|
if (!VerifyClientAccess(hBinding,
|
|
PLUGPLAY_EXECUTE)) {
|
|
return CR_ACCESS_DENIED;
|
|
}
|
|
|
|
//
|
|
// Verify client privilege
|
|
//
|
|
if (!VerifyClientPrivilege(hBinding,
|
|
SE_LOAD_DRIVER_PRIVILEGE,
|
|
L"Set Hardware Profile (not implemented)")) {
|
|
return CR_ACCESS_DENIED;
|
|
}
|
|
|
|
return CR_CALL_NOT_IMPLEMENTED;
|
|
|
|
} // PNP_SetHwProf
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
// Private utility routines
|
|
//-------------------------------------------------------------------
|
|
|
|
BOOL
|
|
IsCurrentProfile(
|
|
ULONG ulProfile
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines if the specified profile matches the current
|
|
profile.
|
|
|
|
Arguments:
|
|
|
|
ulProfile Profile id value (value from 1 - 9999).
|
|
|
|
Return Value:
|
|
|
|
Return TRUE if this is the current profile, FALSE if it isn't.
|
|
|
|
--*/
|
|
|
|
{
|
|
HKEY hKey;
|
|
ULONG ulSize, ulCurrentProfile;
|
|
|
|
//
|
|
// open a key to IDConfigDB
|
|
//
|
|
if (RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE, pszRegPathIDConfigDB, 0,
|
|
KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// get the current profile index stored under IDConfigDB
|
|
//
|
|
ulSize = sizeof(ULONG);
|
|
if (RegQueryValueEx(
|
|
hKey, pszRegValueCurrentConfig, NULL, NULL,
|
|
(LPBYTE)&ulCurrentProfile, &ulSize) != ERROR_SUCCESS) {
|
|
RegCloseKey(hKey);
|
|
return FALSE;
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
if (ulCurrentProfile == ulProfile) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
} // IsCurrentProfile
|
|
|
|
|
|
|