Реестр Windows

Аватар пользователя @mabu опубликовал

Реестр Windows или системный реестр — иерархическая база данных параметров и настроек в большинстве операционных систем Microsoft Windows. Реестр содержит информацию и настройки для аппаратного обеспечения, программного обеспечения, профилей пользователей, предустановки. Большинство изменений в Панели управления, ассоциации файлов, системные политики, список установленных программ фиксируются в реестре. Реестр Windows был введён для упорядочения информации, хранившейся до этого во множестве INI‐файлов, обеспечения единого механизма чтения‐записи настроек, избавления от проблем коротких имён файлов, отсутствия разграничения прав доступа и медленного доступа к INI‐файлам.

Историческая справка

Сам реестр как древовидная иерархическая база данных впервые появился в Windows 3.1 (апрель 1992). Это был всего один двоичный файл, который назывался REG.DAT и хранился в каталоге «C:». Реестр Windows 3.1 имел только одну ветку HKEY_CLASSES_ROOT. Он служил для связи DDE, а позднее и OLE-объектов. Одновременно c появлением реестра в Windows 3.1 появилась программа REGEDIT.EXE для просмотра и редактирования реестра.

Следующий шаг был сделан в Windows NT 3.1 (июль 1993). Произошёл отказ от INI‐файлов как основных файлов конфигурации. На «регистрационную базу» (реестр) была переведена вся конфигурация системы. Основой конфигурации системы стал реестр. Он имел 4 корневых раздела: HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER, HKEY_CLASSES_ROOT и HKEY_USERS. Реестр стал «сборным»: на диске он хранился в файлах: DEFAULT, SOFTWARE, SYSTEM, а при запуске системы из этих файлов собиралась единая база данных.

Реестр в том виде, как его использует Windows и как видит его пользователь в процессе использования программ работы с реестром, формируется из различных данных. Вначале, в процессе установки и настройки Windows, на диске формируются файлы, в которых хранится часть данных относительно конфигурации системы. Затем, в процессе каждой загрузки системы а также в процессе каждого входа и выхода каждого из пользователей, формируется некая виртуальная сущность, называемая «реестром» — объект ядра «REGISTRY». Данные для формирования «реестра» частично берутся из тех самых файлов (Software, System) и частично из информации, собранной ntdetect.com при загрузке Windows. То есть часть данных реестра хранится в файлах, а часть данных формируется в процессе загрузки Windows.

Внутреннее устройство

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

Компьютер
│
├───HKEY_CLASSES_ROOT
│   │
│   ├───Раздел — Параметр по умолчанию
│   │   └───Именованный параметр — Значение
│   │
│   └───Раздел
│       ├───Именованный параметр — Значение
│       ├───Именованный параметр — Значение
│       └───Именованный параметр — Значение
│
├───HKEY_CURRENT_USER
│   │
│   ├───Раздел
│   │   ├───Именованный параметр — Значение
│   │   │
│   │   └───Раздел — Параметр по умолчанию
│   │       └───Именованный параметр — Значение
│   │
│   └───Раздел — Параметр по умолчанию
│       ├───Именованный параметр — Значение
│       ├───Именованный параметр — Значение
│       └───Именованный параметр — Значение
│
├───HKEY_LOCAL_MACHINE
│   │
│   └───…
│
├───HKEY_USERS
│   │
│   └───…
│
└───HKEY_CURRENT_CONFIG
    │
    └───…

Если открыть редактор реестра regedit, то можно увидеть пять основных корневых разделов реестра.

Стандартный разделКраткое названиеОписание
HKEY_CLASSES_ROOTHKCRПредназначается для хранения зарегистрированных типов файлов и классов. Это не настоящий корневой раздел, а всего лишь ссылка на HKEY_LOCAL_MACHINE
HKEY_CURRENT_USERHKCUЗдесь хранятся настройки текущего пользователя, например: переменные среды, данные о группах программ, цветах, принтерах, сетевых подключениях и настройках приложений. Не является настоящим разделом, это ссылка на один из подразделов из HKEY_USERS
HKEY_LOCAL_MACHINEHKLMЗдесь хранятся настройки операционной системы и программ для всех пользователей
HKEY_USERSHKUВ этот раздел подключаются кусты всех загруженных подреестров профилей пользователей
HKEY_CURRENT_CONFIGHKCCсведения о настройке оборудования, является ссылкой на HKEY_LOCAL_MACHINEProfiles

Этот ключ поддерживается начиная с Windows 7 и Server 2008.

Дополнительный разделКраткое названиеОписание
HKEY_CURRENT_USER_LOCAL_SETTINGSнетЗдесь хранятся настройки текущего пользователя для локального компьютера. Эти настройки содержат неперемещаемые данные профиля пользователя.

Также существуют нестандартные разделы, редактор реестра их не показывает.

