3497 lines
106 KiB
C
3497 lines
106 KiB
C
/*++
|
|
|
|
Copyright (c) 1993-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
devreg.c
|
|
|
|
Abstract:
|
|
|
|
Device Installer routines for registry storage/retrieval.
|
|
|
|
Author:
|
|
|
|
Lonny McMichael (lonnym) 1-July-1995
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
//
|
|
// Private function prototypes
|
|
//
|
|
DWORD
|
|
pSetupOpenOrCreateDevRegKey(
|
|
IN PDEVICE_INFO_SET DeviceInfoSet,
|
|
IN PDEVINFO_ELEM DevInfoElem,
|
|
IN DWORD Scope,
|
|
IN DWORD HwProfile,
|
|
IN DWORD KeyType,
|
|
IN BOOL Create,
|
|
IN REGSAM samDesired,
|
|
OUT PHKEY hDevRegKey
|
|
);
|
|
|
|
BOOL
|
|
pSetupFindUniqueKey(
|
|
IN HKEY hkRoot,
|
|
IN LPTSTR SubKey,
|
|
IN ULONG SubKeyLength
|
|
);
|
|
|
|
DWORD
|
|
pSetupOpenOrCreateInterfaceDeviceRegKey(
|
|
IN HKEY hInterfaceClassKey,
|
|
IN PDEVICE_INFO_SET DeviceInfoSet,
|
|
IN PSP_DEVICE_INTERFACE_DATA InterfaceDeviceData,
|
|
IN BOOL Create,
|
|
IN REGSAM samDesired,
|
|
OUT PHKEY hInterfaceDeviceKey
|
|
);
|
|
|
|
DWORD
|
|
pSetupDeleteInterfaceDeviceKey(
|
|
IN HKEY hInterfaceClassKey,
|
|
IN PDEVICE_INFO_SET DeviceInfoSet,
|
|
IN PSP_DEVICE_INTERFACE_DATA InterfaceDeviceData
|
|
);
|
|
|
|
|
|
HKEY
|
|
WINAPI
|
|
SetupDiOpenClassRegKey(
|
|
IN CONST GUID *ClassGuid, OPTIONAL
|
|
IN REGSAM samDesired
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API opens the installer class registry key or a specific class
|
|
installer's subkey.
|
|
|
|
Arguments:
|
|
|
|
ClassGuid - Optionally, supplies a pointer to the GUID of the class whose
|
|
key is to be opened. If this parameter is NULL, then the root of the
|
|
class tree will be opened.
|
|
|
|
samDesired - Specifies the access you require for this key.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is a handle to an opened registry
|
|
key.
|
|
|
|
If the function fails, the return value is INVALID_HANDLE_VALUE. To get
|
|
extended error information, call GetLastError.
|
|
|
|
Remarks:
|
|
|
|
This API _will not_ create a registry key if it doesn't already exist.
|
|
|
|
The handle returned from this API must be closed by calling RegCloseKey.
|
|
|
|
To get at the interface class (DeviceClasses) branch, or to access the
|
|
registry on a remote machine, use SetupDiOpenClassRegKeyEx.
|
|
|
|
--*/
|
|
{
|
|
return SetupDiOpenClassRegKeyEx(ClassGuid, samDesired, DIOCR_INSTALLER, NULL, NULL);
|
|
}
|
|
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// ANSI version
|
|
//
|
|
HKEY
|
|
WINAPI
|
|
SetupDiOpenClassRegKeyExA(
|
|
IN CONST GUID *ClassGuid, OPTIONAL
|
|
IN REGSAM samDesired,
|
|
IN DWORD Flags,
|
|
IN PCSTR MachineName, OPTIONAL
|
|
IN PVOID Reserved
|
|
)
|
|
{
|
|
PCWSTR UnicodeMachineName;
|
|
DWORD rc;
|
|
HKEY hk;
|
|
|
|
hk = INVALID_HANDLE_VALUE;
|
|
|
|
if(MachineName) {
|
|
rc = pSetupCaptureAndConvertAnsiArg(MachineName, &UnicodeMachineName);
|
|
} else {
|
|
UnicodeMachineName = NULL;
|
|
rc = NO_ERROR;
|
|
}
|
|
|
|
if(rc == NO_ERROR) {
|
|
|
|
hk = SetupDiOpenClassRegKeyExW(ClassGuid,
|
|
samDesired,
|
|
Flags,
|
|
UnicodeMachineName,
|
|
Reserved
|
|
);
|
|
rc = GetLastError();
|
|
|
|
if(UnicodeMachineName) {
|
|
MyFree(UnicodeMachineName);
|
|
}
|
|
}
|
|
|
|
SetLastError(rc);
|
|
return hk;
|
|
}
|
|
#else
|
|
//
|
|
// Unicode version
|
|
//
|
|
HKEY
|
|
WINAPI
|
|
SetupDiOpenClassRegKeyExW(
|
|
IN CONST GUID *ClassGuid, OPTIONAL
|
|
IN REGSAM samDesired,
|
|
IN DWORD Flags,
|
|
IN PCWSTR MachineName, OPTIONAL
|
|
IN PVOID Reserved
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(ClassGuid);
|
|
UNREFERENCED_PARAMETER(samDesired);
|
|
UNREFERENCED_PARAMETER(Flags);
|
|
UNREFERENCED_PARAMETER(MachineName);
|
|
UNREFERENCED_PARAMETER(Reserved);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|
|
|
|
HKEY
|
|
WINAPI
|
|
SetupDiOpenClassRegKeyEx(
|
|
IN CONST GUID *ClassGuid, OPTIONAL
|
|
IN REGSAM samDesired,
|
|
IN DWORD Flags,
|
|
IN PCTSTR MachineName, OPTIONAL
|
|
IN PVOID Reserved
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API opens the root of either the installer or the interface class registry
|
|
branch, or a specified class subkey under one of these branches.
|
|
|
|
If the root key is requested, it will be created if not already present (i.e.,
|
|
you're always guaranteed to get a handle to the root unless a registry error
|
|
occurs).
|
|
|
|
If a particular class subkey is requested, it will be returned if present.
|
|
Otherwise, this API will return ERROR_INVALID_CLASS.
|
|
|
|
Arguments:
|
|
|
|
ClassGuid - Optionally, supplies a pointer to the GUID of the class whose
|
|
key is to be opened. If this parameter is NULL, then the root of the
|
|
class tree will be opened. This GUID is either an installer class or
|
|
an interface class depending on the Flags argument.
|
|
|
|
samDesired - Specifies the access you require for this key.
|
|
|
|
Flags - Specifies which registry branch the key is to be opened for. May
|
|
be one of the following values:
|
|
|
|
DIOCR_INSTALLER - Open the class installer (Class) branch.
|
|
DIOCR_INTERFACE - Open the interface class (DeviceClasses) branch.
|
|
|
|
MachineName - If specified, this value indicates the remote machine where
|
|
the key is to be opened.
|
|
|
|
Reserved - Reserved for future use--must be NULL.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is a handle to an opened registry
|
|
key.
|
|
|
|
If the function fails, the return value is INVALID_HANDLE_VALUE. To get
|
|
extended error information, call GetLastError.
|
|
|
|
Remarks:
|
|
|
|
The handle returned from this API must be closed by calling RegCloseKey.
|
|
|
|
--*/
|
|
{
|
|
HKEY hk;
|
|
CONFIGRET cr;
|
|
DWORD Err = NO_ERROR;
|
|
HMACHINE hMachine = NULL;
|
|
|
|
//
|
|
// Make sure the user didn't pass us anything in the Reserved parameter.
|
|
//
|
|
if(Reserved) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
//
|
|
// Validate the flags (really, just an enum for now, but treated as
|
|
// flags for future extensibility).
|
|
//
|
|
if((Flags & ~(DIOCR_INSTALLER | DIOCR_INTERFACE)) ||
|
|
((Flags != DIOCR_INSTALLER) && (Flags != DIOCR_INTERFACE))) {
|
|
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
try {
|
|
|
|
if(MachineName) {
|
|
|
|
if(CR_SUCCESS != (cr = CM_Connect_Machine(MachineName, &hMachine))) {
|
|
//
|
|
// Make sure machine handle is still invalid, so we won't
|
|
// try to disconnect later.
|
|
//
|
|
hMachine = NULL;
|
|
Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
|
|
goto clean0;
|
|
}
|
|
}
|
|
|
|
if((cr = CM_Open_Class_Key_Ex((LPGUID)ClassGuid,
|
|
NULL,
|
|
samDesired,
|
|
ClassGuid ? RegDisposition_OpenExisting
|
|
: RegDisposition_OpenAlways,
|
|
&hk,
|
|
(Flags & DIOCR_INSTALLER) ? CM_OPEN_CLASS_KEY_INSTALLER
|
|
: CM_OPEN_CLASS_KEY_INTERFACE,
|
|
hMachine)) != CR_SUCCESS)
|
|
{
|
|
if(cr == CR_NO_SUCH_REGISTRY_KEY) {
|
|
Err = ERROR_INVALID_CLASS;
|
|
} else {
|
|
Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
|
|
}
|
|
}
|
|
|
|
clean0: ; // nothing to do.
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
//
|
|
// Reference the following variable(s) so the compiler will respect our statement
|
|
// ordering w.r.t. assignment.
|
|
//
|
|
hMachine = hMachine;
|
|
}
|
|
|
|
if(hMachine) {
|
|
CM_Disconnect_Machine(hMachine);
|
|
}
|
|
|
|
SetLastError(Err);
|
|
return (Err == NO_ERROR) ? hk : INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// ANSI version
|
|
//
|
|
HKEY
|
|
WINAPI
|
|
SetupDiCreateDevRegKeyA(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN DWORD Scope,
|
|
IN DWORD HwProfile,
|
|
IN DWORD KeyType,
|
|
IN HINF InfHandle, OPTIONAL
|
|
IN PCSTR InfSectionName OPTIONAL
|
|
)
|
|
{
|
|
DWORD rc;
|
|
PWSTR name;
|
|
HKEY h;
|
|
|
|
if(InfSectionName) {
|
|
rc = pSetupCaptureAndConvertAnsiArg(InfSectionName,&name);
|
|
if(rc != NO_ERROR) {
|
|
SetLastError(rc);
|
|
return(INVALID_HANDLE_VALUE);
|
|
}
|
|
} else {
|
|
name = NULL;
|
|
}
|
|
|
|
h = SetupDiCreateDevRegKeyW(
|
|
DeviceInfoSet,
|
|
DeviceInfoData,
|
|
Scope,
|
|
HwProfile,
|
|
KeyType,
|
|
InfHandle,
|
|
name
|
|
);
|
|
|
|
rc = GetLastError();
|
|
|
|
if(name) {
|
|
MyFree(name);
|
|
}
|
|
SetLastError(rc);
|
|
return(h);
|
|
}
|
|
#else
|
|
//
|
|
// Unicode stub
|
|
//
|
|
HKEY
|
|
WINAPI
|
|
SetupDiCreateDevRegKeyW(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN DWORD Scope,
|
|
IN DWORD HwProfile,
|
|
IN DWORD KeyType,
|
|
IN HINF InfHandle, OPTIONAL
|
|
IN PCWSTR InfSectionName OPTIONAL
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(DeviceInfoSet);
|
|
UNREFERENCED_PARAMETER(DeviceInfoData);
|
|
UNREFERENCED_PARAMETER(Scope);
|
|
UNREFERENCED_PARAMETER(HwProfile);
|
|
UNREFERENCED_PARAMETER(KeyType);
|
|
UNREFERENCED_PARAMETER(InfHandle);
|
|
UNREFERENCED_PARAMETER(InfSectionName);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(INVALID_HANDLE_VALUE);
|
|
}
|
|
#endif
|
|
|
|
HKEY
|
|
WINAPI
|
|
SetupDiCreateDevRegKey(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN DWORD Scope,
|
|
IN DWORD HwProfile,
|
|
IN DWORD KeyType,
|
|
IN HINF InfHandle, OPTIONAL
|
|
IN PCTSTR InfSectionName OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a registry storage key for device-specific configuration
|
|
information, and returns a handle to the key.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - Supplies a handle to the device information set containing
|
|
information about the device instance whose registry configuration storage
|
|
key is to be created.
|
|
|
|
DeviceInfoData - Supplies a pointer to a SP_DEVINFO_DATA structure indicating
|
|
the device instance to create the registry key for.
|
|
|
|
Scope - Specifies the scope of the registry key to be created. This determines
|
|
where the information is actually stored--the key created may be one that is
|
|
global (i.e., constant regardless of current hardware profile) or hardware
|
|
profile-specific. May be one of the following values:
|
|
|
|
DICS_FLAG_GLOBAL - Create a key to store global configuration information.
|
|
|
|
DICS_FLAG_CONFIGSPECIFIC - Create a key to store hardware profile-specific
|
|
information.
|
|
|
|
HwProfile - Specifies the hardware profile to create a key for, if the Scope parameter
|
|
is set to DICS_FLAG_CONFIGSPECIFIC. If this parameter is 0, then the key
|
|
for the current hardware profile should be created (i.e., in the Class branch
|
|
under HKEY_CURRENT_CONFIG). If Scope is DICS_FLAG_GLOBAL, then this parameter
|
|
is ignored.
|
|
|
|
KeyType - Specifies the type of registry storage key to be created. May be one of
|
|
the following values:
|
|
|
|
DIREG_DEV - Create a hardware registry key for the device. This is the key for
|
|
storage of driver-independent configuration information. (This key is in
|
|
the device instance key in the Enum branch.
|
|
|
|
DIREG_DRV - Create a software, or driver, registry key for the device. (This key
|
|
is located in the class branch.)
|
|
|
|
InfHandle - Optionally, supplies the handle of an opened INF file containing an
|
|
install section to be executed for the newly-created key. If this parameter is
|
|
specified, then InfSectionName must be specified as well.
|
|
|
|
InfSectionName - Optionally, supplies the name of an install section in the INF
|
|
file specified by InfHandle. This section will be executed for the newly
|
|
created key. If this parameter is specified, then InfHandle must be specified
|
|
as well.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is a handle to a newly-created
|
|
registry key where private configuration data pertaining to this device
|
|
instance may be stored/retrieved.
|
|
|
|
If the function fails, the return value is INVALID_HANDLE_VALUE. To get
|
|
extended error information, call GetLastError.
|
|
|
|
Remarks:
|
|
|
|
The handle returned from this routine must be closed by calling RegCloseKey.
|
|
|
|
The specified device instance must have been previously registered (i.e.,
|
|
if it was created via SetupDiCreateDeviceInfo, then SetupDiRegisterDeviceInfo
|
|
must have been subsequently called.)
|
|
|
|
During GUI-mode setup on Windows NT, quiet-install behavior is always
|
|
employed in the absence of a user-supplied file queue, regardless of
|
|
whether the device information element has the DI_QUIETINSTALL flag set.
|
|
|
|
--*/
|
|
|
|
{
|
|
HKEY hk = INVALID_HANDLE_VALUE;
|
|
PDEVICE_INFO_SET pDeviceInfoSet;
|
|
DWORD Err;
|
|
PDEVINFO_ELEM DevInfoElem;
|
|
PSP_FILE_CALLBACK MsgHandler;
|
|
PVOID MsgHandlerContext;
|
|
BOOL MsgHandlerIsNativeCharWidth;
|
|
BOOL NoProgressUI;
|
|
|
|
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
Err = NO_ERROR;
|
|
|
|
try {
|
|
//
|
|
// Get a pointer to the element for the specified device
|
|
// instance.
|
|
//
|
|
if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
|
|
DeviceInfoData,
|
|
NULL))) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Create the requested registry storage key.
|
|
//
|
|
if((Err = pSetupOpenOrCreateDevRegKey(pDeviceInfoSet,
|
|
DevInfoElem,
|
|
Scope,
|
|
HwProfile,
|
|
KeyType,
|
|
TRUE,
|
|
KEY_ALL_ACCESS,
|
|
&hk)) != NO_ERROR) {
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// We successfully created the storage key, now run an INF install
|
|
// section against it (if specified).
|
|
//
|
|
if(InfHandle && (InfHandle != INVALID_HANDLE_VALUE) && InfSectionName) {
|
|
//
|
|
// If a copy msg handler and context haven't been specified, then use
|
|
// the default one.
|
|
//
|
|
if(DevInfoElem->InstallParamBlock.InstallMsgHandler) {
|
|
MsgHandler = DevInfoElem->InstallParamBlock.InstallMsgHandler;
|
|
MsgHandlerContext = DevInfoElem->InstallParamBlock.InstallMsgHandlerContext;
|
|
MsgHandlerIsNativeCharWidth = DevInfoElem->InstallParamBlock.InstallMsgHandlerIsNativeCharWidth;
|
|
} else {
|
|
|
|
NoProgressUI = (GuiSetupInProgress || (DevInfoElem->InstallParamBlock.Flags & DI_QUIETINSTALL));
|
|
|
|
if(!(MsgHandlerContext = SetupInitDefaultQueueCallbackEx(
|
|
DevInfoElem->InstallParamBlock.hwndParent,
|
|
(NoProgressUI ? INVALID_HANDLE_VALUE : NULL),
|
|
0,
|
|
0,
|
|
NULL))) {
|
|
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto clean0;
|
|
}
|
|
MsgHandler = SetupDefaultQueueCallback;
|
|
MsgHandlerIsNativeCharWidth = TRUE;
|
|
}
|
|
|
|
if(!_SetupInstallFromInfSection(DevInfoElem->InstallParamBlock.hwndParent,
|
|
InfHandle,
|
|
InfSectionName,
|
|
SPINST_ALL,
|
|
hk,
|
|
NULL,
|
|
0,
|
|
MsgHandler,
|
|
MsgHandlerContext,
|
|
((KeyType == DIREG_DEV) ? DeviceInfoSet
|
|
: INVALID_HANDLE_VALUE),
|
|
((KeyType == DIREG_DEV) ? DeviceInfoData
|
|
: NULL),
|
|
MsgHandlerIsNativeCharWidth,
|
|
NULL
|
|
)) {
|
|
Err = GetLastError();
|
|
}
|
|
|
|
//
|
|
// If we used the default msg handler, release the default context now.
|
|
//
|
|
if(!DevInfoElem->InstallParamBlock.InstallMsgHandler) {
|
|
SetupTermDefaultQueueCallback(MsgHandlerContext);
|
|
}
|
|
}
|
|
|
|
clean0:
|
|
; // Nothing to do.
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
UnlockDeviceInfoSet(pDeviceInfoSet);
|
|
|
|
if(Err == NO_ERROR) {
|
|
return hk;
|
|
} else {
|
|
if(hk != INVALID_HANDLE_VALUE) {
|
|
RegCloseKey(hk);
|
|
}
|
|
SetLastError(Err);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
|
|
HKEY
|
|
WINAPI
|
|
SetupDiOpenDevRegKey(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN DWORD Scope,
|
|
IN DWORD HwProfile,
|
|
IN DWORD KeyType,
|
|
IN REGSAM samDesired
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens a registry storage key for device-specific configuration
|
|
information, and returns a handle to the key.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - Supplies a handle to the device information set containing
|
|
information about the device instance whose registry configuration storage
|
|
key is to be opened.
|
|
|
|
DeviceInfoData - Supplies a pointer to a SP_DEVINFO_DATA structure indicating
|
|
the device instance to open the registry key for.
|
|
|
|
Scope - Specifies the scope of the registry key to be opened. This determines
|
|
where the information is actually stored--the key opened may be one that is
|
|
global (i.e., constant regardless of current hardware profile) or hardware
|
|
profile-specific. May be one of the following values:
|
|
|
|
DICS_FLAG_GLOBAL - Open a key to store global configuration information.
|
|
|
|
DICS_FLAG_CONFIGSPECIFIC - Open a key to store hardware profile-specific
|
|
information.
|
|
|
|
HwProfile - Specifies the hardware profile to open a key for, if the Scope parameter
|
|
is set to DICS_FLAG_CONFIGSPECIFIC. If this parameter is 0, then the key
|
|
for the current hardware profile should be opened (i.e., in the Class branch
|
|
under HKEY_CURRENT_CONFIG). If Scope is SPDICS_FLAG_GLOBAL, then this parameter
|
|
is ignored.
|
|
|
|
KeyType - Specifies the type of registry storage key to be opened. May be one of
|
|
the following values:
|
|
|
|
DIREG_DEV - Open a hardware registry key for the device. This is the key for
|
|
storage of driver-independent configuration information. (This key is in
|
|
the device instance key in the Enum branch.
|
|
|
|
DIREG_DRV - Open a software (i.e., driver) registry key for the device. (This key
|
|
is located in the class branch.)
|
|
|
|
samDesired - Specifies the access you require for this key.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is a handle to an opened registry
|
|
key where private configuration data pertaining to this device instance may be
|
|
stored/retrieved.
|
|
|
|
If the function fails, the return value is INVALID_HANDLE_VALUE. To get
|
|
extended error information, call GetLastError.
|
|
|
|
Remarks:
|
|
|
|
The handle returned from this routine must be closed by calling RegCloseKey.
|
|
|
|
The specified device instance must have been previously registered (i.e., if it
|
|
was created via SetupDiCreateDeviceInfo, then SetupDiRegisterDeviceInfo must have
|
|
been subsequently called.)
|
|
|
|
--*/
|
|
|
|
{
|
|
HKEY hk;
|
|
PDEVICE_INFO_SET pDeviceInfoSet;
|
|
DWORD Err;
|
|
PDEVINFO_ELEM DevInfoElem;
|
|
|
|
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
Err = NO_ERROR;
|
|
|
|
try {
|
|
//
|
|
// Get a pointer to the element for the specified device
|
|
// instance.
|
|
//
|
|
if(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
|
|
DeviceInfoData,
|
|
NULL)) {
|
|
//
|
|
// Open the requested registry storage key.
|
|
//
|
|
Err = pSetupOpenOrCreateDevRegKey(pDeviceInfoSet,
|
|
DevInfoElem,
|
|
Scope,
|
|
HwProfile,
|
|
KeyType,
|
|
FALSE,
|
|
samDesired,
|
|
&hk
|
|
);
|
|
} else {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
UnlockDeviceInfoSet(pDeviceInfoSet);
|
|
|
|
SetLastError(Err);
|
|
return (Err == NO_ERROR) ? hk : INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
|
|
DWORD
|
|
pSetupOpenOrCreateDevRegKey(
|
|
IN PDEVICE_INFO_SET pDeviceInfoSet,
|
|
IN PDEVINFO_ELEM DevInfoElem,
|
|
IN DWORD Scope,
|
|
IN DWORD HwProfile,
|
|
IN DWORD KeyType,
|
|
IN BOOL Create,
|
|
IN REGSAM samDesired,
|
|
OUT PHKEY hDevRegKey
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates or opens a registry storage key for the specified
|
|
device information element, and returns a handle to the opened key.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - Supplies a pointer to the device information set containing
|
|
the element for which a registry storage key is to be created/opened.
|
|
|
|
DevInfoElem - Supplies a pointer to the device information element for
|
|
which a registry storage key is to be created/opened.
|
|
|
|
Scope - Specifies the scope of the registry key to be created/opened. This determines
|
|
where the information is actually stored--the key created may be one that is
|
|
global (i.e., constant regardless of current hardware profile) or hardware
|
|
profile-specific. May be one of the following values:
|
|
|
|
DICS_FLAG_GLOBAL - Create/open a key to store global configuration information.
|
|
|
|
DICS_FLAG_CONFIGSPECIFIC - Create/open a key to store hardware profile-specific
|
|
information.
|
|
|
|
HwProfile - Specifies the hardware profile to create/open a key for, if the Scope parameter
|
|
is set to DICS_FLAG_CONFIGSPECIFIC. If this parameter is 0, then the key
|
|
for the current hardware profile should be created/opened (i.e., in the Class branch
|
|
under HKEY_CURRENT_CONFIG). If Scope is SPDICS_FLAG_GLOBAL, then this parameter
|
|
is ignored.
|
|
|
|
KeyType - Specifies the type of registry storage key to be created/opened. May be one of
|
|
the following values:
|
|
|
|
DIREG_DEV - Create/open a hardware registry key for the device. This is the key for
|
|
storage of driver-independent configuration information. (This key is in
|
|
the device instance key in the Enum branch.
|
|
|
|
DIREG_DRV - Create/open a software, or driver, registry key for the device. (This key
|
|
is located in the class branch.)
|
|
|
|
Create - Specifies whether the key should be created if doesn't already exist.
|
|
|
|
samDesired - Specifies the access you require for this key.
|
|
|
|
hDevRegKey - Supplies the address of a variable that receives a handle to the
|
|
requested registry key. (This variable will only be written to if the
|
|
handle is successfully opened.)
|
|
|
|
Return Value:
|
|
|
|
If the function is successful, the return value is NO_ERROR, otherwise, it is
|
|
the ERROR_* code indicating the error that occurred.
|
|
|
|
Remarks:
|
|
|
|
If a software key is requested (DIREG_DRV), and there isn't already a 'Driver'
|
|
value entry, then one will be created. This entry is of the form:
|
|
|
|
<ClassGUID>\<instance>
|
|
|
|
where <instance> is a base-10, 4-digit number that is unique within that class.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG RegistryBranch;
|
|
CONFIGRET cr;
|
|
DWORD Err, Disposition;
|
|
HKEY hk, hkClass;
|
|
TCHAR DriverKey[GUID_STRING_LEN + 5]; // Eg, {4d36e978-e325-11ce-bfc1-08002be10318}\0000
|
|
ULONG DriverKeyLength;
|
|
TCHAR EmptyString = TEXT('\0');
|
|
|
|
//
|
|
// Under Win95, the class key uses the class name instead of its GUID. The maximum
|
|
// length of a class name is less than the length of a GUID string, but put a check
|
|
// here just to make sure that this assumption remains valid.
|
|
//
|
|
#if MAX_CLASS_NAME_LEN > MAX_GUID_STRING_LEN
|
|
#error MAX_CLASS_NAME_LEN is larger than MAX_GUID_STRING_LEN--fix DriverKey!
|
|
#endif
|
|
|
|
//
|
|
// Figure out what flags to pass to CM_Open_DevInst_Key
|
|
//
|
|
switch(KeyType) {
|
|
|
|
case DIREG_DEV :
|
|
RegistryBranch = CM_REGISTRY_HARDWARE;
|
|
break;
|
|
|
|
case DIREG_DRV :
|
|
//
|
|
// This key may only be opened if the device instance has been registered.
|
|
//
|
|
if(!(DevInfoElem->DiElemFlags & DIE_IS_REGISTERED)) {
|
|
return ERROR_DEVINFO_NOT_REGISTERED;
|
|
}
|
|
|
|
//
|
|
// Retrieve the 'Driver' registry property which indicates where the
|
|
// storage key is located in the class branch.
|
|
//
|
|
DriverKeyLength = sizeof(DriverKey);
|
|
if((cr = CM_Get_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
|
|
CM_DRP_DRIVER,
|
|
NULL,
|
|
DriverKey,
|
|
&DriverKeyLength,
|
|
0,
|
|
pDeviceInfoSet->hMachine)) != CR_SUCCESS) {
|
|
|
|
if(cr != CR_NO_SUCH_VALUE) {
|
|
return (cr == CR_INVALID_DEVINST) ? ERROR_NO_SUCH_DEVINST
|
|
: ERROR_INVALID_DATA;
|
|
} else if(!Create) {
|
|
return ERROR_KEY_DOES_NOT_EXIST;
|
|
}
|
|
|
|
//
|
|
// The Driver entry doesn't exist, and we should create it.
|
|
//
|
|
hk = INVALID_HANDLE_VALUE;
|
|
if(CM_Open_Class_Key_Ex(NULL,
|
|
NULL,
|
|
KEY_ALL_ACCESS,
|
|
RegDisposition_OpenAlways,
|
|
&hkClass,
|
|
0,
|
|
pDeviceInfoSet->hMachine) != CR_SUCCESS) {
|
|
//
|
|
// This shouldn't fail.
|
|
//
|
|
return ERROR_INVALID_DATA;
|
|
}
|
|
|
|
try {
|
|
//
|
|
// Find a unique key name under this class key.
|
|
//
|
|
DriverKeyLength = SIZECHARS(DriverKey);
|
|
if(CM_Get_Class_Key_Name_Ex(&(DevInfoElem->ClassGuid),
|
|
DriverKey,
|
|
&DriverKeyLength,
|
|
0,
|
|
pDeviceInfoSet->hMachine) != CR_SUCCESS) {
|
|
|
|
Err = ERROR_INVALID_CLASS;
|
|
goto clean0;
|
|
}
|
|
DriverKeyLength--; // don't want to include terminating NULL.
|
|
|
|
while(pSetupFindUniqueKey(hkClass, DriverKey, DriverKeyLength)) {
|
|
|
|
if((Err = RegCreateKeyEx(hkClass,
|
|
DriverKey,
|
|
0,
|
|
&EmptyString,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hk,
|
|
&Disposition)) == ERROR_SUCCESS) {
|
|
//
|
|
// Everything's great, unless the Disposition indicates
|
|
// that the key already existed. That means that someone
|
|
// else claimed the key before we got a chance to. In
|
|
// that case, we close this key, and try again.
|
|
//
|
|
if(Disposition == REG_OPENED_EXISTING_KEY) {
|
|
RegCloseKey(hk);
|
|
hk = INVALID_HANDLE_VALUE;
|
|
//
|
|
// Truncate off the class instance part, to be replaced
|
|
// with a new instance number the next go-around.
|
|
//
|
|
DriverKey[GUID_STRING_LEN - 1] = TEXT('\0');
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
hk = INVALID_HANDLE_VALUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(Err != NO_ERROR) { // NO_ERROR == ERROR_SUCCESS
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Set the device instance's 'Driver' registry property to reflect the
|
|
// new software registry storage location.
|
|
//
|
|
CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
|
|
CM_DRP_DRIVER,
|
|
DriverKey,
|
|
sizeof(DriverKey),
|
|
0,
|
|
pDeviceInfoSet->hMachine);
|
|
|
|
|
|
clean0: ; // nothing to do
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
//
|
|
// Access the hk variable so that the compiler will respect
|
|
// the statement ordering in the try clause.
|
|
//
|
|
hk = hk;
|
|
}
|
|
|
|
if(hk != INVALID_HANDLE_VALUE) {
|
|
RegCloseKey(hk);
|
|
}
|
|
|
|
RegCloseKey(hkClass);
|
|
|
|
if(Err != NO_ERROR) {
|
|
return Err;
|
|
}
|
|
}
|
|
|
|
RegistryBranch = CM_REGISTRY_SOFTWARE;
|
|
break;
|
|
|
|
default :
|
|
return ERROR_INVALID_FLAGS;
|
|
}
|
|
|
|
if(Scope == DICS_FLAG_CONFIGSPECIFIC) {
|
|
RegistryBranch |= CM_REGISTRY_CONFIG;
|
|
} else if(Scope != DICS_FLAG_GLOBAL) {
|
|
return ERROR_INVALID_FLAGS;
|
|
}
|
|
|
|
cr = CM_Open_DevInst_Key_Ex(DevInfoElem->DevInst,
|
|
samDesired,
|
|
HwProfile,
|
|
(Create ? RegDisposition_OpenAlways : RegDisposition_OpenExisting),
|
|
&hk,
|
|
RegistryBranch,
|
|
pDeviceInfoSet->hMachine);
|
|
if(cr == CR_SUCCESS) {
|
|
*hDevRegKey = hk;
|
|
Err = NO_ERROR;
|
|
} else {
|
|
|
|
switch(cr) {
|
|
|
|
case CR_INVALID_DEVINST :
|
|
Err = ERROR_NO_SUCH_DEVINST;
|
|
break;
|
|
|
|
case CR_NO_SUCH_REGISTRY_KEY :
|
|
Err = ERROR_KEY_DOES_NOT_EXIST;
|
|
break;
|
|
|
|
default :
|
|
Err = ERROR_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
return Err;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
_SetupDiGetDeviceRegistryProperty(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN DWORD Property,
|
|
OUT PDWORD PropertyRegDataType, OPTIONAL
|
|
OUT PBYTE PropertyBuffer,
|
|
IN DWORD PropertyBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
#ifdef UNICODE
|
|
IN ,BOOL Ansi
|
|
#endif
|
|
)
|
|
{
|
|
PDEVICE_INFO_SET pDeviceInfoSet;
|
|
DWORD Err;
|
|
PDEVINFO_ELEM DevInfoElem;
|
|
CONFIGRET cr;
|
|
ULONG CmRegProperty, PropLength;
|
|
|
|
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
Err = NO_ERROR;
|
|
|
|
try {
|
|
//
|
|
// Get a pointer to the element for the specified device
|
|
// instance.
|
|
//
|
|
if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
|
|
DeviceInfoData,
|
|
NULL))) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
goto clean0;
|
|
}
|
|
|
|
if(Property < SPDRP_MAXIMUM_PROPERTY) {
|
|
CmRegProperty = (ULONG)SPDRP_TO_CMDRP(Property);
|
|
} else {
|
|
Err = ERROR_INVALID_REG_PROPERTY;
|
|
goto clean0;
|
|
}
|
|
|
|
PropLength = PropertyBufferSize;
|
|
#ifdef UNICODE
|
|
if(Ansi) {
|
|
cr = CM_Get_DevInst_Registry_Property_ExA(
|
|
DevInfoElem->DevInst,
|
|
CmRegProperty,
|
|
PropertyRegDataType,
|
|
PropertyBuffer,
|
|
&PropLength,
|
|
0,
|
|
pDeviceInfoSet->hMachine);
|
|
} else
|
|
#endif
|
|
cr = CM_Get_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
|
|
CmRegProperty,
|
|
PropertyRegDataType,
|
|
PropertyBuffer,
|
|
&PropLength,
|
|
0,
|
|
pDeviceInfoSet->hMachine);
|
|
|
|
if((cr == CR_SUCCESS) || (cr == CR_BUFFER_SMALL)) {
|
|
|
|
if(RequiredSize) {
|
|
*RequiredSize = PropLength;
|
|
}
|
|
}
|
|
|
|
if(cr != CR_SUCCESS) {
|
|
|
|
switch(cr) {
|
|
|
|
case CR_INVALID_DEVINST :
|
|
Err = ERROR_NO_SUCH_DEVINST;
|
|
break;
|
|
|
|
case CR_INVALID_PROPERTY :
|
|
Err = ERROR_INVALID_REG_PROPERTY;
|
|
break;
|
|
|
|
case CR_BUFFER_SMALL :
|
|
Err = ERROR_INSUFFICIENT_BUFFER;
|
|
break;
|
|
|
|
default :
|
|
Err = ERROR_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
clean0:
|
|
; // Nothing to do.
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
UnlockDeviceInfoSet(pDeviceInfoSet);
|
|
|
|
SetLastError(Err);
|
|
return (Err == NO_ERROR);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// ANSI version
|
|
//
|
|
BOOL
|
|
WINAPI
|
|
SetupDiGetDeviceRegistryPropertyA(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN DWORD Property,
|
|
OUT PDWORD PropertyRegDataType, OPTIONAL
|
|
OUT PBYTE PropertyBuffer,
|
|
IN DWORD PropertyBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
{
|
|
BOOL b;
|
|
|
|
b = _SetupDiGetDeviceRegistryProperty(
|
|
DeviceInfoSet,
|
|
DeviceInfoData,
|
|
Property,
|
|
PropertyRegDataType,
|
|
PropertyBuffer,
|
|
PropertyBufferSize,
|
|
RequiredSize,
|
|
TRUE
|
|
);
|
|
|
|
return(b);
|
|
}
|
|
#else
|
|
//
|
|
// Unicode stub
|
|
//
|
|
BOOL
|
|
WINAPI
|
|
SetupDiGetDeviceRegistryPropertyW(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN DWORD Property,
|
|
OUT PDWORD PropertyRegDataType, OPTIONAL
|
|
OUT PBYTE PropertyBuffer,
|
|
IN DWORD PropertyBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(DeviceInfoSet);
|
|
UNREFERENCED_PARAMETER(DeviceInfoData);
|
|
UNREFERENCED_PARAMETER(Property);
|
|
UNREFERENCED_PARAMETER(PropertyRegDataType);
|
|
UNREFERENCED_PARAMETER(PropertyBuffer);
|
|
UNREFERENCED_PARAMETER(PropertyBufferSize);
|
|
UNREFERENCED_PARAMETER(RequiredSize);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupDiGetDeviceRegistryProperty(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN DWORD Property,
|
|
OUT PDWORD PropertyRegDataType, OPTIONAL
|
|
OUT PBYTE PropertyBuffer,
|
|
IN DWORD PropertyBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine retrieves the specified property from the Plug & Play device
|
|
storage location in the registry.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - Supplies a handle to the device information set containing
|
|
information about the device instance to retrieve a Plug & Play registry
|
|
property for.
|
|
|
|
DeviceInfoData - Supplies a pointer to a SP_DEVINFO_DATA structure indicating
|
|
the device instance to retrieve the Plug & Play registry property for.
|
|
|
|
Property - Supplies an ordinal specifying the property to be retrieved. Refer
|
|
to sdk\inc\setupapi.h for a complete list of properties that may be retrieved.
|
|
|
|
PropertyRegDataType - Optionally, supplies the address of a variable that
|
|
will receive the data type of the property being retrieved. This will
|
|
be one of the standard registry data types (REG_SZ, REG_BINARY, etc.)
|
|
|
|
PropertyBuffer - Supplies the address of a buffer that receives the property
|
|
data.
|
|
|
|
PropertyBufferSize - Supplies the length, in bytes, of PropertyBuffer.
|
|
|
|
RequiredSize - Optionally, supplies the address of a variable that receives
|
|
the number of bytes required to store the requested property in the buffer.
|
|
|
|
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. If the supplied buffer was not large enough
|
|
to hold the requested property, the error will be ERROR_INSUFFICIENT_BUFFER,
|
|
and RequiredSize will specify how large the buffer needs to be.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL b;
|
|
|
|
b = _SetupDiGetDeviceRegistryProperty(
|
|
DeviceInfoSet,
|
|
DeviceInfoData,
|
|
Property,
|
|
PropertyRegDataType,
|
|
PropertyBuffer,
|
|
PropertyBufferSize,
|
|
RequiredSize
|
|
#ifdef UNICODE
|
|
,FALSE
|
|
#endif
|
|
);
|
|
|
|
return(b);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
_SetupDiSetDeviceRegistryProperty(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN OUT PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN DWORD Property,
|
|
IN CONST BYTE* PropertyBuffer, OPTIONAL
|
|
IN DWORD PropertyBufferSize
|
|
#ifdef UNICODE
|
|
IN ,BOOL Ansi
|
|
#endif
|
|
)
|
|
{
|
|
PDEVICE_INFO_SET pDeviceInfoSet;
|
|
DWORD Err;
|
|
PDEVINFO_ELEM DevInfoElem;
|
|
CONFIGRET cr;
|
|
ULONG CmRegProperty;
|
|
GUID ClassGuid;
|
|
BOOL ClassGuidSpecified;
|
|
TCHAR ClassName[MAX_CLASS_NAME_LEN];
|
|
DWORD ClassNameLength;
|
|
|
|
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
Err = NO_ERROR;
|
|
|
|
try {
|
|
//
|
|
// Get a pointer to the element for the specified device
|
|
// instance.
|
|
//
|
|
if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
|
|
DeviceInfoData,
|
|
NULL))) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Make sure the property code is in-range, and is not SPDRP_CLASS
|
|
// (the Class property is not settable directly, and is automatically
|
|
// updated when the ClassGUID property changes).
|
|
//
|
|
if((Property < SPDRP_MAXIMUM_PROPERTY) && (Property != SPDRP_CLASS)) {
|
|
CmRegProperty = (ULONG)SPDRP_TO_CMDRP(Property);
|
|
} else {
|
|
Err = ERROR_INVALID_REG_PROPERTY;
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// If the property we're setting is ClassGUID, then we need to check to
|
|
// see whether the new GUID is different from the current one. If there's
|
|
// no change, then we're done.
|
|
//
|
|
if(CmRegProperty == CM_DRP_CLASSGUID) {
|
|
|
|
if(!PropertyBuffer) {
|
|
//
|
|
// Then the intent is to reset the device's class GUID. Make
|
|
// sure they passed us a buffer length of zero.
|
|
//
|
|
if(PropertyBufferSize) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
goto clean0;
|
|
}
|
|
|
|
ClassGuidSpecified = FALSE;
|
|
|
|
} else {
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// If we're being called from the ANSI API then we need
|
|
// to convert the ANSI string representation of the GUID
|
|
// to Unicode before we convert the string to an actual GUID.
|
|
//
|
|
PCWSTR UnicodeGuidString;
|
|
|
|
if(Ansi) {
|
|
UnicodeGuidString = pSetupAnsiToUnicode((PCSTR)PropertyBuffer);
|
|
if(!UnicodeGuidString) {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto clean0;
|
|
}
|
|
} else {
|
|
UnicodeGuidString = (PCWSTR)PropertyBuffer;
|
|
}
|
|
Err = pSetupGuidFromString(UnicodeGuidString,&ClassGuid);
|
|
if(UnicodeGuidString != (PCWSTR)PropertyBuffer) {
|
|
MyFree(UnicodeGuidString);
|
|
}
|
|
if(Err != NO_ERROR) {
|
|
goto clean0;
|
|
}
|
|
#else
|
|
if((Err = pSetupGuidFromString((PCTSTR)PropertyBuffer, &ClassGuid)) != NO_ERROR) {
|
|
goto clean0;
|
|
}
|
|
#endif
|
|
ClassGuidSpecified = TRUE;
|
|
}
|
|
|
|
if(IsEqualGUID(&(DevInfoElem->ClassGuid),
|
|
(ClassGuidSpecified ? &ClassGuid
|
|
: &GUID_NULL))) {
|
|
//
|
|
// No change--nothing to do.
|
|
//
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// We're changing the class of this device. First, make sure that the
|
|
// set containing this device doesn't have an associated class (otherwise,
|
|
// we'll suddenly have a device whose class doesn't match the set's class).
|
|
//
|
|
if(pDeviceInfoSet->HasClassGuid) {
|
|
Err = ERROR_CLASS_MISMATCH;
|
|
} else {
|
|
Err = InvalidateHelperModules(DeviceInfoSet, DeviceInfoData, 0);
|
|
}
|
|
|
|
if(Err != NO_ERROR) {
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Everything seems to be in order. Before going any further, we need to
|
|
// delete any software keys associated with this device, so we don't leave
|
|
// orphans in the registry when we change the device's class.
|
|
//
|
|
pSetupDeleteDevRegKeys(DevInfoElem->DevInst,
|
|
DICS_FLAG_GLOBAL | DICS_FLAG_CONFIGSPECIFIC,
|
|
(DWORD)-1,
|
|
DIREG_DRV,
|
|
TRUE
|
|
);
|
|
//
|
|
// Now delete the Driver property for this device...
|
|
//
|
|
CM_Set_DevInst_Registry_Property(DevInfoElem->DevInst,
|
|
CM_DRP_DRIVER,
|
|
NULL,
|
|
0,
|
|
0
|
|
);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
if(Ansi) {
|
|
cr = CM_Set_DevInst_Registry_PropertyA(
|
|
DevInfoElem->DevInst,
|
|
CmRegProperty,
|
|
(PVOID)PropertyBuffer,
|
|
PropertyBufferSize,
|
|
0
|
|
);
|
|
} else
|
|
#endif
|
|
cr = CM_Set_DevInst_Registry_Property(DevInfoElem->DevInst,
|
|
CmRegProperty,
|
|
(PVOID)PropertyBuffer,
|
|
PropertyBufferSize,
|
|
0
|
|
);
|
|
if(cr == CR_SUCCESS) {
|
|
//
|
|
// If we were setting the device's ClassGUID property, then we need to
|
|
// update its Class name property as well.
|
|
//
|
|
if(CmRegProperty == CM_DRP_CLASSGUID) {
|
|
|
|
if(ClassGuidSpecified) {
|
|
|
|
if(!SetupDiClassNameFromGuid(&ClassGuid,
|
|
ClassName,
|
|
SIZECHARS(ClassName),
|
|
&ClassNameLength)) {
|
|
//
|
|
// We couldn't retrieve the corresponding class name.
|
|
// Set ClassNameLength to zero so that we reset class
|
|
// name below.
|
|
//
|
|
ClassNameLength = 0;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// Resetting ClassGUID--we want to reset class name also.
|
|
//
|
|
ClassNameLength = 0;
|
|
}
|
|
|
|
CM_Set_DevInst_Registry_Property(DevInfoElem->DevInst,
|
|
CM_DRP_CLASS,
|
|
ClassNameLength ? (PVOID)ClassName : NULL,
|
|
ClassNameLength * sizeof(TCHAR),
|
|
0
|
|
);
|
|
|
|
//
|
|
// Finally, update the device's class GUID, and also update the
|
|
// caller-supplied SP_DEVINFO_DATA structure to reflect the device's
|
|
// new class.
|
|
//
|
|
CopyMemory(&(DevInfoElem->ClassGuid),
|
|
(ClassGuidSpecified ? &ClassGuid : &GUID_NULL),
|
|
sizeof(GUID)
|
|
);
|
|
|
|
CopyMemory(&(DeviceInfoData->ClassGuid),
|
|
(ClassGuidSpecified ? &ClassGuid : &GUID_NULL),
|
|
sizeof(GUID)
|
|
);
|
|
}
|
|
|
|
} else {
|
|
|
|
switch(cr) {
|
|
|
|
case CR_INVALID_DEVINST :
|
|
Err = ERROR_NO_SUCH_DEVINST;
|
|
break;
|
|
|
|
case CR_INVALID_PROPERTY :
|
|
Err = ERROR_INVALID_REG_PROPERTY;
|
|
break;
|
|
|
|
case CR_INVALID_DATA :
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
|
|
default :
|
|
Err = ERROR_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
clean0:
|
|
; // Nothing to do.
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
UnlockDeviceInfoSet(pDeviceInfoSet);
|
|
|
|
SetLastError(Err);
|
|
return (Err == NO_ERROR);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// ANSI version
|
|
//
|
|
BOOL
|
|
WINAPI
|
|
SetupDiSetDeviceRegistryPropertyA(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN OUT PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN DWORD Property,
|
|
IN CONST BYTE* PropertyBuffer, OPTIONAL
|
|
IN DWORD PropertyBufferSize
|
|
)
|
|
{
|
|
BOOL b;
|
|
|
|
b = _SetupDiSetDeviceRegistryProperty(
|
|
DeviceInfoSet,
|
|
DeviceInfoData,
|
|
Property,
|
|
PropertyBuffer,
|
|
PropertyBufferSize,
|
|
TRUE
|
|
);
|
|
|
|
return(b);
|
|
}
|
|
#else
|
|
//
|
|
// Unicode stub
|
|
//
|
|
BOOL
|
|
WINAPI
|
|
SetupDiSetDeviceRegistryPropertyW(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN OUT PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN DWORD Property,
|
|
IN CONST BYTE* PropertyBuffer, OPTIONAL
|
|
IN DWORD PropertyBufferSize
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(DeviceInfoSet);
|
|
UNREFERENCED_PARAMETER(DeviceInfoData);
|
|
UNREFERENCED_PARAMETER(Property);
|
|
UNREFERENCED_PARAMETER(PropertyBuffer);
|
|
UNREFERENCED_PARAMETER(PropertyBufferSize);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupDiSetDeviceRegistryProperty(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN OUT PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN DWORD Property,
|
|
IN CONST BYTE* PropertyBuffer, OPTIONAL
|
|
IN DWORD PropertyBufferSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the specified Plug & Play device registry property.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - Supplies a handle to the device information set containing
|
|
information about the device instance to set a Plug & Play registry
|
|
property for.
|
|
|
|
DeviceInfoData - Supplies a pointer to a SP_DEVINFO_DATA structure indicating
|
|
the device instance to set the Plug & Play registry property for. If the
|
|
ClassGUID property is being set, then this structure will be updated upon
|
|
return to reflect the device's new class.
|
|
|
|
Property - Supplies an ordinal specifying the property to be set. Refer to
|
|
sdk\inc\setupapi.h for a complete listing of values that may be set
|
|
(these values are denoted with 'R/W' in their descriptive comment).
|
|
|
|
PropertyBuffer - Supplies the address of a buffer containing the new data
|
|
for the property. If the property is being cleared, then this pointer
|
|
should be NULL, and PropertyBufferSize must be zero.
|
|
|
|
PropertyBufferSize - Supplies the length, in bytes, of PropertyBuffer. If
|
|
PropertyBuffer isn't specified (i.e., the property is 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:
|
|
|
|
Note that the Class property cannot be set. This is because it is based on
|
|
the corresponding ClassGUID, and is automatically updated when that property
|
|
changes.
|
|
|
|
Also, note that when the ClassGUID property changes, this routine automatically
|
|
cleans up any software keys associated with the device. Otherwise, we would
|
|
be left with orphaned registry keys.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL b;
|
|
|
|
b = _SetupDiSetDeviceRegistryProperty(
|
|
DeviceInfoSet,
|
|
DeviceInfoData,
|
|
Property,
|
|
PropertyBuffer,
|
|
PropertyBufferSize
|
|
#ifdef UNICODE
|
|
,FALSE
|
|
#endif
|
|
);
|
|
|
|
return(b);
|
|
}
|
|
|
|
DWORD
|
|
_SetupDiGetClassRegistryProperty(
|
|
IN CONST GUID *ClassGuid,
|
|
IN DWORD Property,
|
|
OUT PDWORD PropertyRegDataType, OPTIONAL
|
|
OUT PBYTE PropertyBuffer,
|
|
IN DWORD PropertyBufferSize,
|
|
OUT PDWORD RequiredSize, OPTIONAL
|
|
IN PCTSTR MachineName, OPTIONAL
|
|
IN BOOL Ansi
|
|
)
|
|
/*++
|
|
|
|
See SetupDiGetClassRegistryProperty
|
|
|
|
--*/
|
|
{
|
|
DWORD Err;
|
|
CONFIGRET cr;
|
|
ULONG CmRegProperty, PropLength;
|
|
HMACHINE hMachine = NULL;
|
|
Err = NO_ERROR;
|
|
|
|
#ifndef UNICODE
|
|
UNREFERENCED_PARAMETER(Ansi);
|
|
#endif
|
|
|
|
try {
|
|
//
|
|
// if we want to set register for another machine, find that machine
|
|
//
|
|
if(MachineName) {
|
|
|
|
if(CR_SUCCESS != (cr = CM_Connect_Machine(MachineName, &hMachine))) {
|
|
//
|
|
// Make sure machine handle is still invalid, so we won't
|
|
// try to disconnect later.
|
|
//
|
|
hMachine = NULL;
|
|
Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
|
|
leave;
|
|
}
|
|
}
|
|
|
|
if(Property < SPCRP_MAXIMUM_PROPERTY) {
|
|
CmRegProperty = (ULONG)SPCRP_TO_CMCRP(Property);
|
|
} else {
|
|
Err = ERROR_INVALID_REG_PROPERTY;
|
|
leave;
|
|
}
|
|
|
|
PropLength = PropertyBufferSize;
|
|
#ifdef UNICODE
|
|
if(Ansi) {
|
|
cr = CM_Get_Class_Registry_PropertyA(
|
|
(LPGUID)ClassGuid,
|
|
CmRegProperty,
|
|
PropertyRegDataType,
|
|
PropertyBuffer,
|
|
&PropLength,
|
|
0,
|
|
hMachine);
|
|
} else {
|
|
cr = CM_Get_Class_Registry_PropertyW(
|
|
(LPGUID)ClassGuid,
|
|
CmRegProperty,
|
|
PropertyRegDataType,
|
|
PropertyBuffer,
|
|
&PropLength,
|
|
0,
|
|
hMachine);
|
|
}
|
|
#else
|
|
//
|
|
// on ANSI version
|
|
//
|
|
cr = CM_Get_Class_Registry_Property(
|
|
(LPGUID)ClassGuid,
|
|
CmRegProperty,
|
|
PropertyRegDataType,
|
|
PropertyBuffer,
|
|
&PropLength,
|
|
0,
|
|
hMachine);
|
|
#endif
|
|
|
|
if((cr == CR_SUCCESS) || (cr == CR_BUFFER_SMALL)) {
|
|
|
|
if(RequiredSize) {
|
|
*RequiredSize = PropLength;
|
|
}
|
|
}
|
|
|
|
if(cr != CR_SUCCESS) {
|
|
|
|
switch(cr) {
|
|
|
|
case CR_INVALID_DEVINST :
|
|
Err = ERROR_NO_SUCH_DEVINST;
|
|
break;
|
|
|
|
case CR_INVALID_PROPERTY :
|
|
Err = ERROR_INVALID_REG_PROPERTY;
|
|
break;
|
|
|
|
case CR_BUFFER_SMALL :
|
|
Err = ERROR_INSUFFICIENT_BUFFER;
|
|
break;
|
|
|
|
default :
|
|
Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
|
|
}
|
|
}
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (hMachine != NULL) {
|
|
CM_Disconnect_Machine(hMachine);
|
|
}
|
|
|
|
return Err;
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// ANSI version
|
|
//
|
|
WINSETUPAPI
|
|
BOOL
|
|
WINAPI
|
|
SetupDiGetClassRegistryPropertyA(
|
|
IN CONST GUID *ClassGuid,
|
|
IN DWORD Property,
|
|
OUT PDWORD PropertyRegDataType, OPTIONAL
|
|
OUT PBYTE PropertyBuffer,
|
|
IN DWORD PropertyBufferSize,
|
|
OUT PDWORD RequiredSize, OPTIONAL
|
|
IN PCSTR MachineName, OPTIONAL
|
|
IN PVOID Reserved
|
|
)
|
|
/*++
|
|
|
|
See SetupDiGetClassRegistryProperty
|
|
|
|
--*/
|
|
{
|
|
PCWSTR MachineString = NULL;
|
|
DWORD Err = NO_ERROR;
|
|
|
|
if (Reserved != NULL) {
|
|
//
|
|
// make sure caller doesn't pass a value here
|
|
// so we know we can use this at a later date
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
try {
|
|
//
|
|
// convert machine-name to local
|
|
//
|
|
|
|
if (MachineName != NULL) {
|
|
MachineString = pSetupAnsiToUnicode(MachineName);
|
|
if(!MachineString) {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
leave;
|
|
}
|
|
}
|
|
Err = _SetupDiGetClassRegistryProperty(ClassGuid,
|
|
Property,
|
|
PropertyRegDataType,
|
|
PropertyBuffer,
|
|
PropertyBufferSize,
|
|
RequiredSize,
|
|
MachineString,
|
|
TRUE);
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = NO_ERROR;
|
|
}
|
|
if (MachineString != NULL) {
|
|
MyFree(MachineString);
|
|
}
|
|
SetLastError(Err);
|
|
return (BOOL)(Err == NO_ERROR);
|
|
}
|
|
|
|
#else
|
|
//
|
|
// UNICODE stub
|
|
//
|
|
WINSETUPAPI
|
|
BOOL
|
|
WINAPI
|
|
SetupDiGetClassRegistryPropertyW(
|
|
IN CONST GUID *ClassGuid,
|
|
IN DWORD Property,
|
|
OUT PDWORD PropertyRegDataType, OPTIONAL
|
|
OUT PBYTE PropertyBuffer,
|
|
IN DWORD PropertyBufferSize,
|
|
OUT PDWORD RequiredSize, OPTIONAL
|
|
IN PCWSTR MachineName, OPTIONAL
|
|
IN PVOID Reserved
|
|
)
|
|
/*++
|
|
|
|
See SetupDiGetClassRegistryProperty
|
|
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER(ClassGuid);
|
|
UNREFERENCED_PARAMETER(Property);
|
|
UNREFERENCED_PARAMETER(PropertyRegDataType);
|
|
UNREFERENCED_PARAMETER(PropertyBuffer);
|
|
UNREFERENCED_PARAMETER(PropertyBufferSize);
|
|
UNREFERENCED_PARAMETER(RequiredSize);
|
|
UNREFERENCED_PARAMETER(MachineName);
|
|
UNREFERENCED_PARAMETER(Reserved);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(FALSE);
|
|
}
|
|
|
|
#endif // UNICODE
|
|
|
|
WINSETUPAPI
|
|
BOOL
|
|
WINAPI
|
|
SetupDiGetClassRegistryProperty(
|
|
IN CONST GUID *ClassGuid,
|
|
IN DWORD Property,
|
|
OUT PDWORD PropertyRegDataType, OPTIONAL
|
|
OUT PBYTE PropertyBuffer,
|
|
IN DWORD PropertyBufferSize,
|
|
OUT PDWORD RequiredSize, OPTIONAL
|
|
IN PCTSTR MachineName, OPTIONAL
|
|
IN PVOID Reserved
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine gets the specified Plug & Play device class registry property.
|
|
This is just a wrapper around the Config Mgr API
|
|
Typically the properties here can be overridden on a per-device basis,
|
|
however this routine returns the class properties only.
|
|
|
|
Arguments:
|
|
|
|
ClassGuid - Supplies the class Guid that the property is to be got from
|
|
|
|
Property - Supplies an ordinal specifying the property to be set. Refer to
|
|
sdk\inc\setupapi.h for a complete listing of values that may be set
|
|
(these values are denoted with 'R/W' in their descriptive comment).
|
|
|
|
PropertyBuffer - Supplies the address of a buffer containing the new data
|
|
for the property. If the property is being cleared, then this pointer
|
|
should be NULL, and PropertyBufferSize must be zero.
|
|
|
|
PropertyBufferSize - Supplies the length, in bytes, of PropertyBuffer. If
|
|
PropertyBuffer isn't specified (i.e., the property is to be cleared),
|
|
then this value must be zero.
|
|
|
|
MachineName - Allows properties to be set on a remote machine (if Non-NULL)
|
|
|
|
Reserved - should be 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 = NO_ERROR;
|
|
|
|
if (Reserved != NULL) {
|
|
//
|
|
// make sure caller doesn't pass a value here
|
|
// so we know we can use this at a later date
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
Err = _SetupDiGetClassRegistryProperty(ClassGuid,
|
|
Property,
|
|
PropertyRegDataType,
|
|
PropertyBuffer,
|
|
PropertyBufferSize,
|
|
RequiredSize,
|
|
MachineName,
|
|
FALSE);
|
|
|
|
SetLastError(Err);
|
|
return (BOOL)(Err == NO_ERROR);
|
|
}
|
|
|
|
|
|
DWORD
|
|
_SetupDiSetClassRegistryProperty(
|
|
IN CONST GUID *ClassGuid,
|
|
IN DWORD Property,
|
|
IN CONST BYTE* PropertyBuffer, OPTIONAL
|
|
IN DWORD PropertyBufferSize,
|
|
IN PCTSTR MachineName, OPTIONAL
|
|
IN BOOL Ansi
|
|
)
|
|
/*++
|
|
|
|
See SetupDiGetClassRegistryProperty
|
|
|
|
--*/
|
|
{
|
|
DWORD Err;
|
|
CONFIGRET cr;
|
|
ULONG CmRegProperty, PropLength;
|
|
HMACHINE hMachine = NULL;
|
|
|
|
Err = NO_ERROR;
|
|
|
|
try {
|
|
//
|
|
// if we want to set register for another machine, find that machine
|
|
//
|
|
if(MachineName) {
|
|
|
|
if(CR_SUCCESS != (cr = CM_Connect_Machine(MachineName, &hMachine))) {
|
|
//
|
|
// Make sure machine handle is still invalid, so we won't
|
|
// try to disconnect later.
|
|
//
|
|
hMachine = NULL;
|
|
Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
|
|
leave;
|
|
}
|
|
}
|
|
|
|
if(Property < SPCRP_MAXIMUM_PROPERTY) {
|
|
CmRegProperty = (ULONG)SPCRP_TO_CMCRP(Property);
|
|
} else {
|
|
Err = ERROR_INVALID_REG_PROPERTY;
|
|
leave;
|
|
}
|
|
|
|
PropLength = PropertyBufferSize;
|
|
|
|
#ifdef UNICODE
|
|
if(Ansi) {
|
|
cr = CM_Set_Class_Registry_PropertyA(
|
|
(LPGUID)ClassGuid,
|
|
CmRegProperty,
|
|
PropertyBuffer,
|
|
PropLength,
|
|
0,
|
|
hMachine);
|
|
} else {
|
|
cr = CM_Set_Class_Registry_PropertyW(
|
|
(LPGUID)ClassGuid,
|
|
CmRegProperty,
|
|
PropertyBuffer,
|
|
PropLength,
|
|
0,
|
|
hMachine);
|
|
}
|
|
#else
|
|
//
|
|
// on ANSI version
|
|
//
|
|
cr = CM_Set_Class_Registry_Property(
|
|
(LPGUID)ClassGuid,
|
|
CmRegProperty,
|
|
PropertyBuffer,
|
|
PropLength,
|
|
0,
|
|
hMachine);
|
|
#endif
|
|
|
|
if(cr != CR_SUCCESS) {
|
|
|
|
switch(cr) {
|
|
|
|
case CR_INVALID_PROPERTY :
|
|
Err = ERROR_INVALID_REG_PROPERTY;
|
|
break;
|
|
|
|
default :
|
|
Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
|
|
}
|
|
}
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (hMachine != NULL) {
|
|
CM_Disconnect_Machine(hMachine);
|
|
}
|
|
|
|
return Err;
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// ANSI version
|
|
//
|
|
WINSETUPAPI
|
|
BOOL
|
|
WINAPI
|
|
SetupDiSetClassRegistryPropertyA(
|
|
IN CONST GUID *ClassGuid,
|
|
IN DWORD Property,
|
|
IN CONST BYTE* PropertyBuffer, OPTIONAL
|
|
IN DWORD PropertyBufferSize,
|
|
IN PCSTR MachineName, OPTIONAL
|
|
IN PVOID Reserved
|
|
)
|
|
/*++
|
|
|
|
See SetupDiSetClassRegistryProperty
|
|
|
|
--*/
|
|
{
|
|
PCWSTR MachineString = NULL;
|
|
DWORD Err = NO_ERROR;
|
|
|
|
if (Reserved != NULL) {
|
|
//
|
|
// make sure caller doesn't pass a value here
|
|
// so we know we can use this at a later date
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
try {
|
|
//
|
|
// convert machine-name to local
|
|
//
|
|
|
|
if (MachineName != NULL) {
|
|
MachineString = pSetupAnsiToUnicode(MachineName);
|
|
if(!MachineString) {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
leave;
|
|
}
|
|
}
|
|
Err = _SetupDiSetClassRegistryProperty(ClassGuid,
|
|
Property,
|
|
PropertyBuffer,
|
|
PropertyBufferSize,
|
|
MachineString,
|
|
TRUE);
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = NO_ERROR;
|
|
}
|
|
if (MachineString != NULL) {
|
|
MyFree(MachineString);
|
|
}
|
|
SetLastError(Err);
|
|
return (BOOL)(Err == NO_ERROR);
|
|
}
|
|
|
|
#else
|
|
//
|
|
// UNICODE stub
|
|
//
|
|
WINSETUPAPI
|
|
BOOL
|
|
WINAPI
|
|
SetupDiSetClassRegistryPropertyW(
|
|
IN CONST GUID *ClassGuid,
|
|
IN DWORD Property,
|
|
IN CONST BYTE* PropertyBuffer, OPTIONAL
|
|
IN DWORD PropertyBufferSize,
|
|
IN PCWSTR MachineName, OPTIONAL
|
|
IN PVOID Reserved
|
|
)
|
|
/*++
|
|
|
|
See SetupDiSetClassRegistryProperty
|
|
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER(ClassGuid);
|
|
UNREFERENCED_PARAMETER(Property);
|
|
UNREFERENCED_PARAMETER(PropertyBuffer);
|
|
UNREFERENCED_PARAMETER(PropertyBufferSize);
|
|
UNREFERENCED_PARAMETER(MachineName);
|
|
UNREFERENCED_PARAMETER(Reserved);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(FALSE);
|
|
}
|
|
|
|
#endif // UNICODE
|
|
|
|
|
|
WINSETUPAPI
|
|
BOOL
|
|
WINAPI
|
|
SetupDiSetClassRegistryProperty(
|
|
IN CONST GUID *ClassGuid,
|
|
IN DWORD Property,
|
|
IN CONST BYTE* PropertyBuffer, OPTIONAL
|
|
IN DWORD PropertyBufferSize,
|
|
IN PCTSTR MachineName, OPTIONAL
|
|
IN PVOID Reserved
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the specified Plug & Play device class registry property.
|
|
This is just a wrapper around the Config Mgr API
|
|
Typically the properties here can be overridden on a per-device basis
|
|
|
|
Arguments:
|
|
|
|
ClassGuid - Supplies the class Guid for the P&P device, that the property is to
|
|
be set for
|
|
|
|
Property - Supplies an ordinal specifying the property to be retrieved. Refer
|
|
to sdk\inc\setupapi.h for a complete list of properties that may be retrieved.
|
|
|
|
PropertyRegDataType - Optionally, supplies the address of a variable that
|
|
will receive the data type of the property being retrieved. This will
|
|
be one of the standard registry data types (REG_SZ, REG_BINARY, etc.)
|
|
|
|
PropertyBuffer - Supplies the address of a buffer that receives the property
|
|
data.
|
|
|
|
PropertyBufferSize - Supplies the length, in bytes, of PropertyBuffer.
|
|
|
|
RequiredSize - Optionally, supplies the address of a variable that receives
|
|
the number of bytes required to store the requested property in the buffer.
|
|
|
|
MachineName - Allows properties to be got from a remote machine (if Non-NULL)
|
|
|
|
Reserved - should be 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;
|
|
|
|
Err = _SetupDiSetClassRegistryProperty(ClassGuid,
|
|
Property,
|
|
PropertyBuffer,
|
|
PropertyBufferSize,
|
|
MachineName,
|
|
FALSE);
|
|
SetLastError(Err);
|
|
return (BOOL)(Err == NO_ERROR);
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
pSetupFindUniqueKey(
|
|
IN HKEY hkRoot,
|
|
IN LPTSTR SubKey,
|
|
IN ULONG SubKeyLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine finds a unique key under the specified subkey. This key is
|
|
of the form <SubKey>\xxxx, where xxxx is a base-10, 4-digit number.
|
|
|
|
Arguments:
|
|
|
|
hkRoot - Root key under which the specified SubKey is located.
|
|
|
|
SubKey - Name of the subkey, under which a unique key is to be generated.
|
|
|
|
SubKeyLength - Supplies the length of the SubKey string, not including
|
|
terminating NULL.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is TRUE.
|
|
If the function fails, the return value is FALSE.
|
|
|
|
--*/
|
|
{
|
|
INT i;
|
|
HKEY hk;
|
|
|
|
for(i = 0; i <= 9999; i++) {
|
|
wsprintf(&(SubKey[SubKeyLength]), pszUniqueSubKey, i);
|
|
if(RegOpenKeyEx(hkRoot, SubKey, 0, KEY_READ, &hk) != ERROR_SUCCESS) {
|
|
return TRUE;
|
|
}
|
|
RegCloseKey(hk);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupDiDeleteDevRegKey(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN DWORD Scope,
|
|
IN DWORD HwProfile,
|
|
IN DWORD KeyType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine deletes the specified registry key(s) associated with a device
|
|
information element.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - Supplies a handle to the device information set containing
|
|
the device instance to delete key(s) for.
|
|
|
|
DeviceInfoData - Supplies a pointer to a SP_DEVINFO_DATA structure indicating
|
|
the device instance to delete key(s) for.
|
|
|
|
Scope - Specifies the scope of the registry key to be deleted. This determines
|
|
where the key to be deleted is located--the key may be one that is global
|
|
(i.e., constant regardless of current hardware profile) or hardware
|
|
profile-specific. May be a combination of the following values:
|
|
|
|
DICS_FLAG_GLOBAL - Delete the key that stores global configuration information.
|
|
|
|
DICS_FLAG_CONFIGSPECIFIC - Delete the key that stores hardware profile-specific
|
|
information.
|
|
|
|
HwProfile - Specifies the hardware profile to delete a key for, if the Scope parameter
|
|
includes the DICS_FLAG_CONFIGSPECIFIC flag. If this parameter is 0, then the key
|
|
for the current hardware profile should be deleted (i.e., in the Class branch
|
|
under HKEY_CURRENT_CONFIG). If this parameter is 0xFFFFFFFF, then the key for
|
|
_all_ hardware profiles should be deleted.
|
|
|
|
KeyType - Specifies the type of registry storage key to be deleted. May be one of
|
|
the following values:
|
|
|
|
DIREG_DEV - Delete the hardware registry key for the device. This is the key for
|
|
storage of driver-independent configuration information. (This key is in
|
|
the device instance key in the Enum branch.
|
|
|
|
DIREG_DRV - Delete the software (i.e., driver) registry key for the device. (This key
|
|
is located in the class branch.)
|
|
|
|
DIREG_BOTH - Delete both the hardware and software keys for the device.
|
|
|
|
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;
|
|
CONFIGRET cr;
|
|
|
|
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
try {
|
|
//
|
|
// Get a pointer to the element for the specified device
|
|
// instance.
|
|
//
|
|
if(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
|
|
DeviceInfoData,
|
|
NULL)) {
|
|
|
|
Err = pSetupDeleteDevRegKeys(DevInfoElem->DevInst, Scope, HwProfile, KeyType, FALSE);
|
|
|
|
} else {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
UnlockDeviceInfoSet(pDeviceInfoSet);
|
|
|
|
SetLastError(Err);
|
|
return(Err == NO_ERROR);
|
|
}
|
|
|
|
|
|
DWORD
|
|
pSetupDeleteDevRegKeys(
|
|
IN DEVINST DevInst,
|
|
IN DWORD Scope,
|
|
IN DWORD HwProfile,
|
|
IN DWORD KeyType,
|
|
IN BOOL DeleteUserKeys
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the worker routine for SetupDiDeleteDevRegKey. See the discussion of
|
|
that API for details.
|
|
|
|
Return Value:
|
|
|
|
If successful, the return value is NO_ERROR;
|
|
|
|
If failure, the return value is a Win32 error code indicating the cause of failure.
|
|
|
|
Remarks:
|
|
|
|
Even if one of the operations in this routine fails, all operations will be attempted.
|
|
Thus, as many keys as possible will be deleted. The error returned will be the first
|
|
error that was encountered in this case.
|
|
|
|
--*/
|
|
{
|
|
CONFIGRET cr, crTemp;
|
|
DWORD Err;
|
|
|
|
cr = CR_SUCCESS;
|
|
|
|
if(Scope & DICS_FLAG_GLOBAL) {
|
|
|
|
if((KeyType == DIREG_DEV) || (KeyType == DIREG_BOTH)) {
|
|
crTemp = CM_Delete_DevInst_Key(DevInst, 0, CM_REGISTRY_HARDWARE);
|
|
if((cr == CR_SUCCESS) && (crTemp != CR_SUCCESS) && (crTemp != CR_NO_SUCH_REGISTRY_KEY)) {
|
|
cr = crTemp;
|
|
}
|
|
}
|
|
|
|
if((KeyType == DIREG_DRV) || (KeyType == DIREG_BOTH)) {
|
|
crTemp = CM_Delete_DevInst_Key(DevInst, 0, CM_REGISTRY_SOFTWARE);
|
|
if((cr == CR_SUCCESS) && (crTemp != CR_SUCCESS) && (crTemp != CR_NO_SUCH_REGISTRY_KEY)) {
|
|
cr = crTemp;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(Scope & DICS_FLAG_CONFIGSPECIFIC) {
|
|
|
|
if((KeyType == DIREG_DEV) || (KeyType == DIREG_BOTH)) {
|
|
crTemp = CM_Delete_DevInst_Key(DevInst, HwProfile, CM_REGISTRY_HARDWARE | CM_REGISTRY_CONFIG);
|
|
if((cr == CR_SUCCESS) && (crTemp != CR_SUCCESS) && (crTemp != CR_NO_SUCH_REGISTRY_KEY)) {
|
|
cr = crTemp;
|
|
}
|
|
}
|
|
|
|
if((KeyType == DIREG_DRV) || (KeyType == DIREG_BOTH)) {
|
|
crTemp = CM_Delete_DevInst_Key(DevInst, HwProfile, CM_REGISTRY_SOFTWARE | CM_REGISTRY_CONFIG);
|
|
if((cr == CR_SUCCESS) && (crTemp != CR_SUCCESS) && (crTemp != CR_NO_SUCH_REGISTRY_KEY)) {
|
|
cr = crTemp;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(DeleteUserKeys) {
|
|
|
|
if((KeyType == DIREG_DEV) || (KeyType == DIREG_BOTH)) {
|
|
crTemp = CM_Delete_DevInst_Key(DevInst, 0, CM_REGISTRY_HARDWARE | CM_REGISTRY_USER);
|
|
if((cr == CR_SUCCESS) && (crTemp != CR_SUCCESS) && (crTemp != CR_NO_SUCH_REGISTRY_KEY)) {
|
|
cr = crTemp;
|
|
}
|
|
}
|
|
|
|
if((KeyType == DIREG_DRV) || (KeyType == DIREG_BOTH)) {
|
|
crTemp = CM_Delete_DevInst_Key(DevInst, 0, CM_REGISTRY_SOFTWARE | CM_REGISTRY_USER);
|
|
if((cr == CR_SUCCESS) && (crTemp != CR_SUCCESS) && (crTemp != CR_NO_SUCH_REGISTRY_KEY)) {
|
|
cr = crTemp;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now translate the ConfigMgr return code into a Win32 one.
|
|
//
|
|
switch(cr) {
|
|
|
|
case CR_SUCCESS :
|
|
Err = NO_ERROR;
|
|
break;
|
|
|
|
case CR_REGISTRY_ERROR :
|
|
Err = ERROR_ACCESS_DENIED;
|
|
break;
|
|
|
|
case CR_INVALID_DEVINST :
|
|
Err = ERROR_NO_SUCH_DEVINST;
|
|
break;
|
|
|
|
default :
|
|
Err = ERROR_INVALID_DATA;
|
|
}
|
|
|
|
return Err;
|
|
}
|
|
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// ANSI version
|
|
//
|
|
HKEY
|
|
WINAPI
|
|
SetupDiCreateDeviceInterfaceRegKeyA(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
|
|
IN DWORD Reserved,
|
|
IN REGSAM samDesired,
|
|
IN HINF InfHandle, OPTIONAL
|
|
IN PCSTR InfSectionName OPTIONAL
|
|
)
|
|
{
|
|
DWORD rc;
|
|
PWSTR name;
|
|
HKEY h;
|
|
|
|
if(InfSectionName) {
|
|
rc = pSetupCaptureAndConvertAnsiArg(InfSectionName, &name);
|
|
if(rc != NO_ERROR) {
|
|
SetLastError(rc);
|
|
return(INVALID_HANDLE_VALUE);
|
|
}
|
|
} else {
|
|
name = NULL;
|
|
}
|
|
|
|
h = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet,
|
|
DeviceInterfaceData,
|
|
Reserved,
|
|
samDesired,
|
|
InfHandle,
|
|
name
|
|
);
|
|
|
|
rc = GetLastError();
|
|
|
|
if(name) {
|
|
MyFree(name);
|
|
}
|
|
SetLastError(rc);
|
|
return(h);
|
|
}
|
|
#else
|
|
//
|
|
// Unicode stub
|
|
//
|
|
HKEY
|
|
WINAPI
|
|
SetupDiCreateDeviceInterfaceRegKeyW(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
|
|
IN DWORD Reserved,
|
|
IN REGSAM samDesired,
|
|
IN HINF InfHandle, OPTIONAL
|
|
IN PCWSTR InfSectionName OPTIONAL
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(DeviceInfoSet);
|
|
UNREFERENCED_PARAMETER(DeviceInterfaceData);
|
|
UNREFERENCED_PARAMETER(Reserved);
|
|
UNREFERENCED_PARAMETER(samDesired);
|
|
UNREFERENCED_PARAMETER(InfHandle);
|
|
UNREFERENCED_PARAMETER(InfSectionName);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(INVALID_HANDLE_VALUE);
|
|
}
|
|
#endif
|
|
|
|
HKEY
|
|
WINAPI
|
|
SetupDiCreateDeviceInterfaceRegKey(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
|
|
IN DWORD Reserved,
|
|
IN REGSAM samDesired,
|
|
IN HINF InfHandle, OPTIONAL
|
|
IN PCTSTR InfSectionName OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a registry storage key for a particular device interface,
|
|
and returns a handle to the key.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - Supplies a handle to the device information set containing
|
|
the device interface for whom a registry key is to be created.
|
|
|
|
DeviceInterfaceData - Supplies a pointer to a device interface data structure
|
|
indicating which device interface a key is to be created for.
|
|
|
|
Reserved - Reserved for future use, must be set to 0.
|
|
|
|
samDesired - Specifies the registry access desired for the resulting key handle.
|
|
|
|
InfHandle - Optionally, supplies the handle of an opened INF file containing an
|
|
install section to be executed for the newly-created key. If this parameter is
|
|
specified, then InfSectionName must be specified as well.
|
|
|
|
InfSectionName - Optionally, supplies the name of an install section in the INF
|
|
file specified by InfHandle. This section will be executed for the newly
|
|
created key. If this parameter is specified, then InfHandle must be specified
|
|
as well.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is a handle to a newly-created
|
|
registry key where private configuration data pertaining to this device
|
|
interface may be stored/retrieved.
|
|
|
|
If the function fails, the return value is INVALID_HANDLE_VALUE. To get
|
|
extended error information, call GetLastError.
|
|
|
|
Remarks:
|
|
|
|
The handle returned from this routine must be closed by calling RegCloseKey.
|
|
|
|
During GUI-mode setup on Windows NT, quiet-install behavior is always
|
|
employed in the absence of a user-supplied file queue, regardless of
|
|
whether the device information element has the DI_QUIETINSTALL flag set.
|
|
|
|
--*/
|
|
|
|
{
|
|
HKEY hk, hSubKey;
|
|
PDEVICE_INFO_SET pDeviceInfoSet;
|
|
DWORD Err;
|
|
PDEVINFO_ELEM DevInfoElem;
|
|
PSP_FILE_CALLBACK MsgHandler;
|
|
PVOID MsgHandlerContext;
|
|
BOOL MsgHandlerIsNativeCharWidth;
|
|
BOOL NoProgressUI;
|
|
|
|
if(Reserved != 0) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
Err = NO_ERROR;
|
|
hk = hSubKey = INVALID_HANDLE_VALUE;
|
|
|
|
try {
|
|
//
|
|
// Get a pointer to the device information element for the specified
|
|
// interface device.
|
|
//
|
|
if(!(DevInfoElem = FindDevInfoElemForInterfaceDevice(pDeviceInfoSet, DeviceInterfaceData))) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
goto clean0;
|
|
}
|
|
|
|
hk = SetupDiOpenClassRegKeyEx(&(DeviceInterfaceData->InterfaceClassGuid),
|
|
KEY_READ,
|
|
DIOCR_INTERFACE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if(hk == INVALID_HANDLE_VALUE) {
|
|
//
|
|
// We couldn't open the interface class subkey--this should never happen.
|
|
//
|
|
Err = GetLastError();
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Now, create the client-accessible registry storage key for this interface device.
|
|
//
|
|
Err = pSetupOpenOrCreateInterfaceDeviceRegKey(hk,
|
|
pDeviceInfoSet,
|
|
DeviceInterfaceData,
|
|
TRUE,
|
|
samDesired,
|
|
&hSubKey
|
|
);
|
|
|
|
RegCloseKey(hk);
|
|
hk = INVALID_HANDLE_VALUE;
|
|
|
|
if(Err != NO_ERROR) {
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// We successfully created the storage key, now run an INF install
|
|
// section against it (if specified).
|
|
//
|
|
if(InfHandle && (InfHandle != INVALID_HANDLE_VALUE) && InfSectionName) {
|
|
//
|
|
// If a copy msg handler and context haven't been specified, then
|
|
// use the default one.
|
|
//
|
|
if(DevInfoElem->InstallParamBlock.InstallMsgHandler) {
|
|
MsgHandler = DevInfoElem->InstallParamBlock.InstallMsgHandler;
|
|
MsgHandlerContext = DevInfoElem->InstallParamBlock.InstallMsgHandlerContext;
|
|
MsgHandlerIsNativeCharWidth = DevInfoElem->InstallParamBlock.InstallMsgHandlerIsNativeCharWidth;
|
|
} else {
|
|
|
|
NoProgressUI = (GuiSetupInProgress || (DevInfoElem->InstallParamBlock.Flags & DI_QUIETINSTALL));
|
|
|
|
if(!(MsgHandlerContext = SetupInitDefaultQueueCallbackEx(
|
|
DevInfoElem->InstallParamBlock.hwndParent,
|
|
(NoProgressUI ? INVALID_HANDLE_VALUE : NULL),
|
|
0,
|
|
0,
|
|
NULL))) {
|
|
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto clean0;
|
|
}
|
|
MsgHandler = SetupDefaultQueueCallback;
|
|
MsgHandlerIsNativeCharWidth = TRUE;
|
|
}
|
|
|
|
if(!_SetupInstallFromInfSection(DevInfoElem->InstallParamBlock.hwndParent,
|
|
InfHandle,
|
|
InfSectionName,
|
|
SPINST_ALL ^ SPINST_LOGCONFIG,
|
|
hSubKey,
|
|
NULL,
|
|
0,
|
|
MsgHandler,
|
|
MsgHandlerContext,
|
|
INVALID_HANDLE_VALUE,
|
|
NULL,
|
|
MsgHandlerIsNativeCharWidth,
|
|
NULL
|
|
)) {
|
|
Err = GetLastError();
|
|
}
|
|
|
|
//
|
|
// If we used the default msg handler, release the default context
|
|
// now.
|
|
//
|
|
if(!DevInfoElem->InstallParamBlock.InstallMsgHandler) {
|
|
SetupTermDefaultQueueCallback(MsgHandlerContext);
|
|
}
|
|
}
|
|
|
|
clean0:
|
|
; // Nothing to do.
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
|
|
if(hk != INVALID_HANDLE_VALUE) {
|
|
RegCloseKey(hk);
|
|
}
|
|
|
|
//
|
|
// Access the following registry handle so that the compiler will
|
|
// respect statement ordering w.r.t. its assignment.
|
|
//
|
|
hSubKey = hSubKey;
|
|
}
|
|
|
|
UnlockDeviceInfoSet(pDeviceInfoSet);
|
|
|
|
if(Err == NO_ERROR) {
|
|
return hSubKey;
|
|
} else {
|
|
if(hSubKey != INVALID_HANDLE_VALUE) {
|
|
RegCloseKey(hSubKey);
|
|
}
|
|
SetLastError(Err);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
|
|
HKEY
|
|
WINAPI
|
|
SetupDiOpenDeviceInterfaceRegKey(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
|
|
IN DWORD Reserved,
|
|
IN REGSAM samDesired
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens a registry storage key for a particular device interface,
|
|
and returns a handle to the key.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - Supplies a handle to the device information set containing
|
|
the device interface for whom a registry key is to be opened.
|
|
|
|
InterfaceDeviceData - Supplies a pointer to a device interface data structure
|
|
indicating which device interface a key is to be opened for.
|
|
|
|
Reserved - Reserved for future use, must be set to 0.
|
|
|
|
samDesired - Specifies the access you require for this key.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is a handle to an opened registry
|
|
key where private configuration data pertaining to this device interface may be
|
|
stored/retrieved.
|
|
|
|
If the function fails, the return value is INVALID_HANDLE_VALUE. To get
|
|
extended error information, call GetLastError.
|
|
|
|
Remarks:
|
|
|
|
The handle returned from this routine must be closed by calling RegCloseKey.
|
|
|
|
--*/
|
|
|
|
{
|
|
HKEY hk, hSubKey;
|
|
PDEVICE_INFO_SET pDeviceInfoSet;
|
|
DWORD Err;
|
|
PDEVINFO_ELEM DevInfoElem;
|
|
|
|
if(Reserved != 0) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
Err = NO_ERROR;
|
|
hk = INVALID_HANDLE_VALUE;
|
|
|
|
try {
|
|
//
|
|
// Get a pointer to the device information element for the specified
|
|
// interface device.
|
|
//
|
|
if(!(DevInfoElem = FindDevInfoElemForInterfaceDevice(pDeviceInfoSet, DeviceInterfaceData))) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
goto clean0;
|
|
}
|
|
|
|
hk = SetupDiOpenClassRegKeyEx(&(DeviceInterfaceData->InterfaceClassGuid),
|
|
KEY_READ,
|
|
DIOCR_INTERFACE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if(hk == INVALID_HANDLE_VALUE) {
|
|
//
|
|
// We couldn't open the interface class subkey--this should never happen.
|
|
//
|
|
Err = GetLastError();
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Now, open up the client-accessible registry storage key for this interface device.
|
|
//
|
|
Err = pSetupOpenOrCreateInterfaceDeviceRegKey(hk,
|
|
pDeviceInfoSet,
|
|
DeviceInterfaceData,
|
|
FALSE,
|
|
samDesired,
|
|
&hSubKey
|
|
);
|
|
|
|
clean0:
|
|
; // nothing to do.
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
//
|
|
// Access the following registry handle so that the compiler will respect
|
|
// statement ordering w.r.t. its assignment.
|
|
//
|
|
hk = hk;
|
|
}
|
|
|
|
UnlockDeviceInfoSet(pDeviceInfoSet);
|
|
|
|
if(hk != INVALID_HANDLE_VALUE) {
|
|
RegCloseKey(hk);
|
|
}
|
|
|
|
SetLastError(Err);
|
|
return (Err == NO_ERROR) ? hSubKey : INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupDiDeleteDeviceInterfaceRegKey(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
|
|
IN DWORD Reserved
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine deletes the registry key associated with a device interface.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - Supplies a handle to the device information set containing
|
|
the device interface whose registry key is to be deleted.
|
|
|
|
DeviceInterfaceData - Supplies a pointer to a device interface data structure
|
|
indicating which device interface is to have its registry key deleted.
|
|
|
|
Reserved - Reserved for future use, must be set to 0.
|
|
|
|
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.
|
|
|
|
--*/
|
|
{
|
|
HKEY hk;
|
|
PDEVICE_INFO_SET pDeviceInfoSet;
|
|
DWORD Err;
|
|
PDEVINFO_ELEM DevInfoElem;
|
|
|
|
if(Reserved != 0) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
hk = INVALID_HANDLE_VALUE;
|
|
|
|
try {
|
|
//
|
|
// Get a pointer to the device information element for the specified
|
|
// interface device.
|
|
//
|
|
if(!(DevInfoElem = FindDevInfoElemForInterfaceDevice(pDeviceInfoSet, DeviceInterfaceData))) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
goto clean0;
|
|
}
|
|
|
|
hk = SetupDiOpenClassRegKeyEx(&(DeviceInterfaceData->InterfaceClassGuid),
|
|
KEY_READ,
|
|
DIOCR_INTERFACE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if(hk == INVALID_HANDLE_VALUE) {
|
|
//
|
|
// We couldn't open the interface class subkey--this should never happen.
|
|
//
|
|
Err = GetLastError();
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Now delete the interface device key.
|
|
//
|
|
Err = pSetupDeleteInterfaceDeviceKey(hk, pDeviceInfoSet, DeviceInterfaceData);
|
|
|
|
clean0:
|
|
; // nothing to do.
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
//
|
|
// Access the following registry handle so the compiler will respect statement
|
|
// ordering w.r.t. its assignment.
|
|
//
|
|
hk = hk;
|
|
}
|
|
|
|
UnlockDeviceInfoSet(pDeviceInfoSet);
|
|
|
|
if(hk != INVALID_HANDLE_VALUE) {
|
|
RegCloseKey(hk);
|
|
}
|
|
|
|
SetLastError(Err);
|
|
return(Err == NO_ERROR);
|
|
}
|
|
|
|
|
|
DWORD
|
|
pSetupOpenOrCreateInterfaceDeviceRegKey(
|
|
IN HKEY hInterfaceClassKey,
|
|
IN PDEVICE_INFO_SET DeviceInfoSet,
|
|
IN PSP_DEVICE_INTERFACE_DATA InterfaceDeviceData,
|
|
IN BOOL Create,
|
|
IN REGSAM samDesired,
|
|
OUT PHKEY hInterfaceDeviceKey
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates or opens a registry storage key for the specified
|
|
interface device, and returns a handle to the opened key.
|
|
|
|
Arguments:
|
|
|
|
hInterfaceClassKey - Supplies a handle to the opened driver key, underneath which
|
|
resides the interface device key to be deleted.
|
|
|
|
DeviceInfoSet - Supplies a pointer to the device information set containing
|
|
the interface device for which a registry storage key is to be created/opened.
|
|
|
|
InterfaceDeviceData - Supplies a pointer to an interface device data structure
|
|
indicating which interface device a key is to be opened/created for.
|
|
|
|
Create - Specifies whether the key should be created if doesn't already exist.
|
|
|
|
samDesired - Specifies the access you require for this key.
|
|
|
|
hInterfaceDeviceKey - Supplies the address of a variable that receives a handle
|
|
to the requested registry key. (This variable will only be written to if the
|
|
handle is successfully opened.)
|
|
|
|
Return Value:
|
|
|
|
If the function is successful, the return value is NO_ERROR, otherwise, it is
|
|
the ERROR_* code indicating the error that occurred.
|
|
|
|
Remarks:
|
|
|
|
The algorithm used to form the storage keys for an interface device must be kept
|
|
in sync with the kernel mode implementation of IoOpenDeviceClassRegistryKey.
|
|
|
|
--*/
|
|
{
|
|
DWORD Err;
|
|
PINTERFACE_DEVICE_NODE InterfaceDeviceNode;
|
|
LPGUID ClassGuid;
|
|
HKEY hInterfaceDeviceRootKey, hSubKey;
|
|
DWORD Disposition;
|
|
PCTSTR DevicePath;
|
|
|
|
Err = NO_ERROR;
|
|
hInterfaceDeviceRootKey = INVALID_HANDLE_VALUE;
|
|
try {
|
|
//
|
|
// Get the interface device node, and verify that its class matches what the
|
|
// caller passed us.
|
|
//
|
|
InterfaceDeviceNode = (PINTERFACE_DEVICE_NODE)(InterfaceDeviceData->Reserved);
|
|
ClassGuid = &(DeviceInfoSet->GuidTable[InterfaceDeviceNode->GuidIndex]);
|
|
|
|
if(!IsEqualGUID(ClassGuid, &(InterfaceDeviceData->InterfaceClassGuid))) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Verify that this interface device hasn't been removed.
|
|
//
|
|
if(InterfaceDeviceNode->Flags & SPINT_REMOVED) {
|
|
Err = ERROR_DEVICE_INTERFACE_REMOVED;
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// OK, now open the interface device's root storage key.
|
|
//
|
|
DevicePath = pStringTableStringFromId(DeviceInfoSet->StringTable,
|
|
InterfaceDeviceNode->SymLinkName
|
|
);
|
|
|
|
if(ERROR_SUCCESS != OpenDeviceInterfaceSubKey(hInterfaceClassKey,
|
|
DevicePath,
|
|
KEY_READ,
|
|
&hInterfaceDeviceRootKey,
|
|
NULL,
|
|
NULL)) {
|
|
//
|
|
// Make sure hInterfaceDeviceRootKey is still INVALID_HANDLE_VALUE, so we
|
|
// won't try to close it later.
|
|
//
|
|
hInterfaceDeviceRootKey = INVALID_HANDLE_VALUE;
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
goto clean0;
|
|
}
|
|
|
|
if(Create) {
|
|
|
|
Err = RegCreateKeyEx(hInterfaceDeviceRootKey,
|
|
pszDeviceParameters,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
samDesired,
|
|
NULL,
|
|
&hSubKey,
|
|
&Disposition
|
|
);
|
|
} else {
|
|
|
|
Err = RegOpenKeyEx(hInterfaceDeviceRootKey,
|
|
pszDeviceParameters,
|
|
0,
|
|
samDesired,
|
|
&hSubKey
|
|
);
|
|
}
|
|
|
|
clean0:
|
|
; // nothing to do.
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
//
|
|
// Access the following variable so the compiler will respect statement ordering
|
|
// w.r.t. assignment.
|
|
//
|
|
hInterfaceDeviceRootKey = hInterfaceDeviceRootKey;
|
|
}
|
|
|
|
if(hInterfaceDeviceRootKey != INVALID_HANDLE_VALUE) {
|
|
RegCloseKey(hInterfaceDeviceRootKey);
|
|
}
|
|
|
|
if(Err == NO_ERROR) {
|
|
*hInterfaceDeviceKey = hSubKey;
|
|
}
|
|
|
|
return Err;
|
|
}
|
|
|
|
|
|
DWORD
|
|
pSetupDeleteInterfaceDeviceKey(
|
|
IN HKEY hInterfaceClassKey,
|
|
IN PDEVICE_INFO_SET DeviceInfoSet,
|
|
IN PSP_DEVICE_INTERFACE_DATA InterfaceDeviceData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine deletes an interface device registry key (recursively deleting
|
|
any subkeys as well).
|
|
|
|
Arguments:
|
|
|
|
hInterfaceClassKey - Supplies the handle to the registry key underneath which the 2-level
|
|
interface class hierarchy exists.
|
|
|
|
DeviceInfoSet - Supplies a pointer to the device information set containing
|
|
the interface device whose registry key is to be deleted.
|
|
|
|
InterfaceDeviceData - Supplies a pointer to an interface device data structure
|
|
indicating which interface device is to have its registry key deleted.
|
|
|
|
Return Value:
|
|
|
|
If successful, the return value is NO_ERROR;
|
|
|
|
If failure, the return value is a Win32 error code indicating the cause of failure.
|
|
|
|
--*/
|
|
{
|
|
DWORD Err;
|
|
PINTERFACE_DEVICE_NODE InterfaceDeviceNode;
|
|
LPGUID ClassGuid;
|
|
HKEY hInterfaceDeviceRootKey;
|
|
PCTSTR DevicePath;
|
|
|
|
Err = NO_ERROR;
|
|
hInterfaceDeviceRootKey = INVALID_HANDLE_VALUE;
|
|
|
|
try {
|
|
//
|
|
// Get the interface device node, and verify that its class matches what the
|
|
// caller passed us.
|
|
//
|
|
InterfaceDeviceNode = (PINTERFACE_DEVICE_NODE)(InterfaceDeviceData->Reserved);
|
|
ClassGuid = &(DeviceInfoSet->GuidTable[InterfaceDeviceNode->GuidIndex]);
|
|
|
|
if(!IsEqualGUID(ClassGuid, &(InterfaceDeviceData->InterfaceClassGuid))) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Verify that this interface device hasn't been removed.
|
|
//
|
|
if(InterfaceDeviceNode->Flags & SPINT_REMOVED) {
|
|
Err = ERROR_DEVICE_INTERFACE_REMOVED;
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// OK, now open the interface device's root storage key.
|
|
//
|
|
DevicePath = pStringTableStringFromId(DeviceInfoSet->StringTable,
|
|
InterfaceDeviceNode->SymLinkName
|
|
);
|
|
|
|
if(ERROR_SUCCESS != OpenDeviceInterfaceSubKey(hInterfaceClassKey,
|
|
DevicePath,
|
|
KEY_READ,
|
|
&hInterfaceDeviceRootKey,
|
|
NULL,
|
|
NULL)) {
|
|
//
|
|
// Make sure hInterfaceDeviceRootKey is still INVALID_HANDLE_VALUE, so we
|
|
// won't try to close it later.
|
|
//
|
|
hInterfaceDeviceRootKey = INVALID_HANDLE_VALUE;
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
goto clean0;
|
|
}
|
|
|
|
Err = pSetupRegistryDelnode(hInterfaceDeviceRootKey, pszDeviceParameters);
|
|
|
|
clean0:
|
|
; // nothing to do.
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
//
|
|
// Access the following variable so the compiler will respect statement ordering
|
|
// w.r.t. assignment.
|
|
//
|
|
hInterfaceDeviceRootKey = hInterfaceDeviceRootKey;
|
|
}
|
|
|
|
if(hInterfaceDeviceRootKey != INVALID_HANDLE_VALUE) {
|
|
RegCloseKey(hInterfaceDeviceRootKey);
|
|
}
|
|
|
|
return Err;
|
|
}
|
|
|
|
|
|
#ifdef UNICODE
|
|
BOOL
|
|
WINAPI
|
|
_SetupDiGetCustomDeviceProperty(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN CONST VOID *CustomPropertyName, // ANSI or Unicode, depending on "Ansi" param.
|
|
IN DWORD Flags,
|
|
OUT PDWORD PropertyRegDataType, OPTIONAL
|
|
OUT PBYTE PropertyBuffer,
|
|
IN DWORD PropertyBufferSize,
|
|
OUT PDWORD RequiredSize, OPTIONAL
|
|
IN BOOL Ansi
|
|
)
|
|
{
|
|
PDEVICE_INFO_SET pDeviceInfoSet;
|
|
DWORD Err;
|
|
PDEVINFO_ELEM DevInfoElem;
|
|
CONFIGRET cr;
|
|
ULONG PropLength, CmFlags;
|
|
|
|
//
|
|
// At present, there's only one valid flag...
|
|
//
|
|
if(Flags & ~DICUSTOMDEVPROP_MERGE_MULTISZ) {
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
return FALSE;
|
|
}
|
|
|
|
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
Err = NO_ERROR;
|
|
|
|
try {
|
|
//
|
|
// Get a pointer to the element for the specified device
|
|
// instance.
|
|
//
|
|
if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
|
|
DeviceInfoData,
|
|
NULL))) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
goto clean0;
|
|
}
|
|
|
|
if(Flags & DICUSTOMDEVPROP_MERGE_MULTISZ) {
|
|
CmFlags = CM_CUSTOMDEVPROP_MERGE_MULTISZ;
|
|
} else {
|
|
CmFlags = 0;
|
|
}
|
|
|
|
PropLength = PropertyBufferSize;
|
|
if(Ansi) {
|
|
cr = CM_Get_DevInst_Custom_Property_ExA(
|
|
DevInfoElem->DevInst,
|
|
CustomPropertyName,
|
|
PropertyRegDataType,
|
|
PropertyBuffer,
|
|
&PropLength,
|
|
CmFlags,
|
|
pDeviceInfoSet->hMachine
|
|
);
|
|
} else {
|
|
cr = CM_Get_DevInst_Custom_Property_ExW(
|
|
DevInfoElem->DevInst,
|
|
CustomPropertyName,
|
|
PropertyRegDataType,
|
|
PropertyBuffer,
|
|
&PropLength,
|
|
CmFlags,
|
|
pDeviceInfoSet->hMachine
|
|
);
|
|
}
|
|
|
|
if((cr == CR_SUCCESS) || (cr == CR_BUFFER_SMALL)) {
|
|
|
|
if(RequiredSize) {
|
|
*RequiredSize = PropLength;
|
|
}
|
|
}
|
|
|
|
if(cr != CR_SUCCESS) {
|
|
|
|
switch(cr) {
|
|
|
|
case CR_INVALID_DEVINST :
|
|
Err = ERROR_NO_SUCH_DEVINST;
|
|
break;
|
|
|
|
case CR_BUFFER_SMALL :
|
|
Err = ERROR_INSUFFICIENT_BUFFER;
|
|
break;
|
|
|
|
case CR_NO_SUCH_VALUE :
|
|
Err = ERROR_NOT_FOUND;
|
|
break;
|
|
|
|
default :
|
|
Err = ERROR_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
clean0:
|
|
; // Nothing to do.
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
UnlockDeviceInfoSet(pDeviceInfoSet);
|
|
|
|
SetLastError(Err);
|
|
return (Err == NO_ERROR);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// Unicode version
|
|
//
|
|
BOOL
|
|
WINAPI
|
|
SetupDiGetCustomDevicePropertyW(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN PCWSTR CustomPropertyName,
|
|
IN DWORD Flags,
|
|
OUT PDWORD PropertyRegDataType, OPTIONAL
|
|
OUT PBYTE PropertyBuffer,
|
|
IN DWORD PropertyBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine retrieves the data for the specified property, either from the
|
|
device information element's hardware key, or from the most-specific
|
|
per-hardware-id storage key containing that property.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet -- Supplies a handle to the device information set containing
|
|
information about the device instance to retrieve a Plug & Play
|
|
registry property for.
|
|
|
|
DeviceInfoData -- Supplies a pointer to a SP_DEVINFO_DATA structure
|
|
indicating the device instance to retrieve the Plug & Play registry
|
|
property for
|
|
|
|
CustomPropertyName - Supplies the name of the property to be retrieved.
|
|
|
|
Flags - Supplies flags controlling how the property data is to be
|
|
retrieved. May be a combination of the following values:
|
|
|
|
DICUSTOMDEVPROP_MERGE_MULTISZ : Merge the devnode-specific REG_SZ or
|
|
REG_MULTI_SZ property (if present) with
|
|
the per-hardware-id REG_SZ or
|
|
REG_MULTI_SZ property (if present).
|
|
The resultant data will always be a
|
|
multi-sz list.
|
|
|
|
PropertyRegDataType -- Optionally, supplies the address of a variable that
|
|
will receive the data type of the property being retrieved. This will
|
|
be one of the standard registry data types (REG_SZ, REG_BINARY, etc.)
|
|
|
|
PropertyBuffer -- Supplies the address of a buffer that receives the
|
|
property data.
|
|
|
|
PropertyBufferSize -- Supplies the length, in bytes, of PropertyBuffer.
|
|
|
|
RequiredSize -- Optionally, supplies the address of a variable that
|
|
receives the number of bytes required to store the requested property
|
|
in the buffer.
|
|
|
|
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. If the supplied buffer was not large
|
|
enough to hold the requested property, the error will be
|
|
ERROR_INSUFFICIENT_BUFFER and RequiredSize will specify how large the
|
|
buffer needs to be.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL b;
|
|
|
|
b = _SetupDiGetCustomDeviceProperty(
|
|
DeviceInfoSet,
|
|
DeviceInfoData,
|
|
CustomPropertyName,
|
|
Flags,
|
|
PropertyRegDataType,
|
|
PropertyBuffer,
|
|
PropertyBufferSize,
|
|
RequiredSize,
|
|
FALSE // want Unicode results
|
|
);
|
|
|
|
return(b);
|
|
}
|
|
|
|
//
|
|
// ANSI version
|
|
//
|
|
BOOL
|
|
WINAPI
|
|
SetupDiGetCustomDevicePropertyA(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN PCSTR CustomPropertyName,
|
|
IN DWORD Flags,
|
|
OUT PDWORD PropertyRegDataType, OPTIONAL
|
|
OUT PBYTE PropertyBuffer,
|
|
IN DWORD PropertyBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
(See SetupDiGetCustomDevicePropertyW)
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL b;
|
|
|
|
b = _SetupDiGetCustomDeviceProperty(
|
|
DeviceInfoSet,
|
|
DeviceInfoData,
|
|
CustomPropertyName,
|
|
Flags,
|
|
PropertyRegDataType,
|
|
PropertyBuffer,
|
|
PropertyBufferSize,
|
|
RequiredSize,
|
|
TRUE // want ANSI results
|
|
);
|
|
|
|
return(b);
|
|
}
|
|
|
|
|
|
#else // Both Unicode and ANSI stubs are unimplemented in ANSI setupapi...
|
|
//
|
|
// Unicode stub
|
|
//
|
|
BOOL
|
|
WINAPI
|
|
SetupDiGetCustomDevicePropertyW(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN PCWSTR CustomPropertyName,
|
|
IN DWORD Flags,
|
|
OUT PDWORD PropertyRegDataType, OPTIONAL
|
|
OUT PBYTE PropertyBuffer,
|
|
IN DWORD PropertyBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(DeviceInfoSet);
|
|
UNREFERENCED_PARAMETER(DeviceInfoData);
|
|
UNREFERENCED_PARAMETER(CustomPropertyName);
|
|
UNREFERENCED_PARAMETER(Flags);
|
|
UNREFERENCED_PARAMETER(PropertyRegDataType);
|
|
UNREFERENCED_PARAMETER(PropertyBuffer);
|
|
UNREFERENCED_PARAMETER(PropertyBufferSize);
|
|
UNREFERENCED_PARAMETER(RequiredSize);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// ANSI stub
|
|
//
|
|
BOOL
|
|
WINAPI
|
|
SetupDiGetCustomDevicePropertyA(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN PCSTR CustomPropertyName,
|
|
IN DWORD Flags,
|
|
OUT PDWORD PropertyRegDataType, OPTIONAL
|
|
OUT PBYTE PropertyBuffer,
|
|
IN DWORD PropertyBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(DeviceInfoSet);
|
|
UNREFERENCED_PARAMETER(DeviceInfoData);
|
|
UNREFERENCED_PARAMETER(CustomPropertyName);
|
|
UNREFERENCED_PARAMETER(Flags);
|
|
UNREFERENCED_PARAMETER(PropertyRegDataType);
|
|
UNREFERENCED_PARAMETER(PropertyBuffer);
|
|
UNREFERENCED_PARAMETER(PropertyBufferSize);
|
|
UNREFERENCED_PARAMETER(RequiredSize);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|