Функция RtlQueryRegistryValues (wdm.h)

Подпрограмма RtlQueryRegistryValues позволяет вызывающей системе запрашивать несколько значений из поддерев реестра с одним вызовом.

Синтаксис

NTSYSAPI NTSTATUS RtlQueryRegistryValues(
  [in]           ULONG                     RelativeTo,
  [in]           PCWSTR                    Path,
  [in, out]      PRTL_QUERY_REGISTRY_TABLE QueryTable,
  [in, optional] PVOID                     Context,
  [in, optional] PVOID                     Environment
);

Параметры

[in] RelativeTo

Указывает, является ли пути абсолютным путем реестра или относительно предопределенного пути в качестве одного из следующих.

Ценность Значение
RTL_REGISTRY_ABSOLUTE Путь — абсолютный путь к реестру.
RTL_REGISTRY_CONTROL Путь относительно \Registry\Machine\System\CurrentControlSet\Control.
RTL_REGISTRY_DEVICEMAP Путь относительно \Registry\Machine\Hardware\DeviceMap.
RTL_REGISTRY_SERVICES Путь относительно \Registry\Machine\System\CurrentControlSet\Services.
RTL_REGISTRY_USER Путь относительно \Registry\User\CurrentUser. (Для системного процесса это \User\. По умолчанию.)
RTL_REGISTRY_WINDOWS_NT Путь относительно \Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion.

Значение RelativeTo можно изменить побитовой инструкцией-ORing с одним из следующих флагов.

Флаг Значение
RTL_REGISTRY_OPTIONAL Указывает, что ключ, на который ссылается этот параметр, и параметр пути необязателен.
RTL_REGISTRY_HANDLE Указывает, что параметр пути фактически является дескриптором реестра.

[in] Path

Указатель на абсолютный путь реестра или путь относительно известного расположения, указанного параметром RelativeTo. Обратите внимание, что имена ключей в таком пути должны быть известны вызывающей, включая последний ключ в пути. Если указан флаг RTL_REGISTRY_HANDLE, этот параметр является дескриптором реестра для запроса непосредственно открытого ключа.

[in, out] QueryTable

Указатель на таблицу с одним или несколькими именами значений и именами вложенных ключей, в которых заинтересован вызывающий объект. Каждая запись таблицы содержит адрес указанной вызывающей функции QueryRoutine, которая будет вызываться для каждого имени значения, существующего в реестре. Таблица должна быть завершена с записью NULL таблицы, которая является записью таблицы с элементом NULLQueryRoutine и элементом NULLName. Структура записей таблицы запросов определяется следующим образом:

typedef struct _RTL_QUERY_REGISTRY_TABLE {
    PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine;
    ULONG Flags;
    PWSTR Name;
    PVOID EntryContext;
    ULONG DefaultType;
    PVOID DefaultData;
    ULONG DefaultLength;
} RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE;

Если вызывающий объект выделяет хранилище для таблицы запросов, на которую указывает параметр QueryTable, вызывающий объект отвечает за освобождение этого хранилища после возврата вызова RtlQueryRegistryValues.

QueryRoutine

Адрес функции QueryRoutine, которая вызывается с именем, типом, данными и длиной данных реестра. Если этот элемент и элемент Name являются null, он помечает конец таблицы.

Функция QueryRoutine объявлена следующим образом:

NTSTATUS
QueryRoutine (
    IN PWSTR ValueName,
    IN ULONG ValueType,
    IN PVOID ValueData,
    IN ULONG ValueLength,
    IN PVOID Context,
    IN PVOID EntryContext
    );

Дополнительные сведения см. в разделе QueryRoutine.

Флаги

Флаги для управления интерпретацией оставшихся элементов структуры RTL_QUERY_REGISTRY_TABLE. Для этого элемента определены следующие биты флагов.