Нестандартный разделОписание
HKEY_PERFORMANCE_DATAЗдесь собирается информация о счётчиках производительности системы. Данные фактически не хранятся в реестре; функции реестра заставляют систему собирать данные из своего источника.

Только три раздела реестра являются «настоящими» корневыми, остальные являются ссылками на подразделы из HKEY_LOCAL_MACHINE.

Хранение настроек в реестре

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

Настройки для всех пользователей

Используется раздел HKEY_LOCAL_MACHINE:

HKEY_LOCAL_MACHINE\Software\Имя организации\Название продукта

Программа должна корректно работать при отсутствии этой ветки или какого‐либо параметра в ней, используя значения по умолчанию. Запись в HKEY_LOCAL_MACHINE обычно разрешена только администраторам, поэтому многие программы обходятся без этого пункта.

Настройки для текущего пользователя

Используется раздел HKEY_CURRENT_USER:

HKEY_CURRENT_USER\Software\Имя организации\Название продукта

Если какие‐либо параметры отсутствуют в HKEY_CURRENT_USER, то берутся параметры из HKEY_LOCAL_MACHINE, а если и там нет, то берутся параметры по умолчанию.

Если какие‐либо параметры существуют как в ветке HKEY_LOCAL_MACHINE, так и в ветке HKEY_CURRENT_USER, то HKEY_CURRENT_USER имеют приоритет.

Раздел HKEY_CURRENT_USER хранится в файле NTUSER.DAT в профиле пользователя, что делает настройки перемещаемыми между пользователями домена. Запись в HKEY_CURRENT_USER разрешена текущему пользователю.

Типы данных параметров реестра

Параметры реестра могут хранить данные в различных форматах. При создании параметра его тип сохраняется в реестре и затем используется в функциях чтения значений.

REG_BINARY:
Любые двоичные данные.
REG_DWORD:
32‐битное число.
REG_QWORD:
64‐битное число.
REG_SZ:
Строка с нулевым символом на конце.
REG_EXPAND_SZ:
Строка с нулевым символом на конце, в которой могут использоваться переменные среды, такие как %PATH%.
REG_MULTI_SZ:
Список строк, каждая из которых заканчивается нулевым символом + ещё один нулевой символ в конце списка.

Если данные имеют тип REG_SZ, REG_EXPAND_SZ или REG_MULTI_SZ, то возможна ситуация, что строка была сохранена без конечного нулевого символа. При чтении строки из реестра необходимо убедиться, что строка правильно завершена перед её использованием, иначе может произойти выход за границы буфера. Обрати внимание, что список строк REG_MULTI_SZ должен иметь два завершающих нулевых символа, один для собственно строки, второй как указание на завершение списка.

При записи строки в реестр необходимо указать длину строки включая конечный нулевой символ. Общей ошибкой является использование функции Len (strlen в Си, lstrlen в WinAPI) для определения длины строки, так как функция Len возвращает количество символов в строке не включая завершающий нулевой символ. Длина строки должна быть рассчитана следующим образом: Len(string) + 1.

Список строк REG_MULTI_SZ заканчивается нулевым символом, который интерпретируется как пустая строка. Таким образом в списке нельзя сохранить пустую строку.

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

Безопасность раздела реестра и права доступа

В следующей таблице перечислены конкретные права доступа для объектов раздела реестра.

Флаг Описание
KEY_ALL_ACCESS Разрешаются любые действия над разделом: чтение, запись, перечисление подразделов. Является комбинацией флагов STANDARD_RIGHTS_REQUIRED, KEY_QUERY_VALUE, KEY_SET_VALUE, KEY_CREATE_SUB_KEY, KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY и KEY_CREATE_LINK
KEY_READ Разрешается чтение раздела, параметров и подразделов, является комбинацией флагов STANDARD_RIGHTS_READ, KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS и KEY_NOTIFY
KEY_QUERY_VALUE Разрешается чтение параметров раздела
KEY_ENUMERATE_SUB_KEYS Разрешается перечисление подразделов данного раздела
KEY_WRITE разрешается запись параметров, является комбинацией флагов STANDARD_RIGHTS_WRITE, KEY_SET_VALUE и KEY_CREATE_SUB_KEY
KEY_SET_VALUE Разрешается создание, удаление и изменение параметров в разделе
KEY_CREATE_SUB_KEY Разрешается создание подразделов в текущем разделе
KEY_NOTIFY Разрешается использовать ключ для уведомлений об изменениях в разделе и подразделах
KEY_EXECUTE То же, что и KEY_READ
KEY_CREATE_LINK Зарезервировано для системы
KEY_WOW64_32KEY 64‐битное приложение должно открыть 32‐битную версию реестра
KEY_WOW64_64KEY 64‐битное приложение должно открыть 64‐битную версию реестра

При вызове функции RegOpenKeyEx система проверяет запрошенные права доступа. Если пользователь не имеет правильного доступа к разделу реестра, операция открытия завершается неудачей.

