mirror of https://github.com/lianthony/NT4.0
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.
2597 lines
85 KiB
2597 lines
85 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
devinfo.c
|
|
|
|
Abstract:
|
|
|
|
Device Installer routines dealing with device information sets
|
|
|
|
Author:
|
|
|
|
Lonny McMichael (lonnym) 10-May-1995
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "setupntp.h"
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// Define the context structure used by the default device comparison
|
|
// callback (used by SetupDiRegisterDeviceInfo).
|
|
//
|
|
typedef struct _DEFAULT_DEVCMP_CONTEXT {
|
|
|
|
PCS_RESOURCE NewDevCsResource;
|
|
PCS_RESOURCE CurDevCsResource;
|
|
ULONG CsResourceSize; // applies to both buffers.
|
|
|
|
} DEFAULT_DEVCMP_CONTEXT, *PDEFAULT_DEVCMP_CONTEXT;
|
|
|
|
|
|
//
|
|
// Private routine prototypes.
|
|
//
|
|
DWORD
|
|
pSetupOpenAndAddNewDevInfoElem(
|
|
IN PDEVICE_INFO_SET DeviceInfoSet,
|
|
IN PCTSTR DeviceInstanceId,
|
|
IN BOOL AllowPhantom,
|
|
IN LPGUID ClassGuid, OPTIONAL
|
|
IN HWND hwndParent, OPTIONAL
|
|
OUT PDEVINFO_ELEM *DevInfoElem,
|
|
IN BOOL CheckIfAlreadyThere,
|
|
OUT PBOOL AlreadyPresent, OPTIONAL
|
|
IN ULONG CmLocateFlags
|
|
);
|
|
|
|
DWORD
|
|
pSetupAddNewDeviceInfoElement(
|
|
IN PDEVICE_INFO_SET DeviceInfoSet,
|
|
IN DEVINST DevInst,
|
|
IN LPGUID ClassGuid,
|
|
IN PCTSTR Description, OPTIONAL
|
|
IN HWND hwndParent, OPTIONAL
|
|
IN DWORD DiElemFlags,
|
|
OUT PDEVINFO_ELEM *DeviceInfoElement
|
|
);
|
|
|
|
DWORD
|
|
pSetupClassGuidFromDevInst(
|
|
IN DEVINST DevInst,
|
|
OUT LPGUID ClassGuid
|
|
);
|
|
|
|
DWORD
|
|
pSetupDupDevCompare(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA NewDeviceData,
|
|
IN PSP_DEVINFO_DATA ExistingDeviceData,
|
|
IN PVOID CompareContext
|
|
);
|
|
|
|
|
|
HDEVINFO
|
|
WINAPI
|
|
SetupDiCreateDeviceInfoList(
|
|
IN LPGUID ClassGuid, OPTIONAL
|
|
IN HWND hwndParent OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API creates an empty device information set that will contain device
|
|
device information member elements. This set may be associated with an
|
|
optionally-specified class GUID.
|
|
|
|
Arguments:
|
|
|
|
ClassGuid - Optionally, supplies a pointer to the class GUID that is to be
|
|
associated with this set.
|
|
|
|
hwndParent - Optionally, supplies the window handle of the top-level window
|
|
to use for any UI related to installation of a class driver contained
|
|
in this set's global class driver list (if it has one).
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is a handle to an empty device
|
|
information set.
|
|
|
|
If the function fails, the return value is INVALID_HANDLE_VALUE. To get
|
|
extended error information, call GetLastError.
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_INFO_SET DeviceInfoSet;
|
|
DWORD Err = NO_ERROR;
|
|
|
|
if(DeviceInfoSet = AllocateDeviceInfoSet()) {
|
|
|
|
try {
|
|
|
|
if(ClassGuid) {
|
|
//
|
|
// If a class GUID was specified, then store it away in
|
|
// the device information set.
|
|
//
|
|
CopyMemory(&(DeviceInfoSet->ClassGuid),
|
|
ClassGuid,
|
|
sizeof(GUID)
|
|
);
|
|
DeviceInfoSet->HasClassGuid = TRUE;
|
|
}
|
|
|
|
DeviceInfoSet->InstallParamBlock.hwndParent = hwndParent;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if(Err != NO_ERROR) {
|
|
DestroyDeviceInfoSet(NULL, DeviceInfoSet);
|
|
}
|
|
|
|
} else {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
SetLastError(Err);
|
|
|
|
return (Err == NO_ERROR) ? (HDEVINFO)DeviceInfoSet
|
|
: (HDEVINFO)INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupDiGetDeviceInfoListClass(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
OUT LPGUID ClassGuid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API retrieves the class GUID associated with a device information
|
|
set (if it has an associated class).
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - Supplies a handle to a device information set whose associated
|
|
class is being queried.
|
|
|
|
ClassGuid - Supplies a pointer to a variable that receives the GUID for the
|
|
associated class.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is TRUE.
|
|
|
|
If the function fails, the return value is FALSE. To get extended error
|
|
information, call GetLastError. If the set has no associated class, then
|
|
GetLastError will return ERROR_NO_ASSOCIATED_CLASS.
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_INFO_SET pDeviceInfoSet;
|
|
DWORD Err;
|
|
|
|
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
Err = NO_ERROR;
|
|
|
|
try {
|
|
|
|
if(pDeviceInfoSet->HasClassGuid) {
|
|
//
|
|
// Copy the GUID to the user-supplied buffer.
|
|
//
|
|
CopyMemory(ClassGuid,
|
|
&(pDeviceInfoSet->ClassGuid),
|
|
sizeof(GUID)
|
|
);
|
|
} else {
|
|
Err = ERROR_NO_ASSOCIATED_CLASS;
|
|
}
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
UnlockDeviceInfoSet(pDeviceInfoSet);
|
|
|
|
SetLastError(Err);
|
|
return (Err == NO_ERROR);
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupDiDestroyDeviceInfoList(
|
|
IN HDEVINFO DeviceInfoSet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API destroys a device information set, freeing all associated memory.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - Supplies a handle to a device information set to be destroyed.
|
|
|
|
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;
|
|
PDEVICE_INFO_SET pDeviceInfoSet;
|
|
|
|
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
try {
|
|
Err = DestroyDeviceInfoSet(DeviceInfoSet, pDeviceInfoSet);
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_HANDLE;
|
|
}
|
|
|
|
SetLastError(Err);
|
|
return (Err == NO_ERROR);
|
|
}
|
|
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// ANSI version
|
|
//
|
|
BOOL
|
|
WINAPI
|
|
SetupDiCreateDeviceInfoA(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PCSTR DeviceName,
|
|
IN LPGUID ClassGuid,
|
|
IN PCSTR DeviceDescription, OPTIONAL
|
|
IN HWND hwndParent, OPTIONAL
|
|
IN DWORD CreationFlags,
|
|
OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
|
|
)
|
|
{
|
|
PCWSTR deviceName,deviceDescription;
|
|
DWORD rc;
|
|
BOOL b;
|
|
|
|
b = FALSE;
|
|
rc = CaptureAndConvertAnsiArg(DeviceName,&deviceName);
|
|
if(rc == NO_ERROR) {
|
|
|
|
if(DeviceDescription) {
|
|
rc = CaptureAndConvertAnsiArg(DeviceDescription,&deviceDescription);
|
|
} else {
|
|
deviceDescription = NULL;
|
|
}
|
|
|
|
if(rc == NO_ERROR) {
|
|
|
|
b = SetupDiCreateDeviceInfoW(
|
|
DeviceInfoSet,
|
|
deviceName,
|
|
ClassGuid,
|
|
deviceDescription,
|
|
hwndParent,
|
|
CreationFlags,
|
|
DeviceInfoData
|
|
);
|
|
|
|
rc = GetLastError();
|
|
|
|
if(deviceDescription) {
|
|
MyFree(deviceDescription);
|
|
}
|
|
}
|
|
|
|
MyFree(deviceName);
|
|
}
|
|
|
|
SetLastError(rc);
|
|
return(b);
|
|
}
|
|
#else
|
|
//
|
|
// Unicode version
|
|
//
|
|
BOOL
|
|
WINAPI
|
|
SetupDiCreateDeviceInfoW(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PCWSTR DeviceName,
|
|
IN LPGUID ClassGuid,
|
|
IN PCWSTR DeviceDescription, OPTIONAL
|
|
IN HWND hwndParent, OPTIONAL
|
|
IN DWORD CreationFlags,
|
|
OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(DeviceInfoSet);
|
|
UNREFERENCED_PARAMETER(DeviceName);
|
|
UNREFERENCED_PARAMETER(ClassGuid);
|
|
UNREFERENCED_PARAMETER(DeviceDescription);
|
|
UNREFERENCED_PARAMETER(hwndParent);
|
|
UNREFERENCED_PARAMETER(CreationFlags);
|
|
UNREFERENCED_PARAMETER(DeviceInfoData);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupDiCreateDeviceInfo(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PCTSTR DeviceName,
|
|
IN LPGUID ClassGuid,
|
|
IN PCTSTR DeviceDescription, OPTIONAL
|
|
IN HWND hwndParent, OPTIONAL
|
|
IN DWORD CreationFlags,
|
|
OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API creates a new device information element, and adds it as a new member
|
|
to the specified set.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - Supplies a handle to a device information set to which this
|
|
new device information element is to be added.
|
|
|
|
DeviceName - Supplies either a full device instance ID (e.g., Root\*PNP0500\0000)
|
|
or a Root-enumerated device ID, minus enumerator branch prefix and instance
|
|
ID suffix (e.g., *PNP0500). The latter may only be specified if the
|
|
DICD_GENERATE_ID flag is specified in the CreationFlags parameter.
|
|
|
|
ClassGuid - Supplies a pointer to the GUID for this device's class. If the
|
|
class is not yet known, this value should be GUID_NULL.
|
|
|
|
DeviceDescription - Optionally, supplies a textual description of the device.
|
|
|
|
hwndParent - Optionally, supplies the window handle of the top-level window
|
|
to use for any UI related to installing the device.
|
|
|
|
CreationFlags - Supplies flags controlling how the device information element
|
|
is to be created. May be a combination of the following values:
|
|
|
|
DICD_GENERATE_ID - If this flag is specified, then DeviceName contains only
|
|
a Root-enumerated device ID, and needs to have a unique
|
|
device instance key created for it. This unique device
|
|
instance key will be generated as:
|
|
|
|
Enum\Root\<DeviceName>\<InstanceID>
|
|
|
|
where <InstanceID> is a 4-digit, base-10 number that
|
|
is unique among all subkeys under Enum\Root\<DeviceName>.
|
|
The API, SetupDiGetDeviceInstanceId, may be called to
|
|
find out what ID was generated for this device information
|
|
element.
|
|
|
|
DICD_INHERIT_CLASSDRVS - If this flag is specified, then the resulting device
|
|
information element will inherit the class driver list (if any)
|
|
associated with the device information set itself. In addition,
|
|
if there is a selected driver for the device information set,
|
|
that same driver will be selected for the new device information
|
|
element.
|
|
|
|
DeviceInfoData - Optionaly, supplies a pointer to the variable that receives
|
|
a context structure initialized for this new device information element.
|
|
|
|
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:
|
|
|
|
If this device instance is being added to a set that has an associated class,
|
|
then the device class must be the same, or the call will fail, and GetLastError
|
|
will return ERROR_CLASS_MISMATCH.
|
|
|
|
If the specified device instance is the same as an existing device instance key in
|
|
the registry, the call will fail with ERROR_DEVINST_ALREADY_EXISTS. (This only
|
|
applies if DICD_GENERATE_ID is not specified.)
|
|
|
|
The specified class GUID will be written out to the ClassGUID device instance
|
|
value entry. If the class name can be retrieved (via SetupDiClassNameFromGuid),
|
|
then it will be written to the Class value entry as well.
|
|
|
|
If the new device information element was successfully created, but the
|
|
user-supplied DeviceInfoData buffer is invalid, this API will return FALSE, with
|
|
GetLastError returning ERROR_INVALID_USER_BUFFER. The device information element
|
|
_will_ have been added as a new member of the set, however.
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_INFO_SET pDeviceInfoSet;
|
|
DWORD Err, StringLen;
|
|
PDEVINFO_ELEM DevInfoElem;
|
|
DEVINST DevInst, RootDevInst;
|
|
CONFIGRET cr;
|
|
ULONG CmFlags;
|
|
TCHAR TempString[GUID_STRING_LEN];
|
|
PDRIVER_LIST_OBJECT CurDrvListObject;
|
|
|
|
//
|
|
// We use the TempString buffer both for the string representation of
|
|
// a Class GUID, and for the Class name. The following assert ensures
|
|
// that our assumptions about the relative lengths of these two strings
|
|
// continues to be valid.
|
|
//
|
|
MYASSERT(GUID_STRING_LEN >= MAX_CLASS_NAME_LEN);
|
|
|
|
if(CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS)) {
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
return FALSE;
|
|
}
|
|
|
|
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
Err = NO_ERROR;
|
|
|
|
try {
|
|
//
|
|
// Get a handle to the root device instance, to be used as the parent
|
|
// for the phantom device instance we're about to create.
|
|
//
|
|
if(CM_Locate_DevInst(&RootDevInst, NULL, CM_LOCATE_DEVINST_NORMAL) != CR_SUCCESS) {
|
|
//
|
|
// We're really hosed if we can't get a handle to the root device
|
|
// instance!
|
|
//
|
|
Err = ERROR_INVALID_DATA;
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Create a handle to a phantom device instance.
|
|
//
|
|
CmFlags = CM_CREATE_DEVINST_PHANTOM;
|
|
|
|
if(CreationFlags & DICD_GENERATE_ID) {
|
|
CmFlags |= CM_CREATE_DEVINST_GENERATE_ID;
|
|
}
|
|
|
|
if((cr = CM_Create_DevInst(&DevInst,
|
|
(DEVINSTID)DeviceName,
|
|
RootDevInst,
|
|
CmFlags)) != CR_SUCCESS) {
|
|
|
|
switch(cr) {
|
|
|
|
case CR_INVALID_DEVICE_ID :
|
|
Err = ERROR_INVALID_DEVINST_NAME;
|
|
break;
|
|
|
|
case CR_ALREADY_SUCH_DEVINST :
|
|
Err = ERROR_DEVINST_ALREADY_EXISTS;
|
|
break;
|
|
|
|
case CR_OUT_OF_MEMORY :
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
|
|
default :
|
|
Err = ERROR_INVALID_DATA;
|
|
}
|
|
goto clean0;
|
|
}
|
|
|
|
if((Err = pSetupAddNewDeviceInfoElement(pDeviceInfoSet,
|
|
DevInst,
|
|
ClassGuid,
|
|
DeviceDescription,
|
|
hwndParent,
|
|
DIE_IS_PHANTOM,
|
|
&DevInfoElem)) != NO_ERROR) {
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Now, set the Class and ClassGUID properties for the new device instance.
|
|
//
|
|
pSetupStringFromGuid(ClassGuid, TempString, SIZECHARS(TempString));
|
|
CM_Set_DevInst_Registry_Property(DevInst,
|
|
CM_DRP_CLASSGUID,
|
|
(PVOID)TempString,
|
|
GUID_STRING_LEN * sizeof(TCHAR),
|
|
0
|
|
);
|
|
if(!IsEqualGUID(ClassGuid, &GUID_NULL) &&
|
|
SetupDiClassNameFromGuid(ClassGuid,
|
|
TempString,
|
|
SIZECHARS(TempString),
|
|
&StringLen)) {
|
|
|
|
CM_Set_DevInst_Registry_Property(DevInst,
|
|
CM_DRP_CLASS,
|
|
(PVOID)TempString,
|
|
StringLen * sizeof(TCHAR),
|
|
0
|
|
);
|
|
}
|
|
|
|
//
|
|
// If the caller wants the newly-created devinfo element to inherit the global
|
|
// class driver list, do that now.
|
|
//
|
|
if((CreationFlags & DICD_INHERIT_CLASSDRVS) && (pDeviceInfoSet->ClassDriverHead)) {
|
|
//
|
|
// Find the global class driver list in the devinfo set's list of driver lists.
|
|
//
|
|
CurDrvListObject = GetAssociatedDriverListObject(pDeviceInfoSet->ClassDrvListObjectList,
|
|
pDeviceInfoSet->ClassDriverHead,
|
|
NULL
|
|
);
|
|
MYASSERT(CurDrvListObject && (CurDrvListObject->RefCount > 0));
|
|
|
|
//
|
|
// We found the driver list object, now increment its refcount, and do the
|
|
// inheritance.
|
|
//
|
|
CurDrvListObject->RefCount++;
|
|
|
|
DevInfoElem->ClassDriverCount = pDeviceInfoSet->ClassDriverCount;
|
|
DevInfoElem->ClassDriverHead = pDeviceInfoSet->ClassDriverHead;
|
|
DevInfoElem->ClassDriverTail = pDeviceInfoSet->ClassDriverTail;
|
|
|
|
if(DevInfoElem->SelectedDriver = pDeviceInfoSet->SelectedClassDriver) {
|
|
DevInfoElem->SelectedDriverType = SPDIT_CLASSDRIVER;
|
|
}
|
|
|
|
DevInfoElem->InstallParamBlock.Flags |= CurDrvListObject->ListCreationFlags;
|
|
DevInfoElem->InstallParamBlock.FlagsEx |= CurDrvListObject->ListCreationFlagsEx;
|
|
DevInfoElem->InstallParamBlock.DriverPath = CurDrvListObject->ListCreationDriverPath;
|
|
}
|
|
|
|
clean0:
|
|
; // Nothing to do.
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if((Err == NO_ERROR) && DeviceInfoData) {
|
|
//
|
|
// The user supplied a buffer to receive a SP_DEVINFO_DATA
|
|
// structure, so fill that in now.
|
|
//
|
|
try {
|
|
|
|
if(!(DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
|
|
DevInfoElem,
|
|
DeviceInfoData))) {
|
|
Err = ERROR_INVALID_USER_BUFFER;
|
|
}
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_USER_BUFFER;
|
|
}
|
|
}
|
|
|
|
UnlockDeviceInfoSet(pDeviceInfoSet);
|
|
|
|
SetLastError(Err);
|
|
return(Err == NO_ERROR);
|
|
}
|
|
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// ANSI version
|
|
//
|
|
BOOL
|
|
WINAPI
|
|
SetupDiOpenDeviceInfoA(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PCSTR DeviceInstanceId,
|
|
IN HWND hwndParent, OPTIONAL
|
|
IN DWORD OpenFlags,
|
|
OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
|
|
)
|
|
{
|
|
PCWSTR deviceInstanceId;
|
|
DWORD rc;
|
|
BOOL b;
|
|
|
|
rc = CaptureAndConvertAnsiArg(DeviceInstanceId,&deviceInstanceId);
|
|
if(rc == NO_ERROR) {
|
|
|
|
b = SetupDiOpenDeviceInfoW(
|
|
DeviceInfoSet,
|
|
deviceInstanceId,
|
|
hwndParent,
|
|
OpenFlags,
|
|
DeviceInfoData
|
|
);
|
|
|
|
rc = GetLastError();
|
|
|
|
MyFree(deviceInstanceId);
|
|
|
|
} else {
|
|
b = FALSE;
|
|
}
|
|
|
|
SetLastError(rc);
|
|
return(b);
|
|
}
|
|
#else
|
|
//
|
|
// Unicode version
|
|
//
|
|
BOOL
|
|
WINAPI
|
|
SetupDiOpenDeviceInfoW(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PCWSTR DeviceInstanceId,
|
|
IN HWND hwndParent, OPTIONAL
|
|
IN DWORD OpenFlags,
|
|
OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(DeviceInfoSet);
|
|
UNREFERENCED_PARAMETER(DeviceInstanceId);
|
|
UNREFERENCED_PARAMETER(hwndParent);
|
|
UNREFERENCED_PARAMETER(OpenFlags);
|
|
UNREFERENCED_PARAMETER(DeviceInfoData);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupDiOpenDeviceInfo(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PCTSTR DeviceInstanceId,
|
|
IN HWND hwndParent, OPTIONAL
|
|
IN DWORD OpenFlags,
|
|
OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API retrieves information about an existing device instance, and adds
|
|
it to the specified device information set. If a device information element
|
|
already exists for this device instance, the existing element is returned.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - Supplies a handle to a device information set to which the
|
|
opened device information element is to be added.
|
|
|
|
DeviceInstanceId - Supplies the ID of the device instance. This is the
|
|
registry path (relative to the Enum branch) of the device instance key.
|
|
(E.g., Root\*PNP0500\0000)
|
|
|
|
hwndParent - Optionally, supplies the window handle of the top-level window
|
|
to use for any UI related to installing the device.
|
|
|
|
OpenFlags - Supplies flags controlling how the device information element
|
|
is to be opened. May be a combination of the following values:
|
|
|
|
DIOD_INHERIT_CLASSDRVS - If this flag is specified, then the resulting device
|
|
information element will inherit the class driver
|
|
list (if any) associated with the device information
|
|
set itself. In addition, if there is a selected
|
|
driver for the device information set, that same
|
|
driver will be selected for the new device information
|
|
element.
|
|
|
|
If the device information element was already present,
|
|
its class driver list (if any) will be replaced with
|
|
this new, inherited, list.
|
|
|
|
DIOD_CANCEL_REMOVE - If this flag is set, a device that was marked for removal
|
|
will be have its pending removal cancelled.
|
|
|
|
DeviceInfoData - Optionally, supplies a pointer to the variable that receives
|
|
a context structure initialized for the opened device information element.
|
|
|
|
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:
|
|
|
|
If this device instance is being added to a set that has an associated class,
|
|
then the device class must be the same, or the call will fail, and GetLastError
|
|
will return ERROR_CLASS_MISMATCH.
|
|
|
|
If the new device information element was successfully opened, but the
|
|
user-supplied DeviceInfoData buffer is invalid, this API will return FALSE,
|
|
with GetLastError returning ERROR_INVALID_USER_BUFFER. The device information
|
|
element _will_ have been added as a new member of the set, however.
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_INFO_SET pDeviceInfoSet;
|
|
DWORD Err;
|
|
PDEVINFO_ELEM DevInfoElem;
|
|
PDRIVER_LIST_OBJECT CurDrvListObject;
|
|
BOOL AlreadyPresent;
|
|
|
|
if(OpenFlags & ~(DIOD_INHERIT_CLASSDRVS | DIOD_CANCEL_REMOVE)) {
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
return FALSE;
|
|
}
|
|
|
|
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
Err = NO_ERROR;
|
|
|
|
try {
|
|
|
|
if((Err = pSetupOpenAndAddNewDevInfoElem(pDeviceInfoSet,
|
|
DeviceInstanceId,
|
|
TRUE,
|
|
NULL,
|
|
hwndParent,
|
|
&DevInfoElem,
|
|
TRUE,
|
|
&AlreadyPresent,
|
|
(OpenFlags & DIOD_CANCEL_REMOVE)
|
|
? CM_LOCATE_DEVNODE_CANCELREMOVE : 0
|
|
)) != NO_ERROR) {
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// If the caller wants the newly-opened devinfo element to inherit the global
|
|
// class driver list, do that now.
|
|
//
|
|
if(OpenFlags & DIOD_INHERIT_CLASSDRVS) {
|
|
//
|
|
// If this devinfo element already existed, then it may already have a class
|
|
// driver list. Destroy that list before inheriting from the global class
|
|
// driver list.
|
|
//
|
|
if(AlreadyPresent) {
|
|
//
|
|
// If the selected driver is a class driver, then reset the selection.
|
|
//
|
|
if(DevInfoElem->SelectedDriverType == SPDIT_CLASSDRIVER) {
|
|
DevInfoElem->SelectedDriverType = SPDIT_NODRIVER;
|
|
DevInfoElem->SelectedDriver = NULL;
|
|
}
|
|
|
|
//
|
|
// Destroy the existing class driver list for this device.
|
|
//
|
|
DereferenceClassDriverList(pDeviceInfoSet, DevInfoElem->ClassDriverHead);
|
|
DevInfoElem->ClassDriverCount = 0;
|
|
DevInfoElem->ClassDriverHead = DevInfoElem->ClassDriverTail = NULL;
|
|
DevInfoElem->InstallParamBlock.Flags &= ~(DI_DIDCLASS | DI_MULTMFGS);
|
|
DevInfoElem->InstallParamBlock.FlagsEx &= ~DI_FLAGSEX_DIDINFOLIST;
|
|
}
|
|
|
|
if(pDeviceInfoSet->ClassDriverHead) {
|
|
//
|
|
// Find the global class driver list in the devinfo set's list of driver lists.
|
|
//
|
|
CurDrvListObject = GetAssociatedDriverListObject(pDeviceInfoSet->ClassDrvListObjectList,
|
|
pDeviceInfoSet->ClassDriverHead,
|
|
NULL
|
|
);
|
|
MYASSERT(CurDrvListObject && (CurDrvListObject->RefCount > 0));
|
|
|
|
//
|
|
// We found the driver list object, now increment its refcount, and do the
|
|
// inheritance.
|
|
//
|
|
CurDrvListObject->RefCount++;
|
|
|
|
DevInfoElem->ClassDriverCount = pDeviceInfoSet->ClassDriverCount;
|
|
DevInfoElem->ClassDriverHead = pDeviceInfoSet->ClassDriverHead;
|
|
DevInfoElem->ClassDriverTail = pDeviceInfoSet->ClassDriverTail;
|
|
|
|
if(pDeviceInfoSet->SelectedClassDriver) {
|
|
DevInfoElem->SelectedDriver = pDeviceInfoSet->SelectedClassDriver;
|
|
DevInfoElem->SelectedDriverType = SPDIT_CLASSDRIVER;
|
|
}
|
|
|
|
DevInfoElem->InstallParamBlock.Flags |= CurDrvListObject->ListCreationFlags;
|
|
DevInfoElem->InstallParamBlock.FlagsEx |= CurDrvListObject->ListCreationFlagsEx;
|
|
DevInfoElem->InstallParamBlock.DriverPath = CurDrvListObject->ListCreationDriverPath;
|
|
}
|
|
}
|
|
|
|
clean0: ; // nothing to do
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if((Err == NO_ERROR) && DeviceInfoData) {
|
|
//
|
|
// The user supplied a buffer to receive a SP_DEVINFO_DATA
|
|
// structure, so fill that in now.
|
|
//
|
|
try {
|
|
|
|
if(!(DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
|
|
DevInfoElem,
|
|
DeviceInfoData))) {
|
|
Err = ERROR_INVALID_USER_BUFFER;
|
|
}
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_USER_BUFFER;
|
|
}
|
|
}
|
|
|
|
UnlockDeviceInfoSet(pDeviceInfoSet);
|
|
|
|
SetLastError(Err);
|
|
return(Err == NO_ERROR);
|
|
}
|
|
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// ANSI version
|
|
//
|
|
HDEVINFO
|
|
WINAPI
|
|
SetupDiGetClassDevsA(
|
|
IN LPGUID ClassGuid, OPTIONAL
|
|
IN PCSTR Enumerator, OPTIONAL
|
|
IN HWND hwndParent, OPTIONAL
|
|
IN DWORD Flags
|
|
)
|
|
{
|
|
PCWSTR enumerator;
|
|
DWORD rc;
|
|
HDEVINFO h;
|
|
|
|
if(Enumerator) {
|
|
rc = CaptureAndConvertAnsiArg(Enumerator,&enumerator);
|
|
if(rc != NO_ERROR) {
|
|
SetLastError(rc);
|
|
return(FALSE);
|
|
}
|
|
} else {
|
|
enumerator = NULL;
|
|
}
|
|
|
|
h = SetupDiGetClassDevsW(ClassGuid,enumerator,hwndParent,Flags);
|
|
rc = GetLastError();
|
|
|
|
if(enumerator) {
|
|
MyFree(enumerator);
|
|
}
|
|
|
|
SetLastError(rc);
|
|
return(h);
|
|
}
|
|
#else
|
|
//
|
|
// Unicode version
|
|
//
|
|
HDEVINFO
|
|
WINAPI
|
|
SetupDiGetClassDevsW(
|
|
IN LPGUID ClassGuid, OPTIONAL
|
|
IN PCWSTR Enumerator, OPTIONAL
|
|
IN HWND hwndParent, OPTIONAL
|
|
IN DWORD Flags
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(ClassGuid);
|
|
UNREFERENCED_PARAMETER(Enumerator);
|
|
UNREFERENCED_PARAMETER(hwndParent);
|
|
UNREFERENCED_PARAMETER(Flags);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(INVALID_HANDLE_VALUE);
|
|
}
|
|
#endif
|
|
|
|
HDEVINFO
|
|
WINAPI
|
|
SetupDiGetClassDevs(
|
|
IN LPGUID ClassGuid, OPTIONAL
|
|
IN PCTSTR Enumerator, OPTIONAL
|
|
IN HWND hwndParent, OPTIONAL
|
|
IN DWORD Flags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns a device information set containing all installed
|
|
devices of the specified class.
|
|
|
|
Arguments:
|
|
|
|
ClassGuid - Optionally, supplies the address of the class GUID to use
|
|
when creating the list of devices. If the DIGCF_ALLCLASSES flag is
|
|
set, then this parameter is ignored, and the resulting list will
|
|
contain all classes of devices (i.e., every installed device).
|
|
|
|
Enumerator - Optionally, supplies the name of the key under the Enum branch
|
|
containing devices instances for which information is to be retrieved.
|
|
If this parameter is not specified, then device information will be
|
|
retrieved for all device instances in the entire Enum tree.
|
|
|
|
hwndParent - Optionally, supplies the handle of the top-level window to be
|
|
used for any UI relating to the members of this set.
|
|
|
|
Flags - Supplies control options used in building the device information set.
|
|
May be a combination of the following values:
|
|
|
|
DIGCF_PRESENT - Return only devices that are currently present.
|
|
DIGCF_ALLCLASSES - Return a list of installed devices for all classes. If
|
|
set, this flag will cause ClassGuid to be ignored.
|
|
DIGCF_PROFILE - Return only devices that are a part of the current
|
|
hardware profile.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is a handle to a device information
|
|
set containing all installed devices matching the specified parameters.
|
|
|
|
If the function fails, the return value is INVALID_HANDLE_VALUE. To get
|
|
extended error information, call GetLastError.
|
|
|
|
--*/
|
|
{
|
|
HDEVINFO hDevInfo;
|
|
PDEVICE_INFO_SET pDeviceInfoSet;
|
|
PDEVINFO_ELEM DevInfoElem;
|
|
DWORD Err;
|
|
CONFIGRET cr;
|
|
PTCHAR DevIdBuffer;
|
|
ULONG DevIdBufferLen, CSConfigFlags;
|
|
PTSTR CurDevId;
|
|
|
|
if(!(Flags & DIGCF_ALLCLASSES) && !ClassGuid) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if((hDevInfo = SetupDiCreateDeviceInfoList((Flags & DIGCF_ALLCLASSES)
|
|
? NULL
|
|
: ClassGuid,
|
|
hwndParent)) == INVALID_HANDLE_VALUE) {
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
pDeviceInfoSet = AccessDeviceInfoSet(hDevInfo);
|
|
|
|
Err = NO_ERROR;
|
|
DevIdBuffer = NULL;
|
|
|
|
try {
|
|
//
|
|
// As an optimization, start out with a 16K (character) buffer, in the hopes of avoiding
|
|
// two scans through the hardware tree (once to get the size, and again to get the data).
|
|
//
|
|
DevIdBufferLen = 16384;
|
|
|
|
while(TRUE) {
|
|
|
|
if(!(DevIdBuffer = MyMalloc(DevIdBufferLen * sizeof(TCHAR)))) {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto clean0;
|
|
}
|
|
|
|
if((cr = CM_Get_Device_ID_List(Enumerator,
|
|
DevIdBuffer,
|
|
DevIdBufferLen,
|
|
Enumerator ? CM_GETIDLIST_FILTER_ENUMERATOR
|
|
: CM_GETIDLIST_FILTER_NONE)) == CR_SUCCESS) {
|
|
//
|
|
// Device list successfully retrieved!
|
|
//
|
|
break;
|
|
|
|
} else {
|
|
//
|
|
// Free the current buffer before determining what error occurred.
|
|
//
|
|
MyFree(DevIdBuffer);
|
|
DevIdBuffer = NULL;
|
|
|
|
if(cr == CR_BUFFER_SMALL) {
|
|
//
|
|
// OK, so our buffer wasn't big enough--just how big does it need to be?
|
|
//
|
|
if(CM_Get_Device_ID_List_Size(&DevIdBufferLen,
|
|
Enumerator,
|
|
Enumerator ? CM_GETIDLIST_FILTER_ENUMERATOR
|
|
: CM_GETIDLIST_FILTER_NONE) != CR_SUCCESS) {
|
|
//
|
|
// Couldn't retrieve the list size--this should never happen.
|
|
//
|
|
Err = ERROR_INVALID_DATA;
|
|
goto clean0;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// An error occurred, and it wasn't because we supplied too small a buffer.
|
|
//
|
|
Err = ERROR_INVALID_DATA;
|
|
goto clean0;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// We have now retrieved all the specified device IDs. Now create
|
|
// device information elements from the members of this list.
|
|
//
|
|
for(CurDevId = DevIdBuffer;
|
|
*CurDevId;
|
|
CurDevId += lstrlen(CurDevId) + 1) {
|
|
|
|
if(Flags & DIGCF_PROFILE) {
|
|
//
|
|
// Verify that this device instance is part of the current
|
|
// hardware profile.
|
|
//
|
|
if(CM_Get_HW_Prof_Flags(CurDevId,
|
|
0,
|
|
&CSConfigFlags,
|
|
0) == CR_SUCCESS) {
|
|
|
|
if(CSConfigFlags & CSCONFIGFLAG_DO_NOT_CREATE) {
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
Err = pSetupOpenAndAddNewDevInfoElem(pDeviceInfoSet,
|
|
CurDevId,
|
|
!(Flags & DIGCF_PRESENT),
|
|
(Flags & DIGCF_ALLCLASSES)
|
|
? NULL
|
|
: ClassGuid,
|
|
hwndParent,
|
|
&DevInfoElem,
|
|
FALSE,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if(Err == ERROR_NOT_ENOUGH_MEMORY) {
|
|
goto clean0;
|
|
} else if(Err != NO_ERROR) {
|
|
Err = NO_ERROR;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
clean0:
|
|
; // Nothing to do.
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
//
|
|
// Access the DevIdBuffer variable, so the compiler will respect
|
|
// the statement ordering in the try clause. If we don't do this,
|
|
// then we might not get the pointer reset to NULL right after the
|
|
// buffer is freed, and thus would try to free it again outside the
|
|
// try/except.
|
|
//
|
|
DevIdBuffer = DevIdBuffer;
|
|
}
|
|
|
|
if(DevIdBuffer) {
|
|
MyFree(DevIdBuffer);
|
|
}
|
|
|
|
if(Err != NO_ERROR) {
|
|
DestroyDeviceInfoSet(hDevInfo, pDeviceInfoSet);
|
|
SetLastError(Err);
|
|
return INVALID_HANDLE_VALUE;
|
|
} else {
|
|
UnlockDeviceInfoSet(pDeviceInfoSet);
|
|
return hDevInfo;
|
|
}
|
|
}
|
|
|
|
|
|
DWORD
|
|
pSetupAddNewDeviceInfoElement(
|
|
IN PDEVICE_INFO_SET DeviceInfoSet,
|
|
IN DEVINST DevInst,
|
|
IN LPGUID ClassGuid,
|
|
IN PCTSTR Description, OPTIONAL
|
|
IN HWND hwndParent, OPTIONAL
|
|
IN DWORD DiElemFlags,
|
|
OUT PDEVINFO_ELEM *DeviceInfoElement
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a new device information element based on the
|
|
supplied information, and adds it to the specified device information set.
|
|
ASSUMES THAT THE CALLING ROUTINE HAS ALREADY ACQUIRED THE LOCK!
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - Device information set to add this new element to.
|
|
|
|
DevInst - Supplies the device instance handle of the element to be added.
|
|
|
|
ClassGuid - Class GUID of the element to be added.
|
|
|
|
Description - Optionally, supplies the description of the element to
|
|
be added.
|
|
|
|
hwndParent - Optionally, supplies the handle to the top level window for
|
|
UI relating to this element.
|
|
|
|
DiElemFlags - Specifies flags pertaining to the device information element
|
|
being created.
|
|
|
|
DeviceInfoElement - Supplies the address of the variable that receives a
|
|
pointer to the newly-allocated device information element.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is NO_ERROR, otherwise the
|
|
ERROR_* code is returned.
|
|
|
|
--*/
|
|
{
|
|
DWORD Err = NO_ERROR;
|
|
TCHAR TempString[LINE_LEN];
|
|
|
|
*DeviceInfoElement = NULL;
|
|
|
|
try {
|
|
//
|
|
// If there is a class associated with this device information set,
|
|
// verify that it is the same as that of the new element.
|
|
//
|
|
if(DeviceInfoSet->HasClassGuid &&
|
|
!IsEqualGUID(&(DeviceInfoSet->ClassGuid), ClassGuid)) {
|
|
|
|
Err = ERROR_CLASS_MISMATCH;
|
|
goto clean0;
|
|
|
|
}
|
|
|
|
//
|
|
// Allocate storage for the element.
|
|
//
|
|
if(!(*DeviceInfoElement = MyMalloc(sizeof(DEVINFO_ELEM)))) {
|
|
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto clean0;
|
|
}
|
|
|
|
ZeroMemory(*DeviceInfoElement, sizeof(DEVINFO_ELEM));
|
|
|
|
//
|
|
// Initialize the element with the specified information
|
|
//
|
|
CopyMemory(&((*DeviceInfoElement)->ClassGuid),
|
|
ClassGuid,
|
|
sizeof(GUID)
|
|
);
|
|
(*DeviceInfoElement)->InstallParamBlock.hwndParent = hwndParent;
|
|
|
|
if(Description) {
|
|
//
|
|
// Store two versions of the description--one case-sensitive (for display)
|
|
// and the other case-insensitive (for fast lookup).
|
|
//
|
|
lstrcpyn(TempString, Description, SIZECHARS(TempString));
|
|
|
|
if((((*DeviceInfoElement)->DeviceDescriptionDisplayName =
|
|
pStringTableAddString(DeviceInfoSet->StringTable,
|
|
TempString,
|
|
STRTAB_CASE_SENSITIVE)) == -1) ||
|
|
(((*DeviceInfoElement)->DeviceDescription =
|
|
pStringTableAddString(DeviceInfoSet->StringTable,
|
|
TempString,
|
|
STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE)) == -1)) {
|
|
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto clean0;
|
|
}
|
|
|
|
} else {
|
|
(*DeviceInfoElement)->DeviceDescription =
|
|
(*DeviceInfoElement)->DeviceDescriptionDisplayName = -1;
|
|
}
|
|
|
|
(*DeviceInfoElement)->DevInst = DevInst;
|
|
(*DeviceInfoElement)->DiElemFlags = DiElemFlags;
|
|
(*DeviceInfoElement)->InstallParamBlock.DriverPath = -1;
|
|
|
|
//
|
|
// Now, insert the new element at the end of the device
|
|
// information set's list of elements.
|
|
//
|
|
if(DeviceInfoSet->DeviceInfoHead) {
|
|
DeviceInfoSet->DeviceInfoTail->Next = *DeviceInfoElement;
|
|
DeviceInfoSet->DeviceInfoTail = *DeviceInfoElement;
|
|
} else {
|
|
DeviceInfoSet->DeviceInfoHead =
|
|
DeviceInfoSet->DeviceInfoTail = *DeviceInfoElement;
|
|
}
|
|
DeviceInfoSet->DeviceInfoCount++;
|
|
|
|
clean0:
|
|
; // Nothing to do.
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if((Err != NO_ERROR) && *DeviceInfoElement) {
|
|
|
|
MyFree(*DeviceInfoElement);
|
|
*DeviceInfoElement = NULL;
|
|
}
|
|
|
|
return Err;
|
|
}
|
|
|
|
|
|
DWORD
|
|
pSetupClassGuidFromDevInst(
|
|
IN DEVINST DevInst,
|
|
OUT LPGUID ClassGuid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine attempts to retrieve the class GUID for the specified device
|
|
instance from its device registry key. If it cannot retrieve one, it
|
|
returns GUID_NULL.
|
|
|
|
Arguments:
|
|
|
|
DevInst - Supplies the handle of the device instance whose class GUID is
|
|
to be retrieved.
|
|
|
|
ClassGuid - Supplies the address of the variable that receives the class
|
|
GUID, or GUID_NULL if no class GUID can be retrieved.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is NO_ERROR.
|
|
If the function fails, an ERROR_* code is returned. (Presently, the only
|
|
failure condition returned is ERROR_NOT_ENOUGH_MEMORY.)
|
|
|
|
--*/
|
|
{
|
|
DWORD NumGuids;
|
|
TCHAR TempString[GUID_STRING_LEN];
|
|
DWORD StringSize;
|
|
|
|
StringSize = sizeof(TempString);
|
|
if(CM_Get_DevInst_Registry_Property(DevInst,
|
|
CM_DRP_CLASSGUID,
|
|
NULL,
|
|
TempString,
|
|
&StringSize,
|
|
0) == CR_SUCCESS) {
|
|
//
|
|
// We retrieved the class GUID (in string form) for this device
|
|
// instance--now, convert it into its binary representation.
|
|
//
|
|
return pSetupGuidFromString(TempString, ClassGuid);
|
|
}
|
|
|
|
//
|
|
// We couldn't retrieve a ClassGUID--let's see if there's a Class name we can
|
|
// work with.
|
|
//
|
|
StringSize = sizeof(TempString);
|
|
if(CM_Get_DevInst_Registry_Property(DevInst,
|
|
CM_DRP_CLASS,
|
|
NULL,
|
|
TempString,
|
|
&StringSize,
|
|
0) == CR_SUCCESS) {
|
|
//
|
|
// OK, we found out the class name. Now see if we can find a
|
|
// single class GUID to match it.
|
|
//
|
|
if(SetupDiClassGuidsFromName(TempString, ClassGuid, 1, &NumGuids) && NumGuids) {
|
|
//
|
|
// We found exactly one, so we're happy.
|
|
//
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We have no idea what class of device this is, so use GUID_NULL.
|
|
//
|
|
CopyMemory(ClassGuid, &GUID_NULL, sizeof(GUID));
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupDiDeleteDeviceInfo(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine deletes a member from the specified device information set.
|
|
THIS DOES NOT DELETE ACTUAL DEVICES!
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - Supplies a handle to the device information set containing
|
|
the device information element to be deleted.
|
|
|
|
DeviceInfoData - Supplies a pointer to the SP_DEVINFO_DATA structure for
|
|
the device information element to be deleted.
|
|
|
|
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:
|
|
|
|
If the specified device information element is explicitly in use by a wizard
|
|
page, then the call will fail, and GetLastError will return
|
|
ERROR_DEVINFO_DATA_LOCKED. This will happen if a handle to a wizard page was
|
|
retrieved via SetupDiGetWizardPage, and this element was specified, along with
|
|
the DIWP_FLAG_USE_DEVINFO_DATA flag. In order to be able to delete this element,
|
|
the wizard HPROPSHEETPAGE handle must be closed (either explicitly, or after a
|
|
call to PropertySheet() completes).
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_INFO_SET pDeviceInfoSet;
|
|
DWORD Err;
|
|
PDEVINFO_ELEM ElemToDelete, PrevElem, NextElem;
|
|
|
|
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
Err = NO_ERROR;
|
|
|
|
try {
|
|
//
|
|
// Get a pointer to the element we are to delete.
|
|
//
|
|
ElemToDelete = FindAssociatedDevInfoElem(pDeviceInfoSet,
|
|
DeviceInfoData,
|
|
&PrevElem
|
|
);
|
|
if(ElemToDelete) {
|
|
//
|
|
// Make sure that this element isn't currently locked by
|
|
// a wizard page.
|
|
//
|
|
if(ElemToDelete->DiElemFlags & DIE_IS_LOCKED) {
|
|
Err = ERROR_DEVINFO_DATA_LOCKED;
|
|
goto clean0;
|
|
}
|
|
|
|
NextElem = ElemToDelete->Next;
|
|
|
|
//
|
|
// Destroy the devinfo element. We need to do this before
|
|
// altering the list, because we will be calling the class
|
|
// installer with DIF_DESTROYPRIVATEDATA, and it needs to
|
|
// be able to access this element (obviously).
|
|
//
|
|
DestroyDeviceInfoElement(DeviceInfoSet, pDeviceInfoSet, ElemToDelete);
|
|
|
|
//
|
|
// Now remove the element from the list.
|
|
//
|
|
if(PrevElem) {
|
|
PrevElem->Next = NextElem;
|
|
} else {
|
|
pDeviceInfoSet->DeviceInfoHead = NextElem;
|
|
}
|
|
|
|
if(!NextElem) {
|
|
pDeviceInfoSet->DeviceInfoTail = PrevElem;
|
|
}
|
|
|
|
MYASSERT(pDeviceInfoSet->DeviceInfoCount > 0);
|
|
pDeviceInfoSet->DeviceInfoCount--;
|
|
|
|
//
|
|
// If this element was the currently selected device for this
|
|
// set, then reset the device selection.
|
|
//
|
|
if(pDeviceInfoSet->SelectedDevInfoElem == ElemToDelete) {
|
|
pDeviceInfoSet->SelectedDevInfoElem = NULL;
|
|
}
|
|
|
|
} else {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
clean0: ; // nothing to do
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
UnlockDeviceInfoSet(pDeviceInfoSet);
|
|
|
|
SetLastError(Err);
|
|
return(Err == NO_ERROR);
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupDiEnumDeviceInfo(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN DWORD MemberIndex,
|
|
OUT PSP_DEVINFO_DATA DeviceInfoData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API enumerates the members of the specified device information set.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - Supplies a handle to the device information set whose members
|
|
are to be enumerated.
|
|
|
|
MemberIndex - Supplies the zero-based index of the device information member
|
|
to be retreived.
|
|
|
|
DeviceInfoData - Supplies a pointer to a SP_DEVINFO_DATA structure that will
|
|
receive information about this member.
|
|
|
|
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:
|
|
|
|
To enumerate device information members, an application should initially call
|
|
the SetupDiEnumDeviceInfo function with the MemberIndex parameter set to zero.
|
|
The application should then increment MemberIndex and call the
|
|
SetupDiEnumDeviceInfo function until there are no more values (i.e., the
|
|
function fails, and GetLastError returns ERROR_NO_MORE_ITEMS).
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_INFO_SET pDeviceInfoSet;
|
|
DWORD Err, i;
|
|
PDEVINFO_ELEM DevInfoElem;
|
|
|
|
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
Err = NO_ERROR;
|
|
|
|
try {
|
|
|
|
if(MemberIndex >= pDeviceInfoSet->DeviceInfoCount) {
|
|
Err = ERROR_NO_MORE_ITEMS;
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Find the element corresponding to the specified index.
|
|
//
|
|
DevInfoElem = pDeviceInfoSet->DeviceInfoHead;
|
|
for(i = 0; i < MemberIndex; i++) {
|
|
DevInfoElem = DevInfoElem->Next;
|
|
}
|
|
|
|
if(!(DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
|
|
DevInfoElem,
|
|
DeviceInfoData))) {
|
|
Err = ERROR_INVALID_USER_BUFFER;
|
|
}
|
|
|
|
clean0:
|
|
; // Nothing to do.
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
UnlockDeviceInfoSet(pDeviceInfoSet);
|
|
|
|
SetLastError(Err);
|
|
return(Err == NO_ERROR);
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupDiRegisterDeviceInfo(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN OUT PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN DWORD Flags,
|
|
IN PSP_DETSIG_CMPPROC CompareProc, OPTIONAL
|
|
IN PVOID CompareContext, OPTIONAL
|
|
OUT PSP_DEVINFO_DATA DupDeviceInfoData OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API registers a device instance with the Plug & Play Manager.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - Supplies a handle to the device information set that contains
|
|
the device information element for this device instance.
|
|
|
|
DeviceInfoData - Supplies a pointer to the SP_DEVINFO_DATA structure for the
|
|
device instance being registered. This is an IN OUT parameter, since the
|
|
DevInst field of the structure may be updated with a new handle value upon
|
|
return.
|
|
|
|
Flags - Controls how the device is to be registered. May be a combination of
|
|
the following values:
|
|
|
|
SPRDI_FIND_DUPS - Search for a previously-existing device instance
|
|
corresponding to this device information. If this
|
|
flag is not specified, the device instance will be
|
|
registered, regardless of whether a device instance
|
|
already exists for it.
|
|
|
|
CompareProc - Optionally, supplies a comparison callback function to be used in
|
|
duplicate detection. If specified, the function will be called for each
|
|
device instance that is of the same class as the device instance being
|
|
registered. The prototype of the callback function is as follows:
|
|
|
|
typedef DWORD (CALLBACK* PSP_DETSIG_CMPPROC)(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA NewDeviceData,
|
|
IN PSP_DEVINFO_DATA ExistingDeviceData,
|
|
IN PVOID CompareContext OPTIONAL
|
|
);
|
|
|
|
The compare function must return ERROR_DUPLICATE_FOUND if it finds the two
|
|
devices to be duplicates of each other, and NO_ERROR otherwise. If some
|
|
other error (e.g., out-of-memory) is encountered, the callback should return
|
|
the appropriate ERROR_* code indicating the failure that occurred.
|
|
|
|
If a CompareProc is not supplied, and duplicate detection is requested, then a
|
|
default comparison behavior will be used. (See pSetupDupDevCompare for details.)
|
|
|
|
CompareContext - Optionally, supplies the address of a caller-supplied context
|
|
buffer that will be passed into the compare callback routine. This parameter
|
|
is ignored if CompareProc is not supplied.
|
|
|
|
DupDeviceInfoData - Optionally, supplies a pointer to a device information
|
|
element that will be initialized for the duplicate device instance, if any,
|
|
discovered as a result of attempting to register this device. This will
|
|
be filled in if the function returns FALSE, and GetLastError returns
|
|
ERROR_DUPLICATE_FOUND. This device information element will be added as
|
|
a member of the specified DeviceInfoSet (if it wasn't already a member).
|
|
If DupDeviceInfoData is not supplied, then the duplicate WILL NOT be added
|
|
to the device information set.
|
|
|
|
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:
|
|
|
|
After registering a device information element, the caller should refresh any
|
|
stored copies of the devinst handle associated with this device, as the handle
|
|
value may have changed during registration. The caller need not re-retrieve
|
|
the SP_DEVINFO_DATA structure, because the devinst field of the DeviceInfoData
|
|
structure will be updated to reflect the current handle value. Also, the
|
|
SP_DEVINSTALL_PARAMS should be retrieved, because this will sometimes require
|
|
a reboot (i.e., DI_NEEDREBOOT flag is set).
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_INFO_SET pDeviceInfoSet;
|
|
DWORD Err;
|
|
PDEVINFO_ELEM DevInfoElem, CurDevInfoElem;
|
|
CONFIGRET cr;
|
|
ULONG DevIdBufferLen, ulStatus, ulProblem;
|
|
PTCHAR DevIdBuffer = NULL;
|
|
PTSTR CurDevId;
|
|
DEVINST ParentDevInst;
|
|
BOOL AlreadyPresent;
|
|
SP_DEVINFO_DATA CurDevInfoData;
|
|
TCHAR DeviceInstanceId[MAX_DEVICE_ID_LEN];
|
|
DEFAULT_DEVCMP_CONTEXT DevCmpContext;
|
|
LOG_CONF NewDevLogConfig;
|
|
RES_DES NewDevResDes;
|
|
|
|
if(Flags & ~SPRDI_FIND_DUPS) {
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
return FALSE;
|
|
}
|
|
|
|
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
Err = NO_ERROR;
|
|
|
|
//
|
|
// Initialize the following variables so we'll know whether we need to free any of their
|
|
// associated resources.
|
|
//
|
|
ZeroMemory(&DevCmpContext, sizeof(DevCmpContext));
|
|
NewDevLogConfig = (LOG_CONF)NULL;
|
|
NewDevResDes = (RES_DES)NULL;
|
|
|
|
try {
|
|
|
|
DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
|
|
DeviceInfoData,
|
|
NULL
|
|
);
|
|
if(!DevInfoElem) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
goto clean0;
|
|
} else if(DevInfoElem->DiElemFlags & DIE_IS_REGISTERED) {
|
|
//
|
|
// Nothing to do--it's already been registered.
|
|
//
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// If the caller requested duplicate detection then retrieve
|
|
// all device instances of this class, and compare each one
|
|
// with the device instance being registered.
|
|
//
|
|
if(Flags & SPRDI_FIND_DUPS) {
|
|
|
|
do {
|
|
|
|
if(CM_Get_Device_ID_List_Size(&DevIdBufferLen, NULL, CM_GETIDLIST_FILTER_NONE) != CR_SUCCESS) {
|
|
Err = ERROR_INVALID_DATA;
|
|
goto clean0;
|
|
} else if(!DevIdBufferLen) {
|
|
break;
|
|
}
|
|
|
|
if(!(DevIdBuffer = MyMalloc(DevIdBufferLen * sizeof(TCHAR)))) {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto clean0;
|
|
}
|
|
|
|
cr = CM_Get_Device_ID_List(NULL,
|
|
DevIdBuffer,
|
|
DevIdBufferLen,
|
|
CM_GETIDLIST_FILTER_NONE
|
|
);
|
|
if(cr == CR_BUFFER_SMALL) {
|
|
//
|
|
// This will only happen if a device instance was added between
|
|
// the time that we calculated the size, and when we attempted
|
|
// to retrieve the list. In this case, we'll simply retrieve
|
|
// the size again, and re-attempt to retrieve the list.
|
|
//
|
|
MyFree(DevIdBuffer);
|
|
DevIdBuffer = NULL;
|
|
} else if(cr != CR_SUCCESS) {
|
|
Err = ERROR_INVALID_DATA;
|
|
goto clean0;
|
|
}
|
|
|
|
} while(cr == CR_BUFFER_SMALL);
|
|
|
|
if(!DevIdBufferLen) {
|
|
goto NoDups;
|
|
}
|
|
|
|
//
|
|
// Initialize the structure to be used during duplicate comparison callback.
|
|
//
|
|
CurDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
|
|
|
//
|
|
// We have retrieved a list of every device instance in the system--now
|
|
// do the comparison for each one that matches the class of the device
|
|
// being registered.
|
|
//
|
|
|
|
if(!CompareProc) {
|
|
//
|
|
// We are supposed to do the comparisons, so set up to do our default comparison.
|
|
//
|
|
if((cr = CM_Get_First_Log_Conf(&NewDevLogConfig,
|
|
DevInfoElem->DevInst,
|
|
BOOT_LOG_CONF)) != CR_SUCCESS) {
|
|
//
|
|
// Ensure that our NewDevLogConfig handle is still NULL, so we won't try
|
|
// to free it.
|
|
//
|
|
NewDevLogConfig = (LOG_CONF)NULL;
|
|
|
|
if(cr == CR_INVALID_DEVINST) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
goto clean0;
|
|
} else {
|
|
//
|
|
// The only value we should get here is CR_NO_MORE_LOG_CONF.
|
|
// In this case, there is no comparison data, so we assume there is
|
|
// no possibility of duplication.
|
|
//
|
|
goto NoDups;
|
|
}
|
|
}
|
|
|
|
if(CM_Get_Next_Res_Des(&NewDevResDes,
|
|
NewDevLogConfig,
|
|
ResType_ClassSpecific,
|
|
NULL,
|
|
0) != CR_SUCCESS) {
|
|
//
|
|
// Ensure that our NewDevResDes is still NULL, so we won't try to free it.
|
|
//
|
|
NewDevResDes = (RES_DES)NULL;
|
|
|
|
//
|
|
// Since we can't retrieve the ResDes handle, assume there are no duplicates.
|
|
//
|
|
goto NoDups;
|
|
}
|
|
|
|
//
|
|
// Now retrieve the actual data for the ResDes.
|
|
//
|
|
do {
|
|
|
|
if((CM_Get_Res_Des_Data_Size(&DevCmpContext.CsResourceSize,
|
|
NewDevResDes,
|
|
0) != CR_SUCCESS) ||
|
|
!DevCmpContext.CsResourceSize) {
|
|
//
|
|
// Can't find out the size of the data, or there is none--assume no dups.
|
|
//
|
|
goto NoDups;
|
|
}
|
|
|
|
if(DevCmpContext.NewDevCsResource = MyMalloc(DevCmpContext.CsResourceSize)) {
|
|
|
|
if((cr = CM_Get_Res_Des_Data(NewDevResDes,
|
|
DevCmpContext.NewDevCsResource,
|
|
DevCmpContext.CsResourceSize,
|
|
0)) != CR_SUCCESS) {
|
|
|
|
if(cr == CR_BUFFER_SMALL) {
|
|
//
|
|
// Then someone increased the size of the resource data before we
|
|
// got a chance to read it. Free our buffer and try again.
|
|
//
|
|
MyFree(DevCmpContext.NewDevCsResource);
|
|
DevCmpContext.NewDevCsResource = NULL;
|
|
} else {
|
|
//
|
|
// Some other error occurred (highly unlikely). Assume no dups.
|
|
//
|
|
goto NoDups;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// not enough memory--this is bad enough for us to abort.
|
|
//
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto clean0;
|
|
}
|
|
|
|
} while(cr != CR_SUCCESS);
|
|
|
|
//
|
|
// We have successfully retrieved the class-specific resource data for the new
|
|
// device's boot LogConfig. Now allocate a buffer of the same size to store the
|
|
// corresponding resource data for each device instance we're comparing against.
|
|
// We don't have to worry about devices whose resource data is larger, because
|
|
// CM_Get_Res_Des_Data will do a partial fill to a buffer that's not large enough
|
|
// to contain the entire structure. Since our default comparison only compares
|
|
// the PnP detect signature (i.e., it ignores the legacy data at the very end of
|
|
// the buffer, we're guaranteed that we have enough data to make the determination.
|
|
//
|
|
if(!(DevCmpContext.CurDevCsResource = MyMalloc(DevCmpContext.CsResourceSize))) {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto clean0;
|
|
}
|
|
|
|
CompareProc = pSetupDupDevCompare;
|
|
CompareContext = &DevCmpContext;
|
|
}
|
|
|
|
for(CurDevId = DevIdBuffer;
|
|
*CurDevId;
|
|
CurDevId += lstrlen(CurDevId) + 1) {
|
|
|
|
Err = pSetupOpenAndAddNewDevInfoElem(pDeviceInfoSet,
|
|
CurDevId,
|
|
TRUE,
|
|
&(DevInfoElem->ClassGuid),
|
|
pDeviceInfoSet->InstallParamBlock.hwndParent,
|
|
&CurDevInfoElem,
|
|
TRUE,
|
|
&AlreadyPresent,
|
|
0
|
|
);
|
|
|
|
if(Err == ERROR_NOT_ENOUGH_MEMORY) {
|
|
//
|
|
// Out-of-memory error is the only one bad enough to get us to abort.
|
|
//
|
|
goto clean0;
|
|
} else if(Err != NO_ERROR) {
|
|
//
|
|
// Just ignore this device instance, and move on to the next.
|
|
//
|
|
Err = NO_ERROR;
|
|
continue;
|
|
}
|
|
|
|
DevInfoDataFromDeviceInfoElement(pDeviceInfoSet, CurDevInfoElem, &CurDevInfoData);
|
|
|
|
//
|
|
// We now have the possible duplicate in our set. Call the comparison callback
|
|
// routine.
|
|
//
|
|
Err = CompareProc(DeviceInfoSet, DeviceInfoData, &CurDevInfoData, CompareContext);
|
|
|
|
//
|
|
// If the device instance was created temporarily for the comparison, then it
|
|
// may need to be destroyed. It should be destroyed if it wasn't a duplicate,
|
|
// or if the duplicate output parameter wasn't supplied.
|
|
//
|
|
if(!AlreadyPresent) {
|
|
if((Err != ERROR_DUPLICATE_FOUND) || !DupDeviceInfoData) {
|
|
SetupDiDeleteDeviceInfo(DeviceInfoSet, &CurDevInfoData);
|
|
}
|
|
}
|
|
|
|
if(Err != NO_ERROR) {
|
|
goto clean0;
|
|
}
|
|
}
|
|
}
|
|
|
|
NoDups:
|
|
|
|
#if 1 // New code that avoids reenumeration of Root to register new device
|
|
|
|
//
|
|
// To turn this phantom device instance into a 'live' device instance, we simply call
|
|
// CM_Create_DevInst, which does the right thing (without reenumerating the whole
|
|
// hardware tree!).
|
|
//
|
|
CM_Get_Device_ID(DevInfoElem->DevInst,
|
|
DeviceInstanceId,
|
|
SIZECHARS(DeviceInstanceId),
|
|
0
|
|
);
|
|
|
|
CM_Get_Parent(&ParentDevInst, DevInfoElem->DevInst, 0);
|
|
|
|
if(CM_Create_DevInst(&(DevInfoElem->DevInst),
|
|
DeviceInstanceId,
|
|
ParentDevInst,
|
|
CM_CREATE_DEVINST_NORMAL |
|
|
CM_CREATE_DEVINST_DO_NOT_INSTALL) == CR_SUCCESS) {
|
|
//
|
|
// Device is no longer a phantom!
|
|
//
|
|
DevInfoElem->DiElemFlags &= ~DIE_IS_PHANTOM;
|
|
} else {
|
|
//
|
|
// This should never happen!
|
|
//
|
|
Err = ERROR_NO_SUCH_DEVINST;
|
|
goto clean0;
|
|
}
|
|
|
|
#else // Disable old (slow) code that had to do full enumeration to register the new device.
|
|
|
|
//
|
|
// No duplicate device instances were found--we may register this device.
|
|
// To do this, we re-enumerate the device instance so that it is no longer
|
|
// a phantom, then we mark the element as having been registered.
|
|
//
|
|
// (The logic for this was based on the behavior of the DICS_PROPCHANGE
|
|
// event in SetupDiChangeState.)
|
|
//
|
|
if(CM_Query_Remove_SubTree(DevInfoElem->DevInst, CM_QUERY_REMOVE_UI_OK) == CR_SUCCESS) {
|
|
//
|
|
// We will now attempt to turn the phantom devinst into a real one.
|
|
// In preparation, reset the 'is phantom' flag.
|
|
//
|
|
DevInfoElem->DiElemFlags &= ~DIE_IS_PHANTOM;
|
|
|
|
//
|
|
// Retrieve the name of the device instance. This is necessary, because
|
|
// we're about to remove the DEVINST so that it can be re-enumerated. This
|
|
// should never fail.
|
|
//
|
|
CM_Get_Device_ID(DevInfoElem->DevInst,
|
|
DeviceInstanceId,
|
|
SIZECHARS(DeviceInstanceId),
|
|
0
|
|
);
|
|
|
|
CM_Get_Parent(&ParentDevInst, DevInfoElem->DevInst, 0);
|
|
CM_Remove_SubTree(DevInfoElem->DevInst, CM_REMOVE_UI_OK);
|
|
CM_Reenumerate_DevInst(ParentDevInst, CM_REENUMERATE_SYNCHRONOUS);
|
|
DevInfoElem->DevInst = (DEVINST)0;
|
|
|
|
if(CM_Locate_DevInst(&(DevInfoElem->DevInst),
|
|
(DEVINSTID)DeviceInstanceId,
|
|
CM_LOCATE_DEVINST_NORMAL) != CR_SUCCESS) {
|
|
//
|
|
// For some reason, the device instance couldn't be created. We'll have
|
|
// to retrieve it as a phantom instance, and set the 'need reboot' flag.
|
|
// (This should always work.)
|
|
//
|
|
CM_Locate_DevInst(&(DevInfoElem->DevInst),
|
|
(DEVINSTID)DeviceInstanceId,
|
|
CM_LOCATE_DEVINST_PHANTOM
|
|
);
|
|
|
|
DevInfoElem->InstallParamBlock.Flags |= DI_NEEDREBOOT;
|
|
DevInfoElem->DiElemFlags |= DIE_IS_PHANTOM;
|
|
}
|
|
|
|
//
|
|
// Update the DevInst field of the DeviceInfoData structure to reflect the
|
|
// new value of the devinst handle.
|
|
//
|
|
DeviceInfoData->DevInst = DevInfoElem->DevInst;
|
|
|
|
} else {
|
|
DevInfoElem->InstallParamBlock.Flags |= DI_NEEDREBOOT;
|
|
}
|
|
|
|
#endif // end of old (slow) code
|
|
|
|
DevInfoElem->DiElemFlags |= DIE_IS_REGISTERED;
|
|
|
|
clean0:
|
|
; // Nothing to do.
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
//
|
|
// Access the following variables so the compiler will respect our statement
|
|
// ordering in the try clause.
|
|
//
|
|
DevIdBuffer = DevIdBuffer;
|
|
DevCmpContext.NewDevCsResource = DevCmpContext.NewDevCsResource;
|
|
DevCmpContext.CurDevCsResource = DevCmpContext.CurDevCsResource;
|
|
NewDevLogConfig = NewDevLogConfig;
|
|
NewDevResDes = NewDevResDes;
|
|
}
|
|
|
|
if(DevIdBuffer) {
|
|
MyFree(DevIdBuffer);
|
|
}
|
|
|
|
if(DevCmpContext.NewDevCsResource) {
|
|
MyFree(DevCmpContext.NewDevCsResource);
|
|
}
|
|
|
|
if(DevCmpContext.CurDevCsResource) {
|
|
MyFree(DevCmpContext.CurDevCsResource);
|
|
}
|
|
|
|
if(NewDevResDes) {
|
|
CM_Free_Res_Des_Handle(NewDevResDes);
|
|
}
|
|
|
|
if(NewDevLogConfig) {
|
|
CM_Free_Log_Conf_Handle(NewDevLogConfig);
|
|
}
|
|
|
|
if((Err == ERROR_DUPLICATE_FOUND) && DupDeviceInfoData) {
|
|
//
|
|
// The user supplied a buffer to receive the SP_DEVINFO_DATA
|
|
// structure for the duplicate.
|
|
//
|
|
try {
|
|
|
|
if(!(DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
|
|
CurDevInfoElem,
|
|
DupDeviceInfoData))) {
|
|
Err = ERROR_INVALID_USER_BUFFER;
|
|
}
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_USER_BUFFER;
|
|
}
|
|
}
|
|
|
|
UnlockDeviceInfoSet(pDeviceInfoSet);
|
|
|
|
SetLastError(Err);
|
|
return(Err == NO_ERROR);
|
|
}
|
|
|
|
|
|
DWORD
|
|
pSetupOpenAndAddNewDevInfoElem(
|
|
IN PDEVICE_INFO_SET DeviceInfoSet,
|
|
IN PCTSTR DeviceInstanceId,
|
|
IN BOOL AllowPhantom,
|
|
IN LPGUID ClassGuid, OPTIONAL
|
|
IN HWND hwndParent, OPTIONAL
|
|
OUT PDEVINFO_ELEM *DevInfoElem,
|
|
IN BOOL CheckIfAlreadyPresent,
|
|
OUT PBOOL AlreadyPresent, OPTIONAL
|
|
IN ULONG CmLocateFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens a DEVINST handle to an existing device instance, and
|
|
creates a new device information element for it. This element is added
|
|
to the specified device information set.
|
|
ASSUMES THAT THE CALLING ROUTINE HAS ALREADY ACQUIRED THE LOCK!
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - Device information set to add the new element to.
|
|
|
|
DeviceInstanceId - Supplies the name of the device instance to be opened.
|
|
|
|
AllowPhantom - Specifies whether or not phantom device instances should be
|
|
allowed. If this flag is not set, and the specified device instance is
|
|
not currently active, then the routine will fail with ERROR_NO_SUCH_DEVINST.
|
|
|
|
ClassGuid - Optionally, supplies the class that the specified device instance
|
|
must be in order to be added to the set. If the device instance is found
|
|
to be of some class other than the one specified, then the call will fail with
|
|
ERROR_CLASS_MISMATCH. If this parameter is not specified, then the only check
|
|
that will be done on the device's class is to make sure that it matches the
|
|
class of the set (if the set has an associated class).
|
|
|
|
hwndParent - Optionally, supplies the handle to the top level window for
|
|
UI relating to this element.
|
|
|
|
DevInfoElem - Optionally, supplies the address of the variable that
|
|
receives a pointer to the newly-allocated device information element.
|
|
|
|
CheckIfAlreadyThere - Specifies whether this routine should check to see whether
|
|
the device instance is already in the specified devinfo set.
|
|
|
|
AlreadyPresent - Optionally, supplies the address of a boolean variable
|
|
that is set to indicate whether or not the specified device instance
|
|
was already in the device information set. If CheckIfAlreadyThere is FALSE,
|
|
then this parameter is ignored.
|
|
|
|
CmLocateFlags - Supplies additional flags to be passed to CM_Locate_DevInst.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is NO_ERROR, otherwise the
|
|
ERROR_* code is returned.
|
|
|
|
--*/
|
|
{
|
|
CONFIGRET cr;
|
|
DEVINST DevInst;
|
|
DWORD Err, DiElemFlags;
|
|
GUID GuidBuffer;
|
|
|
|
if((cr = CM_Locate_DevInst(&DevInst,
|
|
(DEVINSTID)DeviceInstanceId,
|
|
CM_LOCATE_DEVINST_NORMAL | CmLocateFlags)) == CR_SUCCESS) {
|
|
|
|
DiElemFlags = DIE_IS_REGISTERED;
|
|
|
|
} else {
|
|
|
|
if(cr == CR_INVALID_DEVICE_ID) {
|
|
return ERROR_INVALID_DEVINST_NAME;
|
|
} else if(!AllowPhantom) {
|
|
return ERROR_NO_SUCH_DEVINST;
|
|
}
|
|
|
|
//
|
|
// It could be that the device instance is present in the registry, but
|
|
// not currently 'live'. If this is the case, we'll be able to get a
|
|
// handle to it by locating it as a phantom device instance.
|
|
//
|
|
if(CM_Locate_DevInst(&DevInst,
|
|
(DEVINSTID)DeviceInstanceId,
|
|
CM_LOCATE_DEVINST_PHANTOM | CmLocateFlags) != CR_SUCCESS) {
|
|
|
|
return ERROR_NO_SUCH_DEVINST;
|
|
}
|
|
|
|
DiElemFlags = DIE_IS_REGISTERED | DIE_IS_PHANTOM;
|
|
}
|
|
|
|
//
|
|
// If requested, search through the current list of device information elements
|
|
// to see if this element already exists.
|
|
//
|
|
if(CheckIfAlreadyPresent) {
|
|
|
|
if(*DevInfoElem = FindDevInfoByDevInst(DeviceInfoSet, DevInst, NULL)) {
|
|
//
|
|
// Make sure that this device instance is of the proper class, if a class GUID
|
|
// filter was supplied.
|
|
//
|
|
if(ClassGuid && !IsEqualGUID(ClassGuid, &((*DevInfoElem)->ClassGuid))) {
|
|
return ERROR_CLASS_MISMATCH;
|
|
}
|
|
|
|
if(AlreadyPresent) {
|
|
*AlreadyPresent = TRUE;
|
|
}
|
|
return NO_ERROR;
|
|
|
|
} else if(AlreadyPresent) {
|
|
*AlreadyPresent = FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Retrieve the class GUID for this device instance.
|
|
//
|
|
if((Err = pSetupClassGuidFromDevInst(DevInst, &GuidBuffer)) != NO_ERROR) {
|
|
return Err;
|
|
}
|
|
|
|
//
|
|
// If a class GUID filter was specified, then make sure that it matches the
|
|
// class GUID for this device instance.
|
|
//
|
|
if(ClassGuid && !IsEqualGUID(ClassGuid, &GuidBuffer)) {
|
|
return ERROR_CLASS_MISMATCH;
|
|
}
|
|
|
|
return pSetupAddNewDeviceInfoElement(DeviceInfoSet,
|
|
DevInst,
|
|
&GuidBuffer,
|
|
NULL,
|
|
hwndParent,
|
|
DiElemFlags,
|
|
DevInfoElem
|
|
);
|
|
}
|
|
|
|
|
|
DWORD
|
|
pSetupDupDevCompare(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA NewDeviceData,
|
|
IN PSP_DEVINFO_DATA ExistingDeviceData,
|
|
IN PVOID CompareContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the default comparison routine for SetupDiRegisterDeviceInfo.
|
|
It is used to determine whether the new device (i.e., the one being registered) is
|
|
a duplicate of an existing device.
|
|
|
|
The current algorithm for duplicate detection is as follows:
|
|
|
|
Compare the BOOT_LOG_CONF logical configurations for the two devices. Two
|
|
resource types are used in this comparison--ResType_IO and ResType_ClassSpecific.
|
|
The IO ranges, if any, for the two devices will be compared to see if they're
|
|
identical. Also, if the devices have a class-specific resource, then the
|
|
CSD_ClassGuid, and the Plug&Play detect signature in CSD_Signature will be
|
|
binary-compared.
|
|
|
|
BUGBUG (lonnym): presently, the LogConfig only supports the class-specific resource,
|
|
so I/O resource comparison is not done.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - Supplies the handle of the device information set containing both devices
|
|
being compared.
|
|
|
|
NewDeviceData - Supplies the address of the SP_DEVINFO_DATA for the device being registered.
|
|
|
|
ExistingDeviceData - Supplies the address of the SP_DEVINFO_DATA for the existing device with
|
|
which the new device is being compared.
|
|
|
|
CompareContext - Supplies the address of a context buffer used during the comparison. This
|
|
buffer is actually a DEFAULT_DEVCMP_CONTEXT structure, defined as follows:
|
|
|
|
typedef struct _DEFAULT_DEVCMP_CONTEXT {
|
|
|
|
PCS_RESOURCE NewDevCsResource;
|
|
PCS_RESOURCE CurDevCsResource;
|
|
ULONG CsResourceSize;
|
|
|
|
} DEFAULT_DEVCMP_CONTEXT, *PDEFAULT_DEVCMP_CONTEXT;
|
|
|
|
NewDevCsResource points to the class-specific resource buffer for the new device.
|
|
CurDevCsResource points to a working buffer that should be used to retrieve the
|
|
class-specific resource for the existing device.
|
|
CsResourceSize supplies the size in bytes of these two buffers (they're both the
|
|
same size).
|
|
|
|
Return Value:
|
|
|
|
If the two devices are not duplicates of each other, the return value is NO_ERROR.
|
|
If the two devices are duplicates of each other, the return value is ERROR_DUPLICATE_FOUND.
|
|
|
|
--*/
|
|
{
|
|
LOG_CONF ExistingDeviceLogConfig;
|
|
RES_DES ExistingDeviceResDes;
|
|
CONFIGRET cr;
|
|
PDEFAULT_DEVCMP_CONTEXT DevCmpContext;
|
|
PCS_DES NewCsDes, ExistingCsDes;
|
|
DWORD Err;
|
|
|
|
//
|
|
// First, retrieve the boot LogConfig for the existing device.
|
|
//
|
|
if(CM_Get_First_Log_Conf(&ExistingDeviceLogConfig,
|
|
ExistingDeviceData->DevInst,
|
|
BOOT_LOG_CONF) != CR_SUCCESS) {
|
|
//
|
|
// Couldn't get the boot LogConfig--assume this device isn't a duplicate.
|
|
//
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Assume there are no duplicates.
|
|
//
|
|
Err = NO_ERROR;
|
|
|
|
//
|
|
// Now, retrieve the the ResDes handle for the class-specific resource.
|
|
//
|
|
if(CM_Get_Next_Res_Des(&ExistingDeviceResDes,
|
|
ExistingDeviceLogConfig,
|
|
ResType_ClassSpecific,
|
|
NULL,
|
|
0) != CR_SUCCESS) {
|
|
//
|
|
// Couldn't get the class-specific ResDes handle--assume this device isn't a duplicate
|
|
//
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Now, retrieve the actual data associated with this ResDes. Note that we don't care if
|
|
// we get a CR_BUFFER_SMALL error, because we are guaranteed that we got back at least the
|
|
// amount of data that we have for the new device. That's all we need to do our comparison.
|
|
//
|
|
DevCmpContext = (PDEFAULT_DEVCMP_CONTEXT)CompareContext;
|
|
|
|
cr = CM_Get_Res_Des_Data(ExistingDeviceResDes,
|
|
DevCmpContext->CurDevCsResource,
|
|
DevCmpContext->CsResourceSize,
|
|
0
|
|
);
|
|
|
|
if((cr == CR_SUCCESS) || (cr == CR_BUFFER_SMALL)) {
|
|
//
|
|
// We got _at least_ enough of the buffer to do the comparison.
|
|
//
|
|
NewCsDes = &(DevCmpContext->NewDevCsResource->CS_Header);
|
|
ExistingCsDes = &(DevCmpContext->CurDevCsResource->CS_Header);
|
|
|
|
//
|
|
// First, see if the Plug&Play detect signatures are both the same size.
|
|
//
|
|
if(NewCsDes->CSD_SignatureLength == ExistingCsDes->CSD_SignatureLength) {
|
|
//
|
|
// See if the class GUIDs are the same.
|
|
//
|
|
if(IsEqualGUID(&(NewCsDes->CSD_ClassGuid), &(ExistingCsDes->CSD_ClassGuid))) {
|
|
//
|
|
// Finally, see if the PnP detect signatures are identical
|
|
//
|
|
if(!memcmp(NewCsDes->CSD_Signature,
|
|
ExistingCsDes->CSD_Signature,
|
|
NewCsDes->CSD_SignatureLength)) {
|
|
//
|
|
// We have ourselves a duplicate!
|
|
//
|
|
Err = ERROR_DUPLICATE_FOUND;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CM_Free_Res_Des_Handle(ExistingDeviceResDes);
|
|
|
|
clean0:
|
|
CM_Free_Log_Conf_Handle(ExistingDeviceLogConfig);
|
|
|
|
return Err;
|
|
}
|
|
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// ANSI version
|
|
//
|
|
BOOL
|
|
WINAPI
|
|
SetupDiGetDeviceInstanceIdA(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
OUT PSTR DeviceInstanceId,
|
|
IN DWORD DeviceInstanceIdSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
{
|
|
WCHAR deviceInstanceId[MAX_DEVICE_ID_LEN];
|
|
PSTR deviceInstanceIdA;
|
|
DWORD AnsiLength;
|
|
BOOL b;
|
|
DWORD rc;
|
|
DWORD requiredSize;
|
|
|
|
b = SetupDiGetDeviceInstanceIdW(
|
|
DeviceInfoSet,
|
|
DeviceInfoData,
|
|
deviceInstanceId,
|
|
MAX_DEVICE_ID_LEN,
|
|
&requiredSize
|
|
);
|
|
|
|
if(!b) {
|
|
return(FALSE);
|
|
}
|
|
|
|
rc = GetLastError();
|
|
|
|
if(deviceInstanceIdA = UnicodeToAnsi(deviceInstanceId)) {
|
|
|
|
AnsiLength = lstrlenA(deviceInstanceIdA) + 1;
|
|
|
|
if(RequiredSize) {
|
|
try {
|
|
*RequiredSize = AnsiLength;
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
b = FALSE;
|
|
}
|
|
}
|
|
|
|
if(DeviceInstanceIdSize >= AnsiLength) {
|
|
|
|
if(!lstrcpyA(DeviceInstanceId,deviceInstanceIdA)) {
|
|
//
|
|
// lstrcpy faulted; assume caller's pointer invalid
|
|
//
|
|
rc = ERROR_INVALID_USER_BUFFER;
|
|
b = FALSE;
|
|
}
|
|
} else {
|
|
rc = ERROR_INSUFFICIENT_BUFFER;
|
|
b = FALSE;
|
|
}
|
|
|
|
MyFree(deviceInstanceIdA);
|
|
|
|
} else {
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
b = FALSE;
|
|
}
|
|
|
|
SetLastError(rc);
|
|
return(b);
|
|
}
|
|
#else
|
|
//
|
|
// Unicode version
|
|
//
|
|
BOOL
|
|
WINAPI
|
|
SetupDiGetDeviceInstanceIdW(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
OUT PWSTR DeviceInstanceId,
|
|
IN DWORD DeviceInstanceIdSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(DeviceInfoSet);
|
|
UNREFERENCED_PARAMETER(DeviceInfoData);
|
|
UNREFERENCED_PARAMETER(DeviceInstanceId);
|
|
UNREFERENCED_PARAMETER(DeviceInstanceIdSize);
|
|
UNREFERENCED_PARAMETER(RequiredSize);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupDiGetDeviceInstanceId(
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
OUT PTSTR DeviceInstanceId,
|
|
IN DWORD DeviceInstanceIdSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine retrieves the device instance ID associated with a device
|
|
information element.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet - Supplies a handle to the device information set containing
|
|
the device information element whose ID is to be retrieved.
|
|
|
|
DeviceInfoData - Supplies a pointer to the SP_DEVINFO_DATA structure for
|
|
the device information element whose ID is to be retrieved.
|
|
|
|
DeviceInstanceId - Supplies the address of a character buffer that will
|
|
receive the ID for the specified device information element.
|
|
|
|
DeviceInstanceIdSize - Supplies the size, in characters, of the DeviceInstanceId
|
|
buffer.
|
|
|
|
RequiredSize - Optionally, supplies the address of a variable that receives the
|
|
number of characters required to store the device instance ID.
|
|
|
|
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;
|
|
ULONG ulLen;
|
|
|
|
if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
Err = NO_ERROR;
|
|
|
|
try {
|
|
//
|
|
// Get a pointer to the element whose ID we are to retrieve.
|
|
//
|
|
if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
|
|
DeviceInfoData,
|
|
NULL))) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Find out how large the buffer needs to be. We always have to
|
|
// make this call first, because CM_Get_Device_ID doesn't return
|
|
// a CR_BUFFER_SMALL error if there isn't room for the terminating
|
|
// NULL.
|
|
//
|
|
if((cr = CM_Get_Device_ID_Size(&ulLen,
|
|
DevInfoElem->DevInst,
|
|
0)) == CR_SUCCESS) {
|
|
//
|
|
// The size returned from CM_Get_Device_ID_Size doesn't include
|
|
// the terminating NULL.
|
|
//
|
|
ulLen++;
|
|
|
|
} else {
|
|
|
|
Err = (cr == CR_INVALID_DEVINST) ? ERROR_NO_SUCH_DEVINST
|
|
: ERROR_INVALID_PARAMETER;
|
|
goto clean0;
|
|
}
|
|
|
|
if(RequiredSize) {
|
|
*RequiredSize = ulLen;
|
|
}
|
|
|
|
if(DeviceInstanceIdSize < ulLen) {
|
|
Err = ERROR_INSUFFICIENT_BUFFER;
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Now retrieve the ID.
|
|
//
|
|
if((cr = CM_Get_Device_ID(DevInfoElem->DevInst,
|
|
DeviceInstanceId,
|
|
DeviceInstanceIdSize,
|
|
0)) != CR_SUCCESS) {
|
|
switch(cr) {
|
|
|
|
case CR_INVALID_POINTER :
|
|
Err = ERROR_INVALID_USER_BUFFER;
|
|
break;
|
|
|
|
default :
|
|
//
|
|
// Should never hit this!
|
|
//
|
|
Err = ERROR_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
clean0: ; // nothing to do.
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
UnlockDeviceInfoSet(pDeviceInfoSet);
|
|
|
|
SetLastError(Err);
|
|
return(Err == NO_ERROR);
|
|
}
|
|
|