Ценность Значение
RTL_QUERY_REGISTRY_SUBKEY имя этой записи таблицы — это еще один путь к разделу реестра, а все следующие записи таблицы предназначены для этого ключа, а не ключа, указанного параметром path. Это изменение фокуса длится до конца таблицы или до тех пор, пока не будет замечена другая RTL_REGISTRY_SUBKEY или RTL_QUERY_REGISTRY_TOPKEY запись. Каждая такая запись должна указывать путь относительно пути , указанного в вызове RtlQueryRegistryValues.
RTL_QUERY_REGISTRY_TOPKEY Сбрасывает текущий дескриптор раздела реестра до исходного, указанного параметрами RelativeTo и path. Это полезно для возврата к исходному узлу после убывания в подразделы с флагом RTL_QUERY_REGISTRY_SUBKEY.
RTL_QUERY_REGISTRY_REQUIRED Указывает, что это значение реестра должно существовать, если DefaultType = REG_NONE; в противном случае, если он не найден, RtlQueryRegistryValues немедленно завершает работу с кодом состояния STATUS_OBJECT_NAME_NOT_FOUND. Это происходит, если элемент NameNULL, а текущий ключ не имеет вложенных ключей или если Name указывает несуществующий подраздел. (Если этот флаг не указан, то при отсутствии совпадения дляNULLNameподпрограмма использует элемент DefaultValue в качестве значения. Если имяnull, а текущий ключ не имеет вложенных ключей, подпрограмма просто пропускает эту запись таблицы.)
RTL_QUERY_REGISTRY_NOVALUE Указывает, что несмотря на отсутствие name для этой записи таблицы, все, что вызывающий объект хочет, является обратным вызовом: то есть вызывающий объект не хочет перечислять все значения в текущем ключе. QueryRoutine вызывается с NULL для ValueData, REG_NONE для ValueTypeи ноль для ValueLength.
RTL_QUERY_REGISTRY_NOEXPAND Для значения реестра типа REG_EXPAND_SZ или REG_MULTI_SZ этот флаг переопределяет поведение по умолчанию, которое необходимо предварительно обработать значение реестра перед вызовом подпрограммы QueryRoutine. По умолчанию RtlQueryRegistryValues расширяет ссылки на переменные среды в значениях REG_EXPAND_SZ и перечисляет каждую строку, завершающуюся значением NULL, в REG_MULTI_SZ в отдельном вызове QueryRoutine, чтобы строки отображались как REG_SZ значения, имеющие те же ValueName. Если этот флаг задан, QueryRoutine получает необработанное значение REG_EXPAND_SZ или REG_MULTI_SZ из реестра. Дополнительные сведения о форматах данных для этих значений см. в KEY_VALUE_BASIC_INFORMATION.
RTL_QUERY_REGISTRY_DIRECT Элемент queryRoutine не используется (и должен быть NULL), а EntryContext указывает на буфер для хранения значения. Если вызывающий объект задает этот флаг, вызывающий объект должен дополнительно задать флаг RTL_QUERY_REGISTRY_TYPECHECK для защиты от переполнения буфера. Дополнительные сведения см. в разделе "Примечания".
RTL_QUERY_REGISTRY_TYPECHECK Используйте этот флаг с флагом RTL_QUERY_REGISTRY_DIRECT, чтобы убедиться, что тип REG_XXX сохраненного значения реестра соответствует типу вызывающего объекта. Если типы не соответствуют, вызов завершается ошибкой. Дополнительные сведения см. в разделе "Примечания".
RTL_QUERY_REGISTRY_DELETE Этот флаг используется для удаления ключей значений после запроса.

Начиная с Windows 2000 поддержка папки "Входящие" предоставляется для всех битов флагов в предыдущей таблице, за исключением RTL_QUERY_REGISTRY_TYPECHECK. Поддержка папки "Входящие" для RTL_QUERY_REGISTRY_TYPECHECK доступна начиная с Windows 8. Для более ранних версий Windows поддержка RTL_QUERY_REGISTRY_TYPECHECK предоставляется через Центр обновления Windows. Дополнительные сведения см. в разделе "Примечания".

Имя

Это имя значения, запрашиваемого вызывающим элементом. Если имяNULL, функция QueryRoutine, указанная для этой записи таблицы, вызывается для всех значений, связанных с текущим разделом реестра. Если установлен флаг RTL_QUERY_REGISTRY_DIRECT, необходимо указать значение, отличное отNULL для Name.

EntryContext

Если установлен флаг RTL_QUERY_REGISTRY_DIRECT, это указатель на буфер для хранения результата операции запроса для этого ключа. В противном случае это значение передается в качестве параметра EntryContextQueryRoutine.

DefaultType

Наименьший байт этого элемента указывает тип возвращаемых данных REG_XXX, если не найден соответствующий ключ, а флаг RTL_QUERY_REGISTRY_REQUIRED не указан. Укажите REG_NONE для типа по умолчанию. Если установлен флаг RTL_QUERY_REGISTRY_TYPECHECK, самый значительный байт этого члена указывает тип REG_XXX хранящегося значения реестра, которое ожидает вызывающий элемент. Биты от 8 до 23 этого элемента зарезервированы и должны быть нулевыми.

DefaultData

Указатель на возвращаемое значение по умолчанию, если не найден соответствующий ключ, и флаг RTL_QUERY_REGISTRY_REQUIRED не указан. Этот элемент игнорируется, если DefaultType = REG_NONE. В противном случае тип данных, на которые указывает DefaultData, должен соответствовать типу значения реестра, указанному элементом DefaultType . Дополнительные сведения о типах значений реестра см. в определении параметра Type в KEY_VALUE_BASIC_INFORMATION.

DefaultLength