Ограничения

Имена разделов, подразделов и параметров не чувствительны к регистру символов.

Имя раздела не должно превышать 255 символов.

Длина имени параметра раздела не должна превышать 16383 юникодных символа (включая нулевой).

Значение параметра может занимать всю доступную память, но рекомендуется использовать не более 2048 байт.

Подразделы не должны превышать 512 уровней вложенности. Одновременно можно создать не более 32 уровней вложенности.

Функции

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

Функции Описание
RegOpenKeyEx Открывает указанный существующий раздел реестра
RegCreateKeyEx Создаёт указанный раздел реестра. Если ключ уже существует, функция открывает его.
RegCloseKey Закрывает открытый раздел реестра.
RegQueryInfoKey Получает информацию о разделе.
RegQueryValueEx Читает значение параметра.
RegSetValueEx Записывает значение параметра.
RegEnumKeyEx Получает список подразделов.
RegEnumValue Получает список параметров подраздела.
RegNotifyChangeKeyValue Уведомляет приложение об изменениях в подразделе.

RegOpenKeyEx

Открывает существующий раздел реестра.

Declare Function RegOpenKeyEx Alias "RegOpenKeyExW"( _
    ByVal hKey As HKEY, _
    ByVal lpSubKey As LPCWSTR, _
    ByVal ulOptions As DWORD, _
    ByVal samDesired As REGSAM, _
    ByVal phkResult As PHKEY _
)As LONG

Параметры

hKey:
Описатель открываемого раздела, который может быть получен функциями RegCreateKeyEx и RegOpenKey. Также действуют стандартные описатели корневых разделов.
lpSubKey:
Указатель на строку с подразделом.
ulOptions:
Дополнительные опции. Установи этот параметр в 0 или REG_OPTION_OPEN_LINK для открывания символической ссылки. Символические ссылки используются только в крайней необходимости.
samDesired:
Требуемый доступ к разделу, в соответствии с таблицей.
phkResult:
Указатель на переменную, куда будет записан дескриптор открытого ключа. Если ключ не является одним из предопределённых разделов реестра, то следует вызвать RegCloseKey после завершения использования дескриптора.

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

При успешном выполнении функция возвращает ERROR_SUCCESS.

Если функция завершается неудачно, возвращаемое значение представляет собой ненулевой код ошибки, определенный в winerror.h. Ты можешь использовать функцию FormatMessage с флагом FORMAT_MESSAGE_FROM_SYSTEM, чтобы получить общее описание ошибки.

RegCreateKeyEx

Создаёт подраздел в реестре. Если подраздел уже существует, то функция открывает его.

Declare Function RegCreateKeyEx Alias "RegCreateKeyExW"( _
    ByVal hKey As HKEY, _
    ByVal lpSubKey As LPCWSTR, _
    ByVal Reserved As DWORD, _
    ByVal lpClass As LPWSTR, _
    ByVal dwOptions As DWORD, _
    ByVal samDesired As REGSAM, _
    ByVal lpSecurityAttributes As LPSECURITY_ATTRIBUTES, _
    ByVal phkResult As PHKEY, _
    ByVal lpdwDisposition As LPDWORD _
)As LONG

Параметры

hKey:
Описатель открываемого раздела, который может быть получен функциями RegCreateKeyEx и RegOpenKey. Раздел должен быть открыт с правами KEY_CREATE_SUB_KEY. Также действуют стандартные описатели корневых разделов.
lpSubKey:
Указатель на строку с подразделом.
Reserved:
Зарезервировано. Следует устанавливать в 0.
lpClass:
Указатель на строку, которая содержит класс этого раздела. Может быть проигнорирован и равен NULL. Используется для подключения к удаленному реестру.
dwOptions:
Опции открытия раздела. Может принимать одну из следующих констант:
samDesired:
Требуемый доступ к разделу, в соответствии с таблицей.
lpSecurityAttributes:
Указатель на структуру SECURITY_ATTRIBUTES, которая определяет, может ли возвращаемый дескриптор быть унаследован дочерними процессами. Если lpSecurityAttributes имеет значение NULL, дескриптор не может быть унаследован.
phkResult:
Указатель на переменную, куда будет записан дескриптор открытого ключа. Если ключ не является одним из предопределённых разделов реестра, то следует вызвать RegCloseKey после завершения использования дескриптора.
lpdwDisposition:
Указатель на переменную, куда будет функция запишет результат открытия или создания подраздела реестра. Если раздел ранее существовал, то функция запишет сюда константу REG_OPENED_EXISTING_KEY, если раздел был создан, то функция запишет REG_CREATED_NEW_KEY. Этот параметр может быть NULL.

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

При успешном выполнении функция возвращает ERROR_SUCCESS.

