725 lines
25 KiB
C
725 lines
25 KiB
C
/*++
|
|
|
|
Copyright (c) 2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
devenum.c
|
|
|
|
Abstract:
|
|
|
|
Code for enum IDE ans SCSI controllers and attached to them storage devices
|
|
and calculate for them SCSI Address.
|
|
|
|
Author:
|
|
|
|
Souren Aghajanyan (sourenag) 05-June-2001
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include "devenum.h"
|
|
|
|
typedef struct tagIDEController
|
|
{
|
|
PCTSTR pnpId;
|
|
UINT defaultSCSIPort;
|
|
}IDE_CONTROLLER, *PIDE_CONTROLLER;
|
|
|
|
#define DEVICE_CURRENT_DRIVE_LETTER_TEXT_ASSIGNMENT TEXT("CurrentDriveLetterAssignment")
|
|
|
|
IDE_CONTROLLER g_knownIDEControllers[] =
|
|
{
|
|
{TEXT("MF\\GOODPRIMARY"), 0},
|
|
{TEXT("MF\\GOODSECONDARY"), 1},
|
|
{TEXT("*PNP0600"), 1}
|
|
};
|
|
|
|
PCTSTR
|
|
pRegQueryStringValue(
|
|
IN HKEY hKey,
|
|
IN PCTSTR ValueName,
|
|
OUT PVOID Buffer,
|
|
IN UINT BufferSize
|
|
)
|
|
{
|
|
static TCHAR defaultBuffer[MAX_REG_SIZE];
|
|
DWORD valueType;
|
|
|
|
MYASSERT((hKey && ValueName) && ((Buffer && BufferSize) || (!Buffer)));
|
|
|
|
if(!Buffer){
|
|
Buffer = (PVOID)defaultBuffer;
|
|
BufferSize = sizeof(defaultBuffer);
|
|
}
|
|
|
|
if(ERROR_SUCCESS != RegQueryValueEx(hKey,
|
|
ValueName,
|
|
0,
|
|
&valueType,
|
|
(PBYTE)Buffer,
|
|
(PULONG)&BufferSize) ||
|
|
REG_SZ != valueType){
|
|
return NULL;
|
|
}
|
|
|
|
return (PCTSTR)Buffer;
|
|
}
|
|
|
|
BOOL
|
|
pDoesDriveExist(
|
|
IN HKEY hDevice,
|
|
OUT DWORD* DriveType
|
|
)
|
|
{
|
|
DWORD driveType;
|
|
PCTSTR pBufferKeyValue;
|
|
TCHAR drivePath[] = TEXT("?:\\");
|
|
BOOL bCDROMDevice = TRUE;
|
|
|
|
if(!hDevice){
|
|
return FALSE;
|
|
}
|
|
|
|
pBufferKeyValue = pRegQueryStringValue(hDevice, TEXT("Class"), NULL, 0);
|
|
if(!pBufferKeyValue){
|
|
return FALSE;
|
|
}
|
|
|
|
bCDROMDevice = !_tcsicmp(pBufferKeyValue, TEXT("CDROM"));
|
|
|
|
pBufferKeyValue = pRegQueryStringValue(hDevice, DEVICE_CURRENT_DRIVE_LETTER_TEXT_ASSIGNMENT, NULL, 0);
|
|
if(!pBufferKeyValue){
|
|
return FALSE;
|
|
}
|
|
|
|
drivePath[0] = pBufferKeyValue[0];
|
|
driveType = GetDriveType(drivePath);
|
|
|
|
if(DriveType){
|
|
*DriveType = driveType;
|
|
}
|
|
|
|
return bCDROMDevice? (DRIVE_CDROM == driveType):
|
|
(DRIVE_NO_ROOT_DIR != driveType && DRIVE_UNKNOWN != driveType);
|
|
}
|
|
|
|
BOOL
|
|
pGetDeviceType(
|
|
IN HKEY hDevice,
|
|
OUT DWORD* DriveType
|
|
)
|
|
{
|
|
|
|
if(!DriveType){
|
|
return FALSE;
|
|
}
|
|
|
|
return pDoesDriveExist(hDevice, DriveType);
|
|
}
|
|
|
|
VOID
|
|
pPreparePNPIDName(
|
|
IN PTSTR deviceInfoRegKey
|
|
)
|
|
{
|
|
MYASSERT(deviceInfoRegKey);
|
|
//
|
|
// Replace '\\' with '&' in registry key to make PNPID
|
|
//
|
|
|
|
while(deviceInfoRegKey = _tcschr(deviceInfoRegKey, '\\')){
|
|
*deviceInfoRegKey = '&';
|
|
}
|
|
}
|
|
|
|
int __cdecl
|
|
pControllerInfoCompare(
|
|
IN const void * elem1,
|
|
IN const void * elem2
|
|
)
|
|
{
|
|
MYASSERT(elem1 && elem2);
|
|
|
|
//
|
|
// Sort controlers in next order: First IDE, after SCSI,
|
|
// inside each group(IDE and SCSI) sort by preliminary defined SCSIPortNumber
|
|
//
|
|
|
|
#define PCONTROLLER_INFO_CAST(x) ((PCONTROLLER_INFO)x)
|
|
|
|
if(PCONTROLLER_INFO_CAST(elem1)->ControllerType > PCONTROLLER_INFO_CAST(elem2)->ControllerType){
|
|
return 1;
|
|
}
|
|
if(PCONTROLLER_INFO_CAST(elem1)->ControllerType < PCONTROLLER_INFO_CAST(elem2)->ControllerType){
|
|
return -1;
|
|
}
|
|
if(PCONTROLLER_INFO_CAST(elem1)->SCSIPortNumber > PCONTROLLER_INFO_CAST(elem2)->SCSIPortNumber){
|
|
return 1;
|
|
}
|
|
if(PCONTROLLER_INFO_CAST(elem1)->SCSIPortNumber < PCONTROLLER_INFO_CAST(elem2)->SCSIPortNumber){
|
|
return -1;
|
|
}
|
|
MYASSERT(INVALID_SCSI_PORT == PCONTROLLER_INFO_CAST(elem1)->SCSIPortNumber);
|
|
return 0;
|
|
}
|
|
|
|
BOOL
|
|
pGatherControllersInfo(
|
|
IN OUT PCONTROLLER_INFO ActiveControllersOut,
|
|
IN OUT PUINT NumberOfActiveControllersOut
|
|
)
|
|
{
|
|
TCHAR regkeyName[MAX_REG_SIZE];
|
|
TCHAR deviceInfoRegKey[MAX_REG_SIZE];
|
|
TCHAR deviceData[MAX_REG_SIZE];
|
|
TCHAR ideHardwareID[MAX_PNPID_SIZE];
|
|
HKEY hActiveDevicesRoot = NULL;
|
|
HKEY hActiveDeviceRoot = NULL;
|
|
HKEY hDevice = NULL;
|
|
UINT itemIndexRoot;
|
|
DWORD bufferLength;
|
|
PTSTR pDelimeter;
|
|
UINT indexAvailable = 0;
|
|
UINT scsiPortNumber;
|
|
UINT controllerStartIndex = 0;
|
|
UINT controllersSubNumber;
|
|
PCONTROLLER_INFO controllerInfo;
|
|
UINT i;
|
|
UINT j;
|
|
CONTROLLER_TYPE deviceType;
|
|
BOOL bROOTDevice;
|
|
UINT ideCounter;
|
|
DWORD rcResult;
|
|
static CONTROLLER_TYPE controllerTypes[] = {CONTROLLER_ON_BOARD_IDE, CONTROLLER_EXTRA_IDE, CONTROLLER_SCSI};
|
|
|
|
if(!NumberOfActiveControllersOut){
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
__try{
|
|
if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_DYN_DATA, TEXT("Config Manager\\Enum"), 0, KEY_READ, &hActiveDevicesRoot)){
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Looking for IDE and SCSI controllers in list of active hardware
|
|
// under "HKDD\Config Manager\Enum"
|
|
//
|
|
for(itemIndexRoot = 0; ;itemIndexRoot++){
|
|
bufferLength = ARRAYSIZE(regkeyName);
|
|
|
|
rcResult = RegEnumKeyEx(hActiveDevicesRoot,
|
|
itemIndexRoot,
|
|
regkeyName,
|
|
&bufferLength,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
if(ERROR_SUCCESS != rcResult){
|
|
break;
|
|
}
|
|
|
|
if(ERROR_SUCCESS != RegOpenKeyEx(hActiveDevicesRoot, regkeyName, 0, KEY_READ, &hActiveDeviceRoot)){
|
|
continue;
|
|
}
|
|
|
|
do{
|
|
//
|
|
// "HardWareKey" consist key path to real device
|
|
//
|
|
if(pRegQueryStringValue(hActiveDeviceRoot,
|
|
TEXT("HardWareKey"),
|
|
regkeyName,
|
|
sizeof(regkeyName))){
|
|
if(!_tcsnicmp(regkeyName, TEXT("ROOT"), 4)){
|
|
//
|
|
// Sometime on board IDE controllers has preserved PNPID under ROOT,
|
|
// and is not represented in MF\CHILD000x.
|
|
//
|
|
bROOTDevice = TRUE;
|
|
deviceType = CONTROLLER_ON_BOARD_IDE;
|
|
}else
|
|
{
|
|
if(!_tcsnicmp(regkeyName, TEXT("MF\\CHILD"), 8)){
|
|
deviceType = CONTROLLER_ON_BOARD_IDE;
|
|
}else if(!_tcsnicmp(regkeyName, TEXT("PCI"), 3)){
|
|
deviceType = CONTROLLER_SCSI;
|
|
}else{
|
|
//deviceType = CONTROLLER_UNKNOWN;
|
|
break;
|
|
}
|
|
bROOTDevice = FALSE;
|
|
}
|
|
|
|
_tcscpy(deviceInfoRegKey, TEXT("Enum\\"));
|
|
_tcscat(deviceInfoRegKey, regkeyName);
|
|
//
|
|
// Open reg key where resides all device infomation
|
|
//
|
|
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, deviceInfoRegKey, 0, KEY_READ, &hDevice)){
|
|
controllerInfo = ActiveControllersOut + indexAvailable;
|
|
//
|
|
// Replace '\\' with '&' in registry key to make PNPID
|
|
//
|
|
pPreparePNPIDName(regkeyName);
|
|
|
|
switch(deviceType){
|
|
case CONTROLLER_ON_BOARD_IDE:
|
|
{
|
|
if(pRegQueryStringValue(hDevice,
|
|
TEXT("HardwareID"),
|
|
ideHardwareID,
|
|
sizeof(deviceData))){
|
|
scsiPortNumber = INVALID_SCSI_PORT;
|
|
//
|
|
// "MF\\GOODPRIMARY" and "MF\\GOODSECONDARY" are pnpid for
|
|
// on board IDE Primary and Secondary Channel controllers.
|
|
// And they always has constant SCSIPortNumber 0 or 1 respectively
|
|
// for NT enum and marked as CONTROLLER_ON_BOARD_IDE.
|
|
// Leave INVALID_SCSI_PORT(SCSIPortNumber) for extra IDE controllers
|
|
// and mark them as CONTROLLER_EXTRA_IDE.
|
|
//
|
|
for(ideCounter = 0; ideCounter < ARRAYSIZE(g_knownIDEControllers); ideCounter++){
|
|
if(!_tcsnicmp(ideHardwareID,
|
|
g_knownIDEControllers[ideCounter].pnpId,
|
|
_tcslen(g_knownIDEControllers[ideCounter].pnpId))){
|
|
scsiPortNumber = g_knownIDEControllers[ideCounter].defaultSCSIPort;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(bROOTDevice && INVALID_SCSI_PORT == scsiPortNumber){
|
|
//
|
|
// Ignore this case, devices is not IDE controller.
|
|
//
|
|
break;
|
|
}
|
|
|
|
if(ActiveControllersOut){
|
|
MYASSERT(controllerInfo->SCSIPortNumber == INVALID_SCSI_PORT);
|
|
_tcscpy(controllerInfo->PNPID, regkeyName);
|
|
controllerInfo->SCSIPortNumber = scsiPortNumber;
|
|
controllerInfo->ControllerType = scsiPortNumber != INVALID_SCSI_PORT?
|
|
CONTROLLER_ON_BOARD_IDE: CONTROLLER_EXTRA_IDE;
|
|
}
|
|
|
|
indexAvailable++;
|
|
}
|
|
}
|
|
break;
|
|
case CONTROLLER_SCSI:
|
|
{
|
|
//
|
|
// For SCSI controllers SCSIPortNumber calaculated from
|
|
// "Driver" value and have "SCSIAdapter\000x" where x
|
|
// is SCSIPortNumber. For SCSI controllers SCSIPortNumber
|
|
// will be postprocessed after enum.
|
|
// Mark as CONTROLLER_SCSI.
|
|
//
|
|
if(pRegQueryStringValue(hDevice,
|
|
TEXT("Driver"),
|
|
deviceData,
|
|
sizeof(deviceData))){
|
|
pDelimeter = _tcschr(deviceData, '\\');
|
|
if(pDelimeter){
|
|
*pDelimeter = '\0';
|
|
if(!_tcsicmp(deviceData, TEXT("SCSIAdapter"))){
|
|
scsiPortNumber = _ttoi(++pDelimeter);
|
|
if(ActiveControllersOut){
|
|
MYASSERT(controllerInfo->SCSIPortNumber == INVALID_SCSI_PORT);
|
|
_tcscpy(controllerInfo->PNPID, regkeyName);
|
|
controllerInfo->SCSIPortNumber = scsiPortNumber;
|
|
controllerInfo->ControllerType = CONTROLLER_SCSI;
|
|
}
|
|
indexAvailable++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
MYASSERT(FALSE);
|
|
}
|
|
|
|
RegCloseKey(hDevice);hDevice = NULL;
|
|
}
|
|
}
|
|
}while(FALSE);
|
|
|
|
RegCloseKey(hActiveDeviceRoot);hActiveDeviceRoot = NULL;
|
|
}
|
|
|
|
*NumberOfActiveControllersOut = indexAvailable;
|
|
|
|
if(ActiveControllersOut){
|
|
//
|
|
// Sort controlers in next order: First IDE, after SCSI,
|
|
// inside each group(IDE and SCSI) sort by preliminary defined SCSIPortNumber
|
|
//
|
|
qsort(ActiveControllersOut, indexAvailable, sizeof(ActiveControllersOut[0]), pControllerInfoCompare);
|
|
//
|
|
// Update port number for SCSI devices.
|
|
// User could add new SCSIAdapter and after remove old SCSIAdapter,
|
|
// it cause that SCSIAdapterNumber will be not effective,
|
|
// because for NT it will be (SCSIAdapterNumber - 1)
|
|
//
|
|
for(i = 0, j = 0; j < indexAvailable; j++){
|
|
if(CONTROLLER_SCSI != ActiveControllersOut[j].ControllerType){
|
|
continue;
|
|
}
|
|
//
|
|
// Now SCSI controllers sorted, reassign PortNumber
|
|
// by right order, in order to recognize in NT.
|
|
//
|
|
ActiveControllersOut[j].SCSIPortNumber = i++;
|
|
}
|
|
|
|
//
|
|
// Calculate effective SCSIPortNumber,
|
|
// 0 - IDE Primary, 1 - IDE Secondary, 2 and ... - SCSI
|
|
//
|
|
for(controllerStartIndex = 0, i = 0;
|
|
i < ARRAYSIZE(controllerTypes);
|
|
i++, controllerStartIndex += controllersSubNumber){
|
|
for(controllersSubNumber = 0, j = 0; j < indexAvailable; j++){
|
|
if(controllerTypes[i] != ActiveControllersOut[j].ControllerType){
|
|
continue;
|
|
}
|
|
if(INVALID_SCSI_PORT != ActiveControllersOut[j].SCSIPortNumber){
|
|
ActiveControllersOut[j].SCSIPortNumber += controllerStartIndex;
|
|
}
|
|
controllersSubNumber++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
__finally{
|
|
if(hDevice){
|
|
RegCloseKey(hDevice);
|
|
}
|
|
if(hActiveDeviceRoot){
|
|
RegCloseKey(hActiveDeviceRoot);
|
|
}
|
|
if(hActiveDevicesRoot){
|
|
RegCloseKey(hActiveDevicesRoot);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
GatherControllersInfo(
|
|
IN OUT PCONTROLLERS_COLLECTION * ControllersCollectionOut
|
|
)
|
|
{
|
|
DWORD rcResult = ERROR_ACCESS_DENIED;
|
|
UINT i;
|
|
PCONTROLLERS_COLLECTION activeControllersCollection = NULL;
|
|
BOOL bResult = FALSE;
|
|
UINT activeControllersNumber;
|
|
|
|
if(!ControllersCollectionOut){
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
__try{
|
|
activeControllersCollection = (PCONTROLLERS_COLLECTION)MALLOC(sizeof(CONTROLLERS_COLLECTION));
|
|
if(!activeControllersCollection){
|
|
rcResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
__leave;
|
|
}
|
|
|
|
//
|
|
// Acquiring number of controllers in system
|
|
//
|
|
if(!pGatherControllersInfo(NULL, &activeControllersCollection->NumberOfControllers)){
|
|
rcResult = ERROR_ACCESS_DENIED;
|
|
__leave;
|
|
}
|
|
|
|
//
|
|
// Proceed only if we have positive controllers number
|
|
//
|
|
if(activeControllersCollection->NumberOfControllers){
|
|
activeControllersCollection->ControllersInfo = (PCONTROLLER_INFO)
|
|
MALLOC(activeControllersCollection->NumberOfControllers * sizeof(CONTROLLER_INFO));
|
|
if(!activeControllersCollection->ControllersInfo){
|
|
rcResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
__leave;
|
|
}
|
|
|
|
//
|
|
// Initialize array
|
|
//
|
|
memset(activeControllersCollection->ControllersInfo,
|
|
0,
|
|
activeControllersCollection->NumberOfControllers * sizeof(CONTROLLER_INFO));
|
|
for(i = 0; i < activeControllersCollection->NumberOfControllers; i++){
|
|
activeControllersCollection->ControllersInfo[i].SCSIPortNumber = INVALID_SCSI_PORT;
|
|
}
|
|
|
|
//
|
|
// fill out controllers info array
|
|
//
|
|
activeControllersNumber = activeControllersCollection->NumberOfControllers;
|
|
if(!pGatherControllersInfo(activeControllersCollection->ControllersInfo,
|
|
&activeControllersNumber)){
|
|
rcResult = ERROR_ACCESS_DENIED;
|
|
__leave;
|
|
}
|
|
}
|
|
else{
|
|
activeControllersCollection->ControllersInfo = NULL;
|
|
}
|
|
|
|
*ControllersCollectionOut = activeControllersCollection;
|
|
|
|
rcResult = ERROR_SUCCESS;
|
|
}
|
|
__finally{
|
|
if(ERROR_SUCCESS != rcResult){
|
|
if(activeControllersCollection){
|
|
ReleaseControllersInfo(activeControllersCollection);
|
|
}
|
|
}
|
|
}
|
|
|
|
SetLastError(rcResult);
|
|
|
|
return ERROR_SUCCESS == rcResult;
|
|
}
|
|
|
|
BOOL
|
|
ReleaseControllersInfo(
|
|
IN PCONTROLLERS_COLLECTION ControllersCollection
|
|
)
|
|
{
|
|
if(!ControllersCollection){
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
if(ControllersCollection){
|
|
if(ControllersCollection->ControllersInfo){
|
|
FREE(ControllersCollection->ControllersInfo);
|
|
}
|
|
FREE(ControllersCollection);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
IsInControllerCollection(
|
|
IN PCONTROLLERS_COLLECTION ControllersCollection,
|
|
IN PCTSTR PnPIdString,
|
|
OUT PUINT Index
|
|
)
|
|
{
|
|
UINT i;
|
|
|
|
if(!ControllersCollection || !PnPIdString || !Index){
|
|
return FALSE;
|
|
}
|
|
|
|
for(i = 0; i < ControllersCollection->NumberOfControllers; i++){
|
|
if(!_tcsnicmp(PnPIdString,
|
|
ControllersCollection->ControllersInfo[i].PNPID,
|
|
_tcslen(ControllersCollection->ControllersInfo[i].PNPID))){
|
|
*Index = i;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetSCSIAddressFromPnPId(
|
|
IN PCONTROLLERS_COLLECTION ControllersCollection,
|
|
IN HKEY hDeviceRegKey,
|
|
IN PCTSTR PnPIdString,
|
|
OUT DRIVE_SCSI_ADDRESS * ScsiAddressOut
|
|
)
|
|
{
|
|
UINT i;
|
|
PCTSTR pBufferKeyValue;
|
|
BOOL bResult;
|
|
|
|
if(!ControllersCollection || !hDeviceRegKey || !PnPIdString || !ScsiAddressOut){
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
bResult = FALSE;
|
|
|
|
do{
|
|
//
|
|
// Check for presence in controllers list controller PNPID of device
|
|
// After complete SCSI_ADDRESS structure with
|
|
// DriveLetter, DriveType, TargetID, Lun.
|
|
//
|
|
if(IsInControllerCollection(ControllersCollection, PnPIdString, &i)){
|
|
|
|
memset(ScsiAddressOut, 0, sizeof(*ScsiAddressOut));
|
|
|
|
ScsiAddressOut->PortNumber = (UCHAR)ControllersCollection->ControllersInfo[i].SCSIPortNumber;
|
|
bResult = pGetDeviceType(hDeviceRegKey, &ScsiAddressOut->DriveType);
|
|
MYASSERT(bResult);
|
|
|
|
pBufferKeyValue = pRegQueryStringValue(hDeviceRegKey,
|
|
DEVICE_CURRENT_DRIVE_LETTER_TEXT_ASSIGNMENT,
|
|
NULL,
|
|
0);
|
|
if(!pBufferKeyValue){
|
|
break;
|
|
}
|
|
ScsiAddressOut->DriveLetter = pBufferKeyValue[0];
|
|
|
|
pBufferKeyValue = pRegQueryStringValue(hDeviceRegKey, TEXT("ScsiTargetId"), NULL, 0);
|
|
if(!pBufferKeyValue){
|
|
break;
|
|
}
|
|
ScsiAddressOut->TargetId = (UCHAR)_ttoi(pBufferKeyValue);
|
|
|
|
pBufferKeyValue = pRegQueryStringValue(hDeviceRegKey, TEXT("ScsiLun"), NULL, 0);
|
|
if(pBufferKeyValue){
|
|
//
|
|
//For most cases ScsiLun is zero, so it is not fatal.
|
|
//
|
|
ScsiAddressOut->Lun = (UCHAR)_ttoi(pBufferKeyValue);
|
|
}
|
|
|
|
bResult = TRUE;
|
|
}
|
|
}while(FALSE);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL
|
|
DeviceEnum(
|
|
IN PCONTROLLERS_COLLECTION ControllersCollection,
|
|
IN PCTSTR DeviceCategory,
|
|
IN PDEVICE_ENUM_CALLBACK_FUNCTION DeviceEnumCallbackFunction,
|
|
IN PVOID CallbackData
|
|
)
|
|
{
|
|
TCHAR deviceType[MAX_REG_SIZE];
|
|
TCHAR regkeyName[MAX_PNPID_SIZE];
|
|
TCHAR deviceInfoRegKey[MAX_REG_SIZE];
|
|
HKEY hActiveDevicesRoot = NULL;
|
|
HKEY hActiveDeviceRoot = NULL;
|
|
HKEY hDevice = NULL;
|
|
UINT itemIndexRoot;
|
|
DWORD bufferLength;
|
|
UINT controllerIndex;
|
|
PTSTR pDevicePNPIDName;
|
|
UINT deviceTypeLen;
|
|
DWORD rcResult;
|
|
|
|
if(!ControllersCollection || !DeviceCategory || !DeviceEnumCallbackFunction){
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
__try{
|
|
if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_DYN_DATA, TEXT("Config Manager\\Enum"), 0, KEY_READ, &hActiveDevicesRoot)){
|
|
return FALSE;
|
|
}
|
|
|
|
_tcscpy(deviceType, DeviceCategory);
|
|
_tcscat(deviceType, TEXT("\\"));
|
|
deviceTypeLen = _tcslen(deviceType);
|
|
|
|
//
|
|
// Looking for devices that attached to controllers in our list
|
|
//
|
|
for(itemIndexRoot = 0; ;itemIndexRoot++){
|
|
bufferLength = ARRAYSIZE(regkeyName);
|
|
|
|
rcResult = RegEnumKeyEx(hActiveDevicesRoot,
|
|
itemIndexRoot,
|
|
regkeyName,
|
|
&bufferLength,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
if(ERROR_SUCCESS != rcResult){
|
|
break;
|
|
}
|
|
|
|
if(ERROR_SUCCESS != RegOpenKeyEx(hActiveDevicesRoot, regkeyName, 0, KEY_READ, &hActiveDeviceRoot)){
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// "HardWareKey" consist key path to real device
|
|
//
|
|
if(pRegQueryStringValue(hActiveDeviceRoot,
|
|
TEXT("HardWareKey"),
|
|
regkeyName,
|
|
sizeof(regkeyName))){
|
|
|
|
if(!_tcsnicmp(regkeyName, deviceType, deviceTypeLen)){
|
|
_tcscpy(deviceInfoRegKey, TEXT("Enum\\"));
|
|
_tcscat(deviceInfoRegKey, regkeyName);
|
|
|
|
//
|
|
// Make a Controller PNPID from device PNPID
|
|
//
|
|
pDevicePNPIDName = _tcsrchr(regkeyName, '\\');
|
|
MYASSERT(pDevicePNPIDName);
|
|
pDevicePNPIDName++;
|
|
|
|
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, deviceInfoRegKey, 0, KEY_READ, &hDevice)){
|
|
//
|
|
// Check for presence Controller PNPID in controllers list and
|
|
// for device availability.
|
|
//
|
|
if(IsInControllerCollection(ControllersCollection, pDevicePNPIDName, &controllerIndex) &&
|
|
pDoesDriveExist(hDevice, NULL)){
|
|
//
|
|
// Call callback for every active device we found,
|
|
// which controller in our list
|
|
// Stop enum, if user does not want to.
|
|
//
|
|
if(!DeviceEnumCallbackFunction(hDevice, ControllersCollection, controllerIndex, CallbackData)){
|
|
//
|
|
// Stop enum, if user does not want to.
|
|
//
|
|
__leave;
|
|
}
|
|
}
|
|
RegCloseKey(hDevice);hDevice = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hActiveDeviceRoot);hActiveDeviceRoot = NULL;
|
|
}
|
|
}
|
|
__finally{
|
|
if(hDevice){
|
|
RegCloseKey(hDevice);
|
|
}
|
|
if(hActiveDeviceRoot){
|
|
RegCloseKey(hActiveDeviceRoot);
|
|
}
|
|
if(hActiveDevicesRoot){
|
|
RegCloseKey(hActiveDevicesRoot);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|