Указывает длину в байтах элемента DefaultData. Если DefaultType REG_SZ, REG_EXPAND_SZ или REG_MULTI_SZ вызывающие элементы могут указывать ноль, чтобы указать, RtlQueryRegistryValues должен вычислить длину на основе значения данных по умолчанию. Если DefaultType = REG_NONE, этот элемент игнорируется.

[in, optional] Context

Указывает значение, переданное в качестве параметра контекста контекста функции QueryRoutine при каждом вызове.

[in, optional] Environment

Указатель на среду, используемую при расширении значений переменных в значениях реестра REG_EXPAND_SZ или указатель NULL (необязательно).

Возвращаемое значение

RtlQueryRegistryValues возвращает код NTSTATUS. Возможные возвращаемые значения:

Возвращаемый код Описание
STATUS_SUCCESS Вся таблица запросов успешно обработана.
STATUS_INVALID_PARAMETER Обработка таблицы запроса завершается недопустимой записью таблицы. Запись таблицы может быть недопустимой, если указанные флаги требуют queryRoutine или элемента Name неNULL, но было указано ЗНАЧЕНИЕ NULL.
STATUS_OBJECT_NAME_NOT_FOUND Параметр пути не соответствует допустимому ключу или обработке таблицы запросов, завершаемой записью с набором флагов RTL_QUERY_REGISTRY_REQUIRED и не найден соответствующий ключ. Это происходит, если элемент имени NULL, а текущий ключ не имеет вложенных ключей или если Имя указывает несуществующий подраздел.
STATUS_BUFFER_TOO_SMALL Флаг RTL_QUERY_REGISTRY_DIRECT задан, а буфер, указанный EntryContext, слишком мал для хранения данных значения ключа.
STATUS_OBJECT_TYPE_MISMATCH Флаг RTL_QUERY_REGISTRY_TYPECHECK задан, а тип хранимого значения реестра не соответствует типу вызывающего объекта.

RtlQueryRegistryValues также завершает обработку таблицы, если функция QueryRoutine для записи таблицы возвращает код ошибки NTSTATUS и возвращает этот код ошибки в качестве результата. (За одним исключением: если QueryRoutine возвращает STATUS_BUFFER_TOO_SMALL, код ошибки игнорируется.)

Замечания

Вызывающий объект задает начальный путь ключа и таблицу. Таблица содержит одну или несколько записей, описывающих ключевые значения и имена подразделов, в которых заинтересован вызывающий объект. Таблица завершается записью с элементом NULLQueryRoutine и элементом NULLName. Таблица должна быть выделена из непагированного пула.

Драйверы режима ядра должны указывать флаг RTL_QUERY_REGISTRY_NOEXPAND, чтобы предотвратить вызов подпрограмм переменных среды. Эти подпрограммы небезопасны, поэтому драйверы в режиме ядра не должны использовать их.

Осторожность

Если вы используете флаг RTL_QUERY_REGISTRY_DIRECT, ненадежное приложение в режиме пользователя может вызвать переполнение буфера. Переполнение буфера может произойти, если драйвер использует этот флаг для чтения значения реестра, к которому назначен неправильный тип. Во всех случаях драйвер, использующий флаг RTL_QUERY_REGISTRY_DIRECT, должен дополнительно использовать флаг RTL_QUERY_REGISTRY_TYPECHECK для предотвращения таких переполнений.

Если флаг RTL_QUERY_REGISTRY_TYPECHECK задан в записи таблицы, вызывающий объект должен указать ожидаемый тип REG_XXX в 8 наиболее важных битах (MSBS) 32-разрядной DefaultType элемент записи таблицы. Как показано в следующем примере кода, константу RTL_QUERY_REGISTRY_TYPECHECK_SHIFT, определяемую как 24, можно использовать в качестве количества сдвигов, необходимых для размещения ожидаемого REG_XXX типа в 8 MSBS элемента DefaultType.