Если функция завершается неудачно, возвращаемое значение представляет собой ненулевой код ошибки, определенный в winerror.h. Ты можешь использовать функцию FormatMessage с флагом FORMAT_MESSAGE_FROM_SYSTEM, чтобы получить общее описание ошибки.

Замечания

Функция RegCreateKeyEx создаёт разделы без параметров. Можно воспользоваться функцией RegSetValueEx для создания параметров.

Функция создаёт все подразделы в пути, если они не существовали. Например, приложение может создать подраздел глубиной в четыре уровня одновременно с тремя предыдущими подразделами, указав строку следующего вида для параметра lpSubKey:

subkey1\subkey2\subkey3\subkey4

Обрати внимание, что это поведение приведет к созданию нежелательных ключей, если существующий ключ в пути будет написан неправильно.

Приложение не может создать ключ, который является прямым потомком HKEY_USERS или HKEY_LOCAL_MACHINE. Приложение может создавать подразделы на более низких уровнях деревьев HKEY_USERS или HKEY_LOCAL_MACHINE.

Если твоя служба или приложение олицетворяют разных пользователей, не используй эту функцию с HKEY_CURRENT_USER. Вместо этого вызови функцию RegOpenCurrentUser.

RegCloseKey

Закрывает описатель реестра, уничтожает объект ядра и освобождает память.

Declare Function RegCloseKey( _
	ByVal hKey As HKEY _
)As LONG

Параметры

hKey:
Описатель открытого раздела, который больше не нужен.

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

При успешном выполнении функция возвращает ERROR_SUCCESS.

Если функция завершается неудачно, возвращаемое значение представляет собой ненулевой код ошибки, определенный в winerror.h. Ты можешь использовать функцию FormatMessage с флагом FORMAT_MESSAGE_FROM_SYSTEM, чтобы получить общее описание ошибки.

Замечания

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

Функция RegCloseKey не обязательно записывает информацию в реестр перед возвратом; для сброса данных на жёсткий диск может потребоваться до нескольких секунд. Если приложение должно явно записать информацию реестра на жёсткий диск, оно может использовать функцию RegFlushKey. RegFlushKey, однако, использует много системных ресурсов и должна вызываться только в случае необходимости.

RegQueryInfoKey

Получает информацию о разделе реестра: имя класса, поличество подразделов и параметров, дату последней модификации.

Declare Function RegQueryInfoKey Alias "RegQueryInfoKeyW"( _
    ByVal hKey As HKEY, _
    ByVal lpClass As LPWSTR, _
    ByVal lpcchClass As LPDWORD, _
    ByVal lpReserved As LPDWORD, _
    ByVal lpcSubKeys As LPDWORD, _
    ByVal lpcbMaxSubKeyLen As LPDWORD, _
    ByVal lpcbMaxClassLen As LPDWORD, _
    ByVal lpcValues As LPDWORD, _
    ByVal lpcbMaxValueNameLen As LPDWORD, _
    ByVal lpcbMaxValueLen As LPDWORD, _
    ByVal lpcbSecurityDescriptor As LPDWORD, _
    ByVal lpftLastWriteTime As PFILETIME _
)As LONG

Параметры

hKey:
Описатель открываемого раздела, который может быть получен функциями RegCreateKeyEx и RegOpenKey. Раздел должен быть открыт с правами KEY_QUERY_VALUE. К стандартным описателям корневых разделов добавляется ключ HKEY_PERFORMANCE_DATA.
lpClass:
Указатель на строку, куда будет записано имя класса раздела. Может быть NULL.
lpcchClass:
Указатель на переменную, определяющую размер буфера, на который указывает параметр lpClass, в символах. Размер должен включать завершающий нулевой символ. Функция записывает сюда длину строки класса, хранящейся в буфере без учёта завершающего нулевого символа. Если буфер недостаточно велик, функция возвращает ERROR_MORE_DATA, а переменная содержит размер строки в символах, не считая завершающего нулевого символа. Если lpClass установлен в NULL, то lpcchClass может быть NULL. Если параметр lpClass не NULL, а параметр lpcchClass равен NULL, то функция возвращает ERROR_INVALID_PARAMETER.
lpReserved:
Зарезервировано. Должно быть NULL.
lpcSubKeys:
Указатель на переменную, куда будет записано количество подразделов в текущем разделе. Может быть NULL.
lpcbMaxSubKeyLen:
Указатель на переменную, куда будет записана длина самого длинного имени подраздела без учёта нулевого символа. Может быть NULL.
lpcbMaxClassLen:
Указатель на переменную, куда будет записана длина самого длинного имени класса подраздела без учёта нулевого символа. Может быть NULL.
lpcValues:
Указатель на переменную, куда будет записано количество параметров в разделе. Может быть NULL.
lpcbMaxValueNameLen:
Указатель на переменную, куда будет записана длина самого длинного имени параметра в разделе. Может быть NULL.
lpcbMaxValueLen:
Указатель на переменную, куда будет записана длина самого большого значения параметра в разделе, в байтах. Может быть NULL.
lpcbSecurityDescriptor:
Указатель на переменную, куда будет записана длина дескриптора защиты раздела, в байтах. Может быть NULL.
lpftLastWriteTime:
Указатель на структуру FILETIME, куда будет записана дата последней модификации раздела или его параметров. Может быть NULL.

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

