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.
1809 lines
52 KiB
1809 lines
52 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
|
|
Module Name:
|
|
|
|
devcaps.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the implementation for the
|
|
Microsoft Biometric Device Library
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
- Created December 2002 by Reid Kuhn
|
|
|
|
--*/
|
|
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <strsafe.h>
|
|
|
|
#include <wdm.h>
|
|
|
|
#include "bdlint.h"
|
|
|
|
|
|
#define DEVICE_REGISTRY_PATH L"\\Registry\\Machine\\Software\\Microsoft\\BAPI\\BSPs\\Microsoft Kernel BSP\\Devices\\"
|
|
#define PNPID_VALUE_NAME L"PNP ID"
|
|
|
|
NTSTATUS
|
|
BDLBuildRegKeyPath
|
|
(
|
|
PDEVICE_OBJECT pPhysicalDeviceObject,
|
|
PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension,
|
|
LPWSTR *pwszDeviceRegistryKeyName
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
HANDLE hDevInstRegyKey = NULL;
|
|
ULONG cbKeyName;
|
|
UNICODE_STRING ValueName;
|
|
KEY_VALUE_BASIC_INFORMATION *pKeyValueInformation = NULL;
|
|
ULONG ResultLength;
|
|
|
|
BDLDebug(
|
|
BDL_DEBUG_TRACE,
|
|
("%s %s: BDL!BDLBuildRegKeyPath: Enter\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
//
|
|
// Opend the device specific registry location
|
|
//
|
|
status = IoOpenDeviceRegistryKey(
|
|
pPhysicalDeviceObject,
|
|
PLUGPLAY_REGKEY_DEVICE,
|
|
KEY_READ | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
|
|
&hDevInstRegyKey);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLBuildRegKeyPath: IoOpenDeviceRegistryKey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Query the PNP ID from the device specific registry location
|
|
//
|
|
RtlInitUnicodeString(&ValueName, PNPID_VALUE_NAME);
|
|
|
|
status = ZwQueryValueKey(
|
|
hDevInstRegyKey,
|
|
&ValueName,
|
|
KeyValueBasicInformation,
|
|
NULL,
|
|
0,
|
|
&ResultLength);
|
|
|
|
pKeyValueInformation = ExAllocatePoolWithTag(PagedPool, ResultLength, BDL_ULONG_TAG);
|
|
|
|
if (pKeyValueInformation == NULL)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLBuildRegKeyPath: ExAllocatePoolWithTag failed\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
status = STATUS_NO_MEMORY;
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
status = ZwQueryValueKey(
|
|
hDevInstRegyKey,
|
|
&ValueName,
|
|
KeyValueBasicInformation,
|
|
pKeyValueInformation,
|
|
ResultLength,
|
|
&ResultLength);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLBuildRegKeyPath: ZwQueryValueKey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (pKeyValueInformation->Type != REG_SZ)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLBuildRegKeyPath: PNP ID is not a string type\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
ASSERT(0);
|
|
status = STATUS_UNSUCCESSFUL;
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Allocate space for the concatenatenation of the base registry name with the
|
|
// PnP name of the current device and pass that concatenation back
|
|
//
|
|
cbKeyName = pKeyValueInformation->NameLength + ((wcslen(DEVICE_REGISTRY_PATH) + 1) * sizeof(WCHAR));
|
|
*pwszDeviceRegistryKeyName = ExAllocatePoolWithTag(PagedPool, cbKeyName, BDL_ULONG_TAG);
|
|
|
|
if (*pwszDeviceRegistryKeyName == NULL)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLBuildRegKeyPath: ExAllocatePoolWithTag failed\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
status = STATUS_NO_MEMORY;
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
StringCbCopyW(*pwszDeviceRegistryKeyName, cbKeyName, DEVICE_REGISTRY_PATH);
|
|
|
|
RtlCopyMemory(
|
|
&((*pwszDeviceRegistryKeyName)[wcslen(DEVICE_REGISTRY_PATH)]),
|
|
pKeyValueInformation->Name,
|
|
pKeyValueInformation->NameLength);
|
|
|
|
(*pwszDeviceRegistryKeyName)[cbKeyName / sizeof(WCHAR)] = L'\0';
|
|
|
|
Return:
|
|
|
|
if (hDevInstRegyKey != NULL)
|
|
{
|
|
ZwClose(hDevInstRegyKey);
|
|
}
|
|
|
|
if (pKeyValueInformation != NULL)
|
|
{
|
|
ExFreePoolWithTag(pKeyValueInformation, BDL_ULONG_TAG);
|
|
}
|
|
|
|
BDLDebug(
|
|
BDL_DEBUG_TRACE,
|
|
("%s %s: BDL!BDLBuildRegKeyPath: Leave\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
return (status);
|
|
|
|
ErrorReturn:
|
|
|
|
goto Return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
BDLOpenSubkey
|
|
(
|
|
HANDLE hRegKey,
|
|
WCHAR *szKey,
|
|
HANDLE *phSubKey
|
|
)
|
|
{
|
|
UNICODE_STRING UnicodeString;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
RtlInitUnicodeString(&UnicodeString, szKey);
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
hRegKey,
|
|
NULL);
|
|
|
|
return (ZwOpenKey(
|
|
phSubKey,
|
|
KEY_READ | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
|
|
&ObjectAttributes));
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
BDLGetValue
|
|
(
|
|
HANDLE hRegKey,
|
|
ULONG Type,
|
|
WCHAR *szValue,
|
|
ULONG *pULONGValue,
|
|
WCHAR **pszValue
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
KEY_VALUE_FULL_INFORMATION *pKeyValueFullInformation = NULL;
|
|
ULONG ResultLength;
|
|
UNICODE_STRING UnicodeString;
|
|
ULONG NumChars;
|
|
|
|
BDLDebug(
|
|
BDL_DEBUG_TRACE,
|
|
("%s %s: BDL!BDLGetValue: Enter\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
RtlInitUnicodeString(&UnicodeString, szValue);
|
|
|
|
status = ZwQueryValueKey(
|
|
hRegKey,
|
|
&UnicodeString,
|
|
KeyValueFullInformation,
|
|
NULL,
|
|
0,
|
|
&ResultLength);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetValue: ZwQueryValueKey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
pKeyValueFullInformation = ExAllocatePoolWithTag(PagedPool, ResultLength, BDL_ULONG_TAG);
|
|
|
|
if (pKeyValueFullInformation == NULL)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetValue: ExAllocatePoolWithTag failed\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
status = STATUS_NO_MEMORY;
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
status = ZwQueryValueKey(
|
|
hRegKey,
|
|
&UnicodeString,
|
|
KeyValueFullInformation,
|
|
pKeyValueFullInformation,
|
|
ResultLength,
|
|
&ResultLength);
|
|
|
|
if (pKeyValueFullInformation->Type != Type)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetValue: %S is not of Type %lx\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
szValue,
|
|
Type))
|
|
|
|
ASSERT(0);
|
|
status = STATUS_UNSUCCESSFUL;
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (Type == REG_DWORD)
|
|
{
|
|
*pULONGValue = *((ULONG *)
|
|
(((PUCHAR) pKeyValueFullInformation) + pKeyValueFullInformation->DataOffset));
|
|
|
|
}
|
|
else
|
|
{
|
|
NumChars = pKeyValueFullInformation->DataLength / sizeof(WCHAR);
|
|
|
|
*pszValue = ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
(NumChars + 1) * sizeof(WCHAR),
|
|
BDL_ULONG_TAG);
|
|
|
|
if (*pszValue == NULL)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetValue: ExAllocatePoolWithTag failed\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
status = STATUS_NO_MEMORY;
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
RtlCopyMemory(
|
|
*pszValue,
|
|
((PUCHAR) pKeyValueFullInformation) + pKeyValueFullInformation->DataOffset,
|
|
pKeyValueFullInformation->DataLength);
|
|
|
|
(*pszValue)[NumChars] = L'\0';
|
|
}
|
|
|
|
Return:
|
|
|
|
if (pKeyValueFullInformation != NULL)
|
|
{
|
|
ExFreePoolWithTag(pKeyValueFullInformation, BDL_ULONG_TAG);
|
|
}
|
|
|
|
BDLDebug(
|
|
BDL_DEBUG_TRACE,
|
|
("%s %s: BDL!BDLGetValue: Leave\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
return (status);
|
|
|
|
ErrorReturn:
|
|
|
|
goto Return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
BDLGetControls
|
|
(
|
|
HANDLE hRegKey,
|
|
ULONG *pNumControls,
|
|
BDL_CONTROL **prgControls
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
HANDLE hControlsKey = NULL;
|
|
UNICODE_STRING UnicodeString;
|
|
KEY_FULL_INFORMATION ControlsKeyFullInfo;
|
|
ULONG ReturnedSize;
|
|
ULONG i;
|
|
HANDLE hControlIdKey = NULL;
|
|
KEY_BASIC_INFORMATION *pControlIdKeyBasicInfo = NULL;
|
|
ULONG KeyBasicInfoSize = 0;
|
|
ULONG NumericMinimum = 0;
|
|
ULONG NumericMaximum = 0;
|
|
|
|
BDLDebug(
|
|
BDL_DEBUG_TRACE,
|
|
("%s %s: BDL!BDLGetControls: Enter\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
*pNumControls = 0;
|
|
*prgControls = NULL;
|
|
|
|
//
|
|
// Open the "Controls" key so it can be used to query all subkeys and values
|
|
//
|
|
status = BDLOpenSubkey(hRegKey, L"Controls", &hControlsKey);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetControls: BDLOpenSubkey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Find out how many controls there are
|
|
//
|
|
status = ZwQueryKey(
|
|
hControlsKey,
|
|
KeyFullInformation,
|
|
&ControlsKeyFullInfo,
|
|
sizeof(ControlsKeyFullInfo),
|
|
&ReturnedSize);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetControls: ZwQueryKey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Allocate the array of controls
|
|
//
|
|
*prgControls = ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
ControlsKeyFullInfo.SubKeys * sizeof(BDL_CONTROL),
|
|
BDL_ULONG_TAG);
|
|
|
|
if (*prgControls == NULL)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetControls: ExAllocatePoolWithTag failed\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
status = STATUS_NO_MEMORY;
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
*pNumControls = ControlsKeyFullInfo.SubKeys;
|
|
RtlZeroMemory(*prgControls, ControlsKeyFullInfo.SubKeys * sizeof(BDL_CONTROL));
|
|
|
|
//
|
|
// Allocate a structure for querying key names that is large enough to hold all of them
|
|
//
|
|
KeyBasicInfoSize = sizeof(KEY_BASIC_INFORMATION) + ControlsKeyFullInfo.MaxNameLen;
|
|
pControlIdKeyBasicInfo = ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
KeyBasicInfoSize + 1,
|
|
BDL_ULONG_TAG);
|
|
|
|
if (pControlIdKeyBasicInfo == NULL)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetControls: ExAllocatePoolWithTag failed\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
status = STATUS_NO_MEMORY;
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Loop for each Control SubKey and get the relevant info
|
|
//
|
|
for (i = 0; i < ControlsKeyFullInfo.SubKeys; i++)
|
|
{
|
|
//
|
|
// Get the name on the <Control Id> key
|
|
//
|
|
status = ZwEnumerateKey(
|
|
hControlsKey,
|
|
i,
|
|
KeyBasicInformation,
|
|
pControlIdKeyBasicInfo,
|
|
KeyBasicInfoSize,
|
|
&ReturnedSize);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetControls: ZwEnumerateKey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Change the <Control ID> key string to a value
|
|
//
|
|
pControlIdKeyBasicInfo->Name[pControlIdKeyBasicInfo->NameLength / sizeof(WCHAR)] = L'\0';
|
|
RtlInitUnicodeString(&UnicodeString, pControlIdKeyBasicInfo->Name);
|
|
RtlUnicodeStringToInteger(&UnicodeString, 16, &((*prgControls)[i].ControlId));
|
|
|
|
//
|
|
// Open up the <Control ID> key
|
|
//
|
|
status = BDLOpenSubkey(hControlsKey, pControlIdKeyBasicInfo->Name, &hControlIdKey);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetControls: BDLOpenSubkey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Get all the values under the key
|
|
//
|
|
if ((STATUS_SUCCESS != (status = BDLGetValue(
|
|
hControlIdKey,
|
|
REG_DWORD,
|
|
L"NumericMinimum",
|
|
&(NumericMinimum),
|
|
NULL))) ||
|
|
(STATUS_SUCCESS != (status = BDLGetValue(
|
|
hControlIdKey,
|
|
REG_DWORD,
|
|
L"NumericMaximum",
|
|
&(NumericMaximum),
|
|
NULL))) ||
|
|
(STATUS_SUCCESS != (status = BDLGetValue(
|
|
hControlIdKey,
|
|
REG_DWORD,
|
|
L"NumericGranularity",
|
|
&((*prgControls)[i].NumericGranularity),
|
|
NULL))) ||
|
|
(STATUS_SUCCESS != (status = BDLGetValue(
|
|
hControlIdKey,
|
|
REG_DWORD,
|
|
L"NumericDivisor",
|
|
&((*prgControls)[i].NumericDivisor),
|
|
NULL))) ||
|
|
(STATUS_SUCCESS != (status = BDLGetValue(
|
|
hControlIdKey,
|
|
REG_DWORD,
|
|
L"Flags",
|
|
&((*prgControls)[i].Flags),
|
|
NULL))))
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetControls: BDLGetValue failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Convert Min and Max to 32-bit integers
|
|
//
|
|
if (NumericMinimum | 0x8000000)
|
|
{
|
|
(*prgControls)[i].NumericMinimum =
|
|
0 - (((INT32) (((ULONG) 0xFFFFFFFF) - NumericMinimum)) + 1);
|
|
}
|
|
else
|
|
{
|
|
(*prgControls)[i].NumericMinimum = (INT32) NumericMinimum;
|
|
}
|
|
|
|
if (NumericMaximum | 0x8000000)
|
|
{
|
|
(*prgControls)[i].NumericMaximum =
|
|
0 - (((INT32) (((ULONG) 0xFFFFFFFF) - NumericMaximum)) + 1);
|
|
}
|
|
else
|
|
{
|
|
(*prgControls)[i].NumericMaximum = (INT32) NumericMaximum;
|
|
}
|
|
|
|
ZwClose(hControlIdKey);
|
|
hControlIdKey = NULL;
|
|
}
|
|
|
|
Return:
|
|
|
|
if (hControlsKey != NULL)
|
|
{
|
|
ZwClose(hControlsKey);
|
|
}
|
|
|
|
if (hControlIdKey != NULL)
|
|
{
|
|
ZwClose(hControlIdKey);
|
|
}
|
|
|
|
if (pControlIdKeyBasicInfo != NULL)
|
|
{
|
|
ExFreePoolWithTag(pControlIdKeyBasicInfo, BDL_ULONG_TAG);
|
|
}
|
|
|
|
BDLDebug(
|
|
BDL_DEBUG_TRACE,
|
|
("%s %s: BDL!BDLGetControls: Leave\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
return (status);
|
|
|
|
ErrorReturn:
|
|
|
|
goto Return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
BDLGetSourceLists
|
|
(
|
|
HANDLE hRegKey,
|
|
ULONG *pNumSourceLists,
|
|
BDL_CHANNEL_SOURCE_LIST **prgSourceLists
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
HANDLE hSourcesKey = NULL;
|
|
UNICODE_STRING UnicodeString;
|
|
KEY_FULL_INFORMATION SourcesKeyFullInfo;
|
|
ULONG ReturnedSize;
|
|
ULONG i;
|
|
HANDLE hSourceListIndexKey = NULL;
|
|
KEY_BASIC_INFORMATION *pSourcesListIndexKeyBasicInfo = NULL;
|
|
ULONG KeyBasicInfoSize = 0;
|
|
WCHAR *szGUID = NULL;
|
|
|
|
BDLDebug(
|
|
BDL_DEBUG_TRACE,
|
|
("%s %s: BDL!BDLGetSourceLists: Enter\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
*pNumSourceLists = 0;
|
|
*prgSourceLists = NULL;
|
|
|
|
//
|
|
// Open the "Sources" key so it can be used to query all subkeys and values
|
|
//
|
|
status = BDLOpenSubkey(hRegKey, L"Sources", &hSourcesKey);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetSourceLists: BDLOpenSubkey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Find out how many sources lists there are
|
|
//
|
|
status = ZwQueryKey(
|
|
hSourcesKey,
|
|
KeyFullInformation,
|
|
&SourcesKeyFullInfo,
|
|
sizeof(SourcesKeyFullInfo),
|
|
&ReturnedSize);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetSourceLists: ZwQueryKey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Allocate the array of sources lists
|
|
//
|
|
*prgSourceLists = ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
SourcesKeyFullInfo.SubKeys * sizeof(BDL_CHANNEL_SOURCE_LIST),
|
|
BDL_ULONG_TAG);
|
|
|
|
if (*prgSourceLists == NULL)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetSourceLists: ExAllocatePoolWithTag failed\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
status = STATUS_NO_MEMORY;
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
*pNumSourceLists = SourcesKeyFullInfo.SubKeys;
|
|
RtlZeroMemory(*prgSourceLists, SourcesKeyFullInfo.SubKeys * sizeof(BDL_CHANNEL_SOURCE_LIST));
|
|
|
|
//
|
|
// Allocate a structure for querying key names that is large enough to hold all of them
|
|
//
|
|
KeyBasicInfoSize = sizeof(KEY_BASIC_INFORMATION) + SourcesKeyFullInfo.MaxNameLen;
|
|
pSourcesListIndexKeyBasicInfo = ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
KeyBasicInfoSize + 1,
|
|
BDL_ULONG_TAG);
|
|
|
|
if (pSourcesListIndexKeyBasicInfo == NULL)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetSourceLists: ExAllocatePoolWithTag failed\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
status = STATUS_NO_MEMORY;
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Loop for each Source List Index SubKey and get the relevant info
|
|
//
|
|
for (i = 0; i < SourcesKeyFullInfo.SubKeys; i++)
|
|
{
|
|
//
|
|
// Get the name of the <Source List Index> key
|
|
//
|
|
// NOTE: This code does not ensure that the key names progress from "0" to "1"
|
|
// to "n". The WHQL driver validation ensures proper registry form.
|
|
//
|
|
status = ZwEnumerateKey(
|
|
hSourcesKey,
|
|
i,
|
|
KeyBasicInformation,
|
|
pSourcesListIndexKeyBasicInfo,
|
|
KeyBasicInfoSize,
|
|
&ReturnedSize);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetSourceLists: ZwEnumerateKey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Open up the <Source List Index> key
|
|
//
|
|
status = BDLOpenSubkey(
|
|
hSourcesKey,
|
|
pSourcesListIndexKeyBasicInfo->Name,
|
|
&hSourceListIndexKey);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetSourceLists: BDLOpenSubkey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Get all the values under the key
|
|
//
|
|
if ((STATUS_SUCCESS != (status = BDLGetValue(
|
|
hSourceListIndexKey,
|
|
REG_SZ,
|
|
L"Format",
|
|
NULL,
|
|
&szGUID))) ||
|
|
(STATUS_SUCCESS != (status = BDLGetValue(
|
|
hSourceListIndexKey,
|
|
REG_DWORD,
|
|
L"Min",
|
|
&((*prgSourceLists)[i].MinSources),
|
|
NULL))) ||
|
|
(STATUS_SUCCESS != (status = BDLGetValue(
|
|
hSourceListIndexKey,
|
|
REG_DWORD,
|
|
L"Max",
|
|
&((*prgSourceLists)[i].MaxSources),
|
|
NULL))) ||
|
|
(STATUS_SUCCESS != (status = BDLGetValue(
|
|
hSourceListIndexKey,
|
|
REG_DWORD,
|
|
L"Flags",
|
|
&((*prgSourceLists)[i].Flags),
|
|
NULL))))
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetSourceLists: BDLGetValue failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Convert the Format GUID string to an actual GUID
|
|
//
|
|
RtlInitUnicodeString(&UnicodeString, szGUID);
|
|
status = RtlGUIDFromString(&UnicodeString, &((*prgSourceLists)[i].FormatGUID));
|
|
|
|
ZwClose(hSourceListIndexKey);
|
|
hSourceListIndexKey = NULL;
|
|
}
|
|
|
|
Return:
|
|
|
|
if (hSourcesKey != NULL)
|
|
{
|
|
ZwClose(hSourcesKey);
|
|
}
|
|
|
|
if (hSourceListIndexKey != NULL)
|
|
{
|
|
ZwClose(hSourceListIndexKey);
|
|
}
|
|
|
|
if (pSourcesListIndexKeyBasicInfo != NULL)
|
|
{
|
|
ExFreePoolWithTag(pSourcesListIndexKeyBasicInfo, BDL_ULONG_TAG);
|
|
}
|
|
|
|
if (szGUID != NULL)
|
|
{
|
|
ExFreePoolWithTag(szGUID, BDL_ULONG_TAG);
|
|
}
|
|
|
|
BDLDebug(
|
|
BDL_DEBUG_TRACE,
|
|
("%s %s: BDL!BDLGetSourceLists: Leave\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
return (status);
|
|
|
|
ErrorReturn:
|
|
|
|
goto Return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
BDLGetProducts
|
|
(
|
|
HANDLE hRegKey,
|
|
ULONG *pNumProducts,
|
|
BDL_PRODUCT **prgProducts
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
HANDLE hProductsKey = NULL;
|
|
UNICODE_STRING UnicodeString;
|
|
KEY_FULL_INFORMATION ProductsKeyFullInfo;
|
|
ULONG ReturnedSize;
|
|
ULONG i;
|
|
HANDLE hProductIndexKey = NULL;
|
|
KEY_BASIC_INFORMATION *pProductIndexKeyBasicInfo = NULL;
|
|
ULONG KeyBasicInfoSize = 0;
|
|
|
|
BDLDebug(
|
|
BDL_DEBUG_TRACE,
|
|
("%s %s: BDL!BDLGetProducts: Enter\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
*pNumProducts = 0;
|
|
*prgProducts = NULL;
|
|
|
|
//
|
|
// Open the "Products" key so it can be used to query all subkeys and values
|
|
//
|
|
status = BDLOpenSubkey(hRegKey, L"Products", &hProductsKey);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetProducts: BDLOpenSubkey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Find out how many products there are
|
|
//
|
|
status = ZwQueryKey(
|
|
hProductsKey,
|
|
KeyFullInformation,
|
|
&ProductsKeyFullInfo,
|
|
sizeof(ProductsKeyFullInfo),
|
|
&ReturnedSize);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetProducts: ZwQueryKey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Allocate the array of products
|
|
//
|
|
*prgProducts = ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
ProductsKeyFullInfo.SubKeys * sizeof(BDL_PRODUCT),
|
|
BDL_ULONG_TAG);
|
|
|
|
if (*prgProducts == NULL)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetProducts: ExAllocatePoolWithTag failed\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
status = STATUS_NO_MEMORY;
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
*pNumProducts = ProductsKeyFullInfo.SubKeys;
|
|
RtlZeroMemory(*prgProducts, ProductsKeyFullInfo.SubKeys * sizeof(BDL_PRODUCT));
|
|
|
|
//
|
|
// Allocate a structure for querying key names that is large enough to hold all of them
|
|
//
|
|
KeyBasicInfoSize = sizeof(KEY_BASIC_INFORMATION) + ProductsKeyFullInfo.MaxNameLen;
|
|
pProductIndexKeyBasicInfo = ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
KeyBasicInfoSize + 1,
|
|
BDL_ULONG_TAG);
|
|
|
|
if (pProductIndexKeyBasicInfo == NULL)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetProducts: ExAllocatePoolWithTag failed\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
status = STATUS_NO_MEMORY;
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Loop for each Source List Index SubKey and get the relevant info
|
|
//
|
|
for (i = 0; i < ProductsKeyFullInfo.SubKeys; i++)
|
|
{
|
|
//
|
|
// Get the name of the <Product Index> key
|
|
//
|
|
// NOTE: This code does not ensure that the key names progress from "0" to "1"
|
|
// to "n". The WHQL driver validation ensures proper registry form.
|
|
//
|
|
status = ZwEnumerateKey(
|
|
hProductsKey,
|
|
i,
|
|
KeyBasicInformation,
|
|
pProductIndexKeyBasicInfo,
|
|
KeyBasicInfoSize,
|
|
&ReturnedSize);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetProducts: ZwEnumerateKey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Open up the <Product Index> key
|
|
//
|
|
status = BDLOpenSubkey(
|
|
hProductsKey,
|
|
pProductIndexKeyBasicInfo->Name,
|
|
&hProductIndexKey);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetProducts: BDLOpenSubkey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Get all the values under the key
|
|
//
|
|
if (STATUS_SUCCESS != (status = BDLGetValue(
|
|
hProductIndexKey,
|
|
REG_DWORD,
|
|
L"Flags",
|
|
&((*prgProducts)[i].Flags),
|
|
NULL)))
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetProducts: BDLGetValue failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
ZwClose(hProductIndexKey);
|
|
hProductIndexKey = NULL;
|
|
}
|
|
|
|
Return:
|
|
|
|
if (hProductsKey != NULL)
|
|
{
|
|
ZwClose(hProductsKey);
|
|
}
|
|
|
|
if (hProductIndexKey != NULL)
|
|
{
|
|
ZwClose(hProductIndexKey);
|
|
}
|
|
|
|
if (pProductIndexKeyBasicInfo != NULL)
|
|
{
|
|
ExFreePoolWithTag(pProductIndexKeyBasicInfo, BDL_ULONG_TAG);
|
|
}
|
|
|
|
BDLDebug(
|
|
BDL_DEBUG_TRACE,
|
|
("%s %s: BDL!BDLGetProducts: Leave\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
return (status);
|
|
|
|
ErrorReturn:
|
|
|
|
goto Return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
BDLGetChannels
|
|
(
|
|
HANDLE hRegKey,
|
|
ULONG *pNumChannels,
|
|
BDL_CHANNEL **prgChannels
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
HANDLE hChannelsKey = NULL;
|
|
KEY_FULL_INFORMATION ChannelsKeyFullInfo;
|
|
UNICODE_STRING UnicodeString;
|
|
ULONG ReturnedSize;
|
|
ULONG i;
|
|
HANDLE hChannelIdKey = NULL;
|
|
KEY_BASIC_INFORMATION *pChannelIdKeyBasicInfo = NULL;
|
|
ULONG KeyBasicInfoSize = 0;
|
|
|
|
BDLDebug(
|
|
BDL_DEBUG_TRACE,
|
|
("%s %s: BDL!BDLGetChannels: Enter\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
*pNumChannels = 0;
|
|
*prgChannels = NULL;
|
|
|
|
//
|
|
// Open the "Channels" key so it can be used to query all subkeys and values
|
|
//
|
|
status = BDLOpenSubkey(hRegKey, L"Channels", &hChannelsKey);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetChannels: BDLOpenSubkey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Find out how many controls there are
|
|
//
|
|
status = ZwQueryKey(
|
|
hChannelsKey,
|
|
KeyFullInformation,
|
|
&ChannelsKeyFullInfo,
|
|
sizeof(ChannelsKeyFullInfo),
|
|
&ReturnedSize);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetChannels: ZwQueryKey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Allocate the array of channels
|
|
//
|
|
*prgChannels = ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
ChannelsKeyFullInfo.SubKeys * sizeof(BDL_CHANNEL),
|
|
BDL_ULONG_TAG);
|
|
|
|
if (*prgChannels == NULL)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetChannels: ExAllocatePoolWithTag failed\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
status = STATUS_NO_MEMORY;
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
*pNumChannels = ChannelsKeyFullInfo.SubKeys;
|
|
RtlZeroMemory(*prgChannels, ChannelsKeyFullInfo.SubKeys * sizeof(BDL_CHANNEL));
|
|
|
|
//
|
|
// Allocate a structure for querying key names that is large enough to hold all of them
|
|
//
|
|
KeyBasicInfoSize = sizeof(KEY_BASIC_INFORMATION) + ChannelsKeyFullInfo.MaxNameLen;
|
|
pChannelIdKeyBasicInfo = ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
KeyBasicInfoSize + 1,
|
|
BDL_ULONG_TAG);
|
|
|
|
if (pChannelIdKeyBasicInfo == NULL)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetChannels: ExAllocatePoolWithTag failed\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
status = STATUS_NO_MEMORY;
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Loop for each Channel SubKey and get the relevant info
|
|
//
|
|
for (i = 0; i < ChannelsKeyFullInfo.SubKeys; i++)
|
|
{
|
|
//
|
|
// Get the name on the <Channel Id> key
|
|
//
|
|
status = ZwEnumerateKey(
|
|
hChannelsKey,
|
|
i,
|
|
KeyBasicInformation,
|
|
pChannelIdKeyBasicInfo,
|
|
KeyBasicInfoSize,
|
|
&ReturnedSize);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetChannels: ZwEnumerateKey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Change the <Channel ID> key string to a value
|
|
//
|
|
pChannelIdKeyBasicInfo->Name[pChannelIdKeyBasicInfo->NameLength / sizeof(WCHAR)] = L'\0';
|
|
RtlInitUnicodeString(&UnicodeString, pChannelIdKeyBasicInfo->Name);
|
|
RtlUnicodeStringToInteger(&UnicodeString, 16, &((*prgChannels)[i].ChannelId));
|
|
|
|
//
|
|
// Open up the <Channel ID> key
|
|
//
|
|
status = BDLOpenSubkey(hChannelsKey, pChannelIdKeyBasicInfo->Name, &hChannelIdKey);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetChannels: BDLOpenSubkey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Get the Cancelable value
|
|
//
|
|
status = BDLGetValue(
|
|
hChannelIdKey,
|
|
REG_DWORD,
|
|
L"Cancelable",
|
|
(ULONG *) &((*prgChannels)[i].fCancelable),
|
|
NULL);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetChannels: BDLGetValue failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Get the channel level controls
|
|
//
|
|
status = BDLGetControls(
|
|
hChannelIdKey,
|
|
&((*prgChannels)[i].NumControls),
|
|
&((*prgChannels)[i].rgControls));
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetChannels: BDLGetControls failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Get the sources lists
|
|
//
|
|
status = BDLGetSourceLists(
|
|
hChannelIdKey,
|
|
&((*prgChannels)[i].NumSourceLists),
|
|
&((*prgChannels)[i].rgSourceLists));
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetChannels: BDLGetSourceLists failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Get the products
|
|
//
|
|
status = BDLGetProducts(
|
|
hChannelIdKey,
|
|
&((*prgChannels)[i].NumProducts),
|
|
&((*prgChannels)[i].rgProducts));
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetChannels: BDLGetProductss failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
ZwClose(hChannelIdKey);
|
|
hChannelIdKey = NULL;
|
|
}
|
|
|
|
|
|
Return:
|
|
|
|
if (hChannelsKey != NULL)
|
|
{
|
|
ZwClose(hChannelsKey);
|
|
}
|
|
|
|
if (hChannelIdKey != NULL)
|
|
{
|
|
ZwClose(hChannelIdKey);
|
|
}
|
|
|
|
if (pChannelIdKeyBasicInfo != NULL)
|
|
{
|
|
ExFreePoolWithTag(pChannelIdKeyBasicInfo, BDL_ULONG_TAG);
|
|
}
|
|
|
|
BDLDebug(
|
|
BDL_DEBUG_TRACE,
|
|
("%s %s: BDL!BDLGetChannels: Leave\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
return (status);
|
|
|
|
ErrorReturn:
|
|
|
|
goto Return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
BDLGetComponents
|
|
(
|
|
HANDLE hRegKey,
|
|
ULONG *pNumComponents,
|
|
BDL_COMPONENT **prgComponents
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
HANDLE hComponentsKey = NULL;
|
|
UNICODE_STRING UnicodeString;
|
|
KEY_FULL_INFORMATION ComponentsKeyFullInfo;
|
|
ULONG ReturnedSize;
|
|
ULONG i;
|
|
HANDLE hComponentIdKey = NULL;
|
|
KEY_BASIC_INFORMATION *pComponentIdKeyBasicInfo = NULL;
|
|
ULONG KeyBasicInfoSize = 0;
|
|
|
|
BDLDebug(
|
|
BDL_DEBUG_TRACE,
|
|
("%s %s: BDL!BDLGetComponents: Enter\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
*pNumComponents = 0;
|
|
*prgComponents = NULL;
|
|
|
|
//
|
|
// Open the "Components" key so it can be used to query all subkeys and values
|
|
//
|
|
status = BDLOpenSubkey(hRegKey, L"Components", &hComponentsKey);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetComponents: BDLOpenSubkey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Find out how many components there are
|
|
//
|
|
status = ZwQueryKey(
|
|
hComponentsKey,
|
|
KeyFullInformation,
|
|
&ComponentsKeyFullInfo,
|
|
sizeof(ComponentsKeyFullInfo),
|
|
&ReturnedSize);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetComponents: ZwQueryKey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Allocate the array of components
|
|
//
|
|
*prgComponents = ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
ComponentsKeyFullInfo.SubKeys * sizeof(BDL_COMPONENT),
|
|
BDL_ULONG_TAG);
|
|
|
|
if (*prgComponents == NULL)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetComponents: ExAllocatePoolWithTag failed\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
status = STATUS_NO_MEMORY;
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
*pNumComponents = ComponentsKeyFullInfo.SubKeys;
|
|
RtlZeroMemory(*prgComponents, ComponentsKeyFullInfo.SubKeys * sizeof(BDL_COMPONENT));
|
|
|
|
//
|
|
// Allocate a structure for querying key names that is large enough to hold all of them
|
|
//
|
|
KeyBasicInfoSize = sizeof(KEY_BASIC_INFORMATION) + ComponentsKeyFullInfo.MaxNameLen;
|
|
pComponentIdKeyBasicInfo = ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
KeyBasicInfoSize + 1,
|
|
BDL_ULONG_TAG);
|
|
|
|
if (pComponentIdKeyBasicInfo == NULL)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetComponents: ExAllocatePoolWithTag failed\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
status = STATUS_NO_MEMORY;
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Loop for each Component SubKey and get the relevant info
|
|
//
|
|
for (i = 0; i < ComponentsKeyFullInfo.SubKeys; i++)
|
|
{
|
|
//
|
|
// Get the name on the <Component Id> key
|
|
//
|
|
status = ZwEnumerateKey(
|
|
hComponentsKey,
|
|
i,
|
|
KeyBasicInformation,
|
|
pComponentIdKeyBasicInfo,
|
|
KeyBasicInfoSize,
|
|
&ReturnedSize);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetComponents: ZwEnumerateKey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Change the <Component ID> key string to a value
|
|
//
|
|
pComponentIdKeyBasicInfo->Name[pComponentIdKeyBasicInfo->NameLength / sizeof(WCHAR)] = L'\0';
|
|
RtlInitUnicodeString(&UnicodeString, pComponentIdKeyBasicInfo->Name);
|
|
RtlUnicodeStringToInteger(&UnicodeString, 16, &((*prgComponents)[i].ComponentId));
|
|
|
|
//
|
|
// Open up the <Component ID> key
|
|
//
|
|
status = BDLOpenSubkey(hComponentsKey, pComponentIdKeyBasicInfo->Name, &hComponentIdKey);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetComponents: BDLOpenSubkey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Get the component level controls
|
|
//
|
|
status = BDLGetControls(
|
|
hComponentIdKey,
|
|
&((*prgComponents)[i].NumControls),
|
|
&((*prgComponents)[i].rgControls));
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetComponents: BDLGetControls failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Get the channels in this component
|
|
//
|
|
status = BDLGetChannels(
|
|
hComponentIdKey,
|
|
&((*prgComponents)[i].NumChannels),
|
|
&((*prgComponents)[i].rgChannels));
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetComponents: BDLGetChannels failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
ZwClose(hComponentIdKey);
|
|
hComponentIdKey = NULL;
|
|
}
|
|
|
|
Return:
|
|
|
|
if (hComponentsKey != NULL)
|
|
{
|
|
ZwClose(hComponentsKey);
|
|
}
|
|
|
|
if (hComponentIdKey != NULL)
|
|
{
|
|
ZwClose(hComponentIdKey);
|
|
}
|
|
|
|
if (pComponentIdKeyBasicInfo != NULL)
|
|
{
|
|
ExFreePoolWithTag(pComponentIdKeyBasicInfo, BDL_ULONG_TAG);
|
|
}
|
|
|
|
BDLDebug(
|
|
BDL_DEBUG_TRACE,
|
|
("%s %s: BDL!BDLGetControls: Leave\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
return (status);
|
|
|
|
ErrorReturn:
|
|
|
|
goto Return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
BDLGetDeviceCapabilities
|
|
(
|
|
PDEVICE_OBJECT pPhysicalDeviceObject,
|
|
PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
LPWSTR pwszDeviceRegistryKeyName = NULL;
|
|
HANDLE hDeviceKey = NULL;
|
|
|
|
BDLDebug(
|
|
BDL_DEBUG_TRACE,
|
|
("%s %s: BDL!BDLGetDevicesCapabilities: Enter\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
//
|
|
// Build the top level registry key name
|
|
//
|
|
status = BDLBuildRegKeyPath(
|
|
pPhysicalDeviceObject,
|
|
pBDLExtension,
|
|
&pwszDeviceRegistryKeyName);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetDevicesCapabilities: BDLBuildRegKeyPath failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Open the top level device key so it can be used to query all subkeys and values
|
|
//
|
|
status = BDLOpenSubkey(NULL, pwszDeviceRegistryKeyName, &hDeviceKey);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetDevicesCapabilities: BDLOpenSubkey failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Get the device level controls
|
|
//
|
|
status = BDLGetControls(
|
|
hDeviceKey,
|
|
&(pBDLExtension->DeviceCapabilities.NumControls),
|
|
&(pBDLExtension->DeviceCapabilities.rgControls));
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetDevicesCapabilities: BDLGetControls failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// Get the components
|
|
//
|
|
status = BDLGetComponents(
|
|
hDeviceKey,
|
|
&(pBDLExtension->DeviceCapabilities.NumComponents),
|
|
&(pBDLExtension->DeviceCapabilities.rgComponents));
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
BDLDebug(
|
|
BDL_DEBUG_ERROR,
|
|
("%s %s: BDL!BDLGetDevicesCapabilities: BDLGetControls failed with %x\n",
|
|
__DATE__,
|
|
__TIME__,
|
|
status))
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
Return:
|
|
|
|
if (pwszDeviceRegistryKeyName != NULL)
|
|
{
|
|
ExFreePoolWithTag(pwszDeviceRegistryKeyName, BDL_ULONG_TAG);
|
|
}
|
|
|
|
if (hDeviceKey != NULL)
|
|
{
|
|
ZwClose(hDeviceKey);
|
|
}
|
|
|
|
BDLDebug(
|
|
BDL_DEBUG_TRACE,
|
|
("%s %s: BDL!BDLGetDevicesCapabilities: Leave\n",
|
|
__DATE__,
|
|
__TIME__))
|
|
|
|
return (status);
|
|
|
|
ErrorReturn:
|
|
|
|
BDLCleanupDeviceCapabilities(pBDLExtension);
|
|
|
|
goto Return;
|
|
}
|
|
|
|
|
|
VOID
|
|
BDLCleanupDeviceCapabilities
|
|
(
|
|
PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension
|
|
)
|
|
{
|
|
BDL_DEVICE_CAPABILITIES *pDeviceCapabilites = &(pBDLExtension->DeviceCapabilities);
|
|
ULONG i, j;
|
|
|
|
//
|
|
// Free device level control array
|
|
//
|
|
if (pDeviceCapabilites->rgControls != NULL)
|
|
{
|
|
ExFreePoolWithTag(pDeviceCapabilites->rgControls, BDL_ULONG_TAG);
|
|
pDeviceCapabilites->rgControls = NULL;
|
|
}
|
|
|
|
//
|
|
// Free component array
|
|
//
|
|
if (pDeviceCapabilites->rgComponents != NULL)
|
|
{
|
|
//
|
|
// Free each component
|
|
//
|
|
for (i = 0; i < pDeviceCapabilites->NumComponents; i++)
|
|
{
|
|
//
|
|
// Free component level control array
|
|
//
|
|
if (pDeviceCapabilites->rgComponents[i].rgControls != NULL)
|
|
{
|
|
ExFreePoolWithTag(pDeviceCapabilites->rgComponents[i].rgControls, BDL_ULONG_TAG);
|
|
}
|
|
|
|
//
|
|
// Free channel array
|
|
//
|
|
if (pDeviceCapabilites->rgComponents[i].rgChannels != NULL)
|
|
{
|
|
//
|
|
// Free each channel
|
|
//
|
|
for (j = 0; j < pDeviceCapabilites->rgComponents[i].NumChannels; j++)
|
|
{
|
|
//
|
|
// Free channel level controls, source lists, and products
|
|
//
|
|
if (pDeviceCapabilites->rgComponents[i].rgChannels[j].rgControls != NULL)
|
|
{
|
|
ExFreePoolWithTag(
|
|
pDeviceCapabilites->rgComponents[i].rgChannels[j].rgControls,
|
|
BDL_ULONG_TAG);
|
|
}
|
|
|
|
if (pDeviceCapabilites->rgComponents[i].rgChannels[j].rgSourceLists != NULL)
|
|
{
|
|
ExFreePoolWithTag(
|
|
pDeviceCapabilites->rgComponents[i].rgChannels[j].rgSourceLists,
|
|
BDL_ULONG_TAG);
|
|
}
|
|
|
|
if (pDeviceCapabilites->rgComponents[i].rgChannels[j].rgProducts != NULL)
|
|
{
|
|
ExFreePoolWithTag(
|
|
pDeviceCapabilites->rgComponents[i].rgChannels[j].rgProducts,
|
|
BDL_ULONG_TAG);
|
|
}
|
|
}
|
|
|
|
ExFreePoolWithTag(pDeviceCapabilites->rgComponents[i].rgChannels, BDL_ULONG_TAG);
|
|
}
|
|
}
|
|
|
|
ExFreePoolWithTag(pDeviceCapabilites->rgComponents, BDL_ULONG_TAG);
|
|
pDeviceCapabilites->rgComponents = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|