RTL_QUERY_REGISTRY_TABLE QueryRegTable[2];    
...
QueryRegTable[0].DefaultType = (REG_SZ << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE;
...
QueryRegTable[1].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE;
...

Начиная с Windows 8, если RtlQueryRegistryValues обращается к ненадежному кусту, а вызывающий задает флаг RTL_QUERY_REGISTRY_DIRECT для этого вызова, вызывающий объект должен дополнительно задать флаг RTL_QUERY_REGISTRY_TYPECHECK. Нарушение этого правила вызовом из пользовательского режима вызывает исключение. Нарушение этого правила вызовом из режима ядра вызывает проверку ошибки 0x139 (KERNEL_SECURITY_CHECK_FAILURE).

Доверенными являются только системные hives. Вызов RtlQueryRegistryValues, который обращается к системным кустам, не вызывает исключение или ошибку, если установлен флаг RTL_QUERY_REGISTRY_DIRECT, и флаг RTL_QUERY_REGISTRY_TYPECHECK не задан. Однако, как рекомендуется, флаг RTL_QUERY_REGISTRY_TYPECHECK всегда следует задать, если установлен флаг RTL_QUERY_REGISTRY_DIRECT.

Аналогичным образом, в версиях Windows до Windows 8, как рекомендуется, вызов RtlQueryRegistryValues, который задает флаг RTL_QUERY_REGISTRY_DIRECT, должен дополнительно задать флаг RTL_QUERY_REGISTRY_TYPECHECK. Однако неисполнение этой рекомендации не приводит к исключению или проверке ошибок.

Ниже приведен список системных кустов:

  • \REGISTRY\MACHINE\HARDWARE

  • \REGISTRY\MACHINE\SOFTWARE

  • \REGISTRY\MACHINE\SYSTEM

  • \REGISTRY\MACHINE\SECURITY

  • \REGISTRY\MACHINE\SAM

Поддержка флага RTL_QUERY_REGISTRY_TYPECHECK доступна через Центр обновления Windows для Windows 7, Windows Vista, Windows Server 2003 и Windows XP. Дополнительные сведения об этом обновлении см. в уязвимостях в ядре Windows, которые могут разрешить повышение привилегий (2393802). В версиях этих операционных систем, которые не имеют этого обновления, вызывающий объект может использовать флаг RTL_QUERY_REGISTRY_TYPECHECK. Однако этот флаг игнорируется подпрограммой RtlQueryRegistryValues.

Начиная с пакета драйверов Windows (WDK) 8, флаг RTL_QUERY_REGISTRY_TYPECHECK определен в файле заголовка Wdm.h следующим образом:

#define RTL_QUERY_REGISTRY_TYPECHECK 0x00000100

Если запись не указывает флаг RTL_QUERY_REGISTRY_DIRECT, RtlQueryRegistryValues использует указанную функцию QueryRoutine, чтобы сообщить имя значения, тип, данные и длину данных в байтах вызывающей функции. Если элемент имени записи NULL, RtlQueryRegistryValues сообщает каждый прямой подраздел ключа. Если тип ключа REG_MULTI_SZ и флаг RTL_QUERY_REGISTRY_NOEXPAND не указан, подпрограмма вызывает QueryRoutine отдельно для каждой отдельной строки; в противном случае подпрограмма сообщает об этом как одно значение. Если запись указывает флаг RTL_QUERY_REGISTRY_DIRECT, RtlQueryRegistryValues сохраняет значение ключа в буфере, на который указывает элемент entryContext. Формат возвращаемых данных выглядит следующим образом.

Тип данных ключа Как возвращаются данные
Строка Юникода с завершением null (например, REG_SZ, REG_EXPAND_SZ). EntryContext должен указывать на инициализированную структуру UNICODE_STRING. Если элемент буфера UNICODE_STRINGNULL, подпрограмма выделяет хранилище строковых данных. В противном случае данные строки хранятся в буфере, на который буфер указывает.
REG_MULTI_SZ Необходимо указать флаг RTL_QUERY_REGISTRY_NOEXPAND для этого типа данных ключа. EntryContext указывает на инициализированную структуру UNICODE_STRING. Подпрограмма сохраняет значение ключа в виде одного строкового значения. Каждый отдельный компонент в строке завершается нулем. Если элемент буфера UNICODE_STRINGNULL, подпрограмма выделяет хранилище строковых данных. В противном случае данные строки хранятся в буфере, на который буфер указывает.
Нестроковые данные с размером, в байтах, <= sizeof(ULONG) Значение хранится в расположении памяти, указанном EntryContext.
Нестроковые данные с размером, в байтах, >sizeof(ULONG) Буфер, на который указывает EntryContext, должен начинаться со подписанного значения LONG. Величина значения должна указывать размер буфера в байтах. Если знак значения отрицательный, RtlQueryRegistryValues будет хранить только данные значения ключа. В противном случае он будет использовать первый ULONG в буфере для записи длины значения в байтах, второй ULONG для записи типа значения и остальной части буфера для хранения данных значений.

Если ошибка возникает на любом этапе обработки таблицы запросов, RtlQueryRegistryValues перестает обрабатывать таблицу и возвращает состояние ошибки.

Описание возможных значений REG_XXX см. в ZwSetValueKey.

Требования

Требование Ценность
целевая платформа Всеобщий
заголовка wdm.h (include Wdm.h, Ntddk.h, Ntifs.h)
библиотеки Ntoskrnl.lib
DLL Ntoskrnl.exe
IRQL PASSIVE_LEVEL

См. также

QueryRoutine

RtlZeroMemory

UNICODE_STRING

ZwEnumerateKey

ZwEnumerateValueKey

ZwSetValueKey