При успешном выполнении функция возвращает ERROR_SUCCESS.

Если функция завершилась ошибкой, то возвращается код ошибки.

RegQueryValueEx

Получает значение параметра раздела реестра.

Declare Function RegQueryValueEx Alias "RegQueryValueExW"( _
    ByVal hKey As HKEY, _
    ByVal lpValueName As LPCWSTR, _
    ByVal lpReserved As LPDWORD, _
    ByVal lpType As LPDWORD, _
    ByVal lpData As LPBYTE, _
    ByVal lpcbData As LPDWORD _
)As LONG

Параметры

hKey:
Описатель открываемого раздела, который может быть получен функциями RegCreateKeyEx и RegOpenKey. Раздел должен быть открыт с правами KEY_QUERY_VALUE. К стандартным описателям корневых разделов добавляется ключ HKEY_PERFORMANCE_DATA.
lpValueName:
Указатель на строку, содержащую название параметра. Если равно NULL или пустой строке "", то возвращается значение «по умолчанию». Если параметр с таким именем не существует, то функция вернёт ERROR_FILE_NOT_FOUND.
lpReserved:
Зарезервировано. Должно быть NULL.
lpType:
Указатель на переменную, куда будет записан тип данных параметра. Может быть NULL, если тип данных не требуется.
lpData:
Указатель на буфер, куда будет записано значение параметра. Может быть NULL, в этом случае значение параметра не возвращается, такой метод используется для вычисления размера требуемого буфера.
lpcbData:
Указатель на переменную с размером буфера под значение параметра в байтах. Функция запишет сюда размер данных, скопированных в буфер, в байтах. Если данные носят текстовый характер, то в это число включается и нулевой символ. Если размер буфера недостаточен для сохранения данных, функция запишет требуемый размер буфера, вернёт ERROR_MORE_DATA, а содержимое lpData оставит неопределённым.

Если hKey указывает на HKEY_PERFORMANCE_DATA и буфер lpData недостаточно велик, чтобы содержать все возвращаемые данные, RegQueryValueEx возвращает ERROR_MORE_DATA, и значение, возвращаемое через параметр lpcbData, не определено. Это связано с тем, что размер данных производительности может изменяться от одного вызова к другому. В этом случае необходимо увеличить размер буфера и снова вызвать RegQueryValueEx, передав обновлённый размер буфера в параметре lpcbData. Повторяй это до тех пор, пока функция не завершится успешно. Тебе нужно поддерживать отдельную переменную, чтобы отслеживать размер буфера, потому что значение, возвращаемое lpcbData, непредсказуемо.

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

При успешном выполнении функция возвращает ERROR_SUCCESS.

Если функция завершилась ошибкой, то возвращается код ошибки.

Если буфер lpData слишком мал, функция возвращает ERROR_MORE_DATA.

Если параметра lpValueName не существует, функция возвращает ERROR_FILE_NOT_FOUND.

Замечания

Функция предоставляет возможность вначале проверить каков размер данных в параметре, отправив NULL в lpData. Это позволяет выделять память под значение параметра динамически, по ходу выполнения программы.

Если данные имеют тип REG_SZ, REG_MULTI_SZ или REG_EXPAND_SZ, то строка, возможно, была сохранена без завершающего нулевого символа. Поэтому, даже если функция возвращает ERROR_SUCCESS, приложение должно убедиться, что строка правильно завершена перед её использованием; в противном случае может произойти выход за границы буфера.

При запросе значений объектов производительности из раздела HKEY_PERFORMANCE_DATA возвращаемая структура данных иногда содержит данные других объектов, явно не указанных в функции RegQueryValueEx. Для HKEY_PERFORMANCE_DATA это нормальное поведение, приложение должно быть готово всегда искать запрошенный объект в полученных данных.

RegSetValueEx

Устанавливает значение параметра реестра. Если такого параметра не существовало в подразделе, то он будет создан.

Declare Function RegSetValueEx Alias "RegSetValueExW"( _
    ByVal hKey As HKEY, _
    ByVal lpValueName As LPCWSTR, _
    ByVal Reserved As DWORD, _
    ByVal dwType As DWORD, _
    ByVal lpData As Const UBYTE Ptr, _
    ByVal cbData As DWORD _
)As LONG

Параметры

hKey:
Описатель открываемого раздела, который может быть получен функциями RegCreateKeyEx и RegOpenKey. Раздел должен быть открыт с правами KEY_SET_VALUE. Также действуют стандартные описатели корневых разделов.
lpValueName:
Указатель на строку, содержащую название параметра. Если равно NULL, то устанавливается значение «по умолчанию». Если параметр с таким именем не существует, то он будет создан.
lpReserved:
Зарезервировано. Должно быть NULL.
dwType:
Тип данных параметра.
lpData:
Указатель на буфер, содержащий значение параметра. Строковые данные должны заканчиваться завершающим нулевым символом.
cbData:
Размер буфера под параметр в байтах. Для числовых данных достаточно указать SizeOf(REG_DWORD) или SizeOf(REG_QWORD), для строк необходимо учитывать все нулевые символы, например, так: ((Длина строки + 1) * SizeOf(WString)).

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

При успешном выполнении функция возвращает ERROR_SUCCESS.

Если функция завершается неудачно, возвращаемое значение представляет собой ненулевой код ошибки, определенный в winerror.h. Ты можешь использовать функцию FormatMessage с флагом FORMAT_MESSAGE_FROM_SYSTEM, чтобы получить общее описание ошибки.

Замечания

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

Такие данные как значки, точечные рисунки, исполняемые файлы необходимо сохранять на диске.

RegEnumKeyEx

Перечисляет подразделы раздела реестра.

Declare Function RegEnumKeyEx Alias "RegEnumKeyExW"( _
    ByVal hKey As HKEY, _
    ByVal dwIndex As DWORD, _
    ByVal lpName As LPWSTR, _
    ByVal lpcchName As LPDWORD, _
    ByVal lpReserved As LPDWORD, _
    ByVal lpClass As LPWSTR, _
    ByVal lpcchClass As LPDWORD, _
    ByVal lpftLastWriteTime As PFILETIME _
)As LONG

Параметры

hKey:
Описатель открываемого раздела, который может быть получен функциями RegCreateKeyEx и RegOpenKey. Раздел должен быть открыт с правами KEY_ENUMERATE_SUB_KEYS. К стандартным описателям корневых разделов добавляется ключ HKEY_PERFORMANCE_DATA.
dwIndex:
Индекс подраздела. При первом вызове этот параметр должен быть равен нулю, при последующих — увеличиваться на единицу. Подразделы не упорядочены, функция может возвращать подразделы в любом порядке.
lpName:
Указатель на строку‐буфер, куда будет записано имя подраздела.
lpcchName:
Указатель на переменную, где хранится длина строки‐буфера имени подраздела в символах включая нулевой. Если функция выполнится успешно, то сюда будет записана длина имени подраздела без учёта нулевого символа.
lpReserved:
Зарезервировано. Должно быть NULL.
lpClass:
Указатель на строку‐буфер, куда будет записано имя класса раздела. Может быть NULL.
lpcchClass:
Указатель на переменную, где хранится длина строки‐буфера имени класса подраздела в символах, включая нулевой. Если функция выполнится успешно, то сюда будет записана длина имени класса подраздела без учёта нулевого символа. Может быть NULL если строка‐буфер для имени класса подраздела равна NULL.
lpftLastWriteTime:
Указатель на структуру FILETIME, куда будет записана дата последней модификации подраздела. Может быть NULL.

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

При успешном выполнении функция возвращает ERROR_SUCCESS.

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

Замечания

Для перечисления подразделов приложение должно вызвать функцию RegEnumKeyEx с параметром dwIndex равным нулю. Затем каждый раз увеличивать dwIndex на единицу и вызывать функцию снова, до тех пор, пока не будут перечислены все подразделы: в этом случае функция вернёт ERROR_NO_MORE_ITEMS или ошибку.

Приложение также может установить dwIndex в индекс последнего подраздела при первом вызове функции и уменьшать индекс до тех пор, пока не будет перечислен подраздел с индексом 0. Чтобы получить индекс последнего подраздела, используй функцию RegQueryInfoKey.

RegEnumValue

Перечисляет параметры раздела реестра.

Declare Function RegEnumValue Alias "RegEnumValueW"( _
    ByVal hKey As HKEY, _
    ByVal dwIndex As DWORD, _
    ByVal lpValueName As LPWSTR, _
    ByVal lpcchValueName As LPDWORD, _
    ByVal lpReserved As LPDWORD, _
    ByVal lpType As LPDWORD, _
    ByVal lpData As LPBYTE, _
    ByVal lpcbData As LPDWORD _
)As LONG

Параметры

hKey:
Описатель открываемого раздела, который может быть получен функциями RegCreateKeyEx и RegOpenKey. Раздел должен быть открыт с правами KEY_QUERY_VALUE. К стандартным описателям корневых разделов добавляется ключ HKEY_PERFORMANCE_DATA.
dwIndex:
Индекс параметра. При первом вызове этот параметр должен быть равен нулю, при последующих — увеличиваться на единицу. Параметры не упорядочены, функция может возвращать параметры в любом порядке.
lpValueName:
Указатель на строку‐буфер, куда будет записано имя параметра.
lpcchValueName:
Указатель на переменную, где хранится длина строки‐буфера имени параметра в символах включая нулевой. Если функция выполнится успешно, то сюда будет записана длина имени параметра без учёта нулевого символа.
lpReserved:
Зарезервировано. Должно быть NULL.
lpType:
Указатель на переменную, куда будет записан тип данных параметра. Может быть NULL.
lpData:
Указатель на буфер, куда будет записано значение параметра. Если указать NULL, то функция заполнит lpcbData требуемой длиной буфера.
lpcbData:
Указатель на переменную с размером буфера под значение параметра в байтах. Функция запишет сюда размер данных, скопированных в буфер. Может быть NULL, только если lpData равно NULL.

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

При успешном выполнении функция возвращает ERROR_SUCCESS.

Если буфер, размер буфера, указанный в lpcbData недостаточен для сохранения данных, то функция вернёт ERROR_MORE_DATA и запишет требуемый размер буфера в lpcbData.

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

Замечания

Для перечисления параметров подраздела реестра приложение должно вызвать функцию RegEnumValue с параметром dwIndex равным нулю. Затем каждый раз увеличивать этот параметр на единицу и вызывать функцию снова, до тех пор, пока не будут перечислены все параметры, в этом случае функция вернёт ERROR_NO_MORE_ITEMS или ошибку.

Также можно перечислять параметры в обратном порядке, установив параметр dwIndex равным максимальному индексу параметра, возвращённому функцией ReqQueryValue, и уменьшая его на единицу при каждом вызове функции до нуля.

Функция возвращает параметры подраздела без всякой сортировки.

RegNotifyChangeKeyValue

Уведомляет приложение об изменении в разделе реестра.

Declare Function RegNotifyChangeKeyValue( _
    ByVal hKey As HKEY, _
    ByVal bWatchSubtree As WINBOOL, _
    ByVal dwNotifyFilter As DWORD, _
    ByVal hEvent As HANDLE, _
    ByVal fAsynchronous As WINBOOL _
)As LONG

Параметры

hKey:
Описатель открываемого раздела, который может быть получен функциями RegCreateKeyEx и RegOpenKey. Раздел должен быть открыт с правами KEY_NOTIFY. Также действуют стандартные описатели корневых разделов.
bWatchSubtree:
Если этот параметр равен TRUE, то функция будет следить за изменениями в подразделах, если FALSE то только в текущем разделе.
dwNotifyFilter:
Указывает, о каких изменениях следуем уведомлять приложение. Может быть комбинацией из следующих значений:
hEvent:
Описатель объекта ядра «событие». Если fAsynchronous установлен в TRUE, то функция возвращает значение немедленно и будет отправлять уведомления через указанное событие. Если fAsynchronous равно FALSE, то hEvent игнорируется.
fAsynchronous:
Если установлен в TRUE, то функция возвращает значение немедленно и будет отправлять уведомления через указанное событие, в этом случае hEvent должен быть действительным объектом ядра «событие». Если fAsynchronous равно FALSE, то hEvent игнорируется.

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

При успешном выполнении функция возвращает ERROR_SUCCESS.

Если функция завершается неудачно, возвращаемое значение представляет собой ненулевой код ошибки, определенный в winerror.h. Ты можешь использовать функцию FormatMessage с флагом FORMAT_MESSAGE_FROM_SYSTEM, чтобы получить общее описание ошибки.

Замечания

Функция уведомляет об одном изменении. Чтобы получить уведомление о следующем, необходимо вызвать её снова.

Примеры

Чтение и запись настроек приложения

В этом примере сохраним и считаем из реестра имя пользователя и размеры окна приложения «Офис» вымышленной корпорации «Большие программы» в профиле пользователя.

#define unicode
#include "windows.bi"

Const RegSection = "Software\Большие программы\Офис"
Const UserNameKey = "Пользователь"
Const WidthKey = "Width"
Const HeightKey = "Height"

' Запись параметров
Scope
    Dim reg As HKEY = Any
    Dim lpdwDisposition As DWORD = Any

    ' Открыть раздел реестра в профиле текущего пользователя
    Dim hr As Long = RegCreateKeyEx(HKEY_CURRENT_USER, @RegSection, 0, 0, 0, KEY_SET_VALUE, NULL, @reg, @lpdwDisposition)
    If hr <> ERROR_SUCCESS Then
        End(1)
    End If

    ' Записать ширину окна
    Dim WindowWidth As DWORD = 640
    hr = RegSetValueEx(reg, @WidthKey, 0, REG_DWORD, CPtr(Byte Ptr, @WindowWidth), SizeOf(DWORD))

    ' Записать высоту окна
    Dim WindowHeight As DWORD = 480
    hr = RegSetValueEx(reg, @HeightKey, 0, REG_DWORD, CPtr(Byte Ptr, @WindowHeight), SizeOf(DWORD))

    ' Записать имя пользователя
    Dim UserName As WString Ptr = @"Алексей"
    hr = RegSetValueEx(reg, @UserNameKey, 0, REG_SZ, CPtr(Byte Ptr, UserName), (Len(UserName) + 1) * SizeOf(WString))

    RegCloseKey(reg)
End Scope

' Чтение параметров
Scope
    Dim reg As HKEY = Any
    Dim lpdwDisposition As DWORD = Any
    Dim hr As Long = RegCreateKeyEx(HKEY_CURRENT_USER, @RegSection, 0, 0, 0, KEY_QUERY_VALUE, NULL, @reg, @lpdwDisposition)
    If hr <> ERROR_SUCCESS Then
        End(1)
    End If

    Scope
        Dim WindowWidth As DWORD = Any
        Dim BufferLength As DWORD = SizeOf(DWORD)
        hr = RegQueryValueEx(reg, @WidthKey, 0, NULL, CPtr(Byte Ptr, @WindowWidth), @BufferLength)
        Print "Ширина окна", WindowWidth
    End Scope

    Scope
        Dim WindowHeight As DWORD = Any
        Dim BufferLength As DWORD = SizeOf(DWORD)
        hr = RegQueryValueEx(reg, @HeightKey, 0, NULL, CPtr(Byte Ptr, @WindowHeight), @BufferLength)
        Print "Высота окна", WindowHeight
    End Scope

    Scope
        ' Определить размер требуемого буфера для имени пользователя
        Dim BufferLength As DWORD = Any
        hr = RegQueryValueEx(reg, @UserNameKey, 0, NULL, NULL, @BufferLength)
        Print "Размер буфера под имя пользователя в байтах", BufferLength

        Dim pUserName As WString Ptr = Allocate(BufferLength)
        hr = RegQueryValueEx(reg, @UserNameKey, 0, NULL, CPtr(Byte Ptr, pUserName), @BufferLength)
        Print "Имя пользователя", *UserName
        Deallocate(pUserName)
    End Scope

    RegCloseKey(reg)
End Scope

Перечисление подразделов

В этом примере перечислим все подразделы в разделе «Software» для всех пользователей.

#define unicode
#include "windows.bi"

Const RegSection = "Software"

' Получить список подразделов

Dim reg As HKEY = Any
Dim lpdwDisposition As DWORD = Any

' Открыть раздел реестра общий для всех пользователей
Dim hr As Long = RegCreateKeyEx(HKEY_LOCAL_MACHINE, @RegSection, 0, 0, 0, KEY_QUERY_VALUE + KEY_ENUMERATE_SUB_KEYS, NULL, @reg, @lpdwDisposition)
If hr <> ERROR_SUCCESS Then
    End(1)
End If

Dim strClassName As WString * 512 = Any
Dim ClassNameLength As DWORD = 511

Dim SubKeysCount As DWORD = Any
Dim MaxSubKeyLength As DWORD = Any
Dim MaxClassNameLength As DWORD = Any

Dim ValuesCount As DWORD = Any
Dim MaxValueDataLength As DWORD = Any
Dim MaxValueNameLength As DWORD = Any

Dim LastWriteTime As FILETIME = Any

' Информация о разделе реестра
hr = RegQueryInfoKey(reg, @strClassName, @ClassNameLength, 0, @SubKeysCount, @MaxSubKeyLength, @MaxClassNameLength, @ValuesCount, @MaxValueNameLength, @MaxValueDataLength, NULL, @LastWriteTime)
If hr <> ERROR_SUCCESS Then
    End(1)
End If

Print "ClassNameLength", ClassNameLength
Print "SubKeysCount", SubKeysCount
Print "MaxSubKeyLength", MaxSubKeyLength
Print "MaxClassNameLength", MaxClassNameLength
Print "ValuesCount", ValuesCount
Print "MaxValueNameLength", MaxValueNameLength
Print "MaxValueDataLength", MaxValueDataLength

Dim SubKeyName As WString Ptr = Allocate((SizeOf(WString) + 1) * MaxSubKeyLength)

' Перечисление подразделов в обратном порядке
For i As DWORD = SubKeysCount - 1 To 0 Step -1
    Dim MaxSubKeyLength1 As DWORD = MaxSubKeyLength + 1
    hr = RegEnumKeyEx(reg, i, SubKeyName, @MaxSubKeyLength1, 0, NULL, 0, @LastWriteTime)
    If hr <> ERROR_SUCCESS Then
        Print "Ошибка перечисления", hr
        Exit For
    End If
    Print *SubKeyName
Next

Deallocate(SubKeyName)
RegCloseKey(reg)