
6.2. Соглашения по работе с реестром
При сохранении параметров приложения в реестре очень важно определить, кому эта информация предназначена: компьютеру (т. е. всем пользователям) или одному пользователю. Иначе говоря, должна ли конфигурация некоторого компонента приложения быть одинаковой для всех пользователей или каждый пользователь будет настраивать ее по-своему? Обычно информация, сохраняемая в реестре при установке ПО, применяется для всех пользователей. Этот процесс очень похож на установку в систему нового устройства. И наоборот: изменения, внесенные пользователем в конфигурацию приложения во время его выполнения, обычно сохраняются для конкретного пользователя.
Параметры реестра, специфичные для компьютера. Существует соглашение, в соответствии с которым приложения и служебные программы сохраняют данные, специфичные для конфигурации исполняющего их компьютера, в следующей иерархии разделов:
HKEY_LOCAL_MACHINE Software
Company Name
Your Product Name
Your Product Version (optional)
Key1
Valuel
Value2
Key2
Такая структура помогает избежать беспорядка и ускоряет поиск данных, относящихся к программе. Серверные приложения не сохраняют конфигурации для конкретных пользователей. Все их параметры специфичны для определенного компьютера, так что им не нужно подстраиваться под каждого пользователя.
Параметры реестра, специфичные для пользователя. Подразделы раздела HKEY_USERS содержат сведения о пользовательских параметрах. Система автоматически устанавливает соответствие между HKEY_CURRENT_USER и подразделом, описывающим текущего, т. е. ассоциированного с текущим процессом, пользователя. Если поток заимствует права другого пользователя, все обращения этого потока к HKEY_CURRENT_USER будут относиться к этому пользователю. Если приложение будет обращаться к специфичной для пользователя информации реестра, оно должно следовать соглашению, похожему на применяемое в случае для раздела HKEY_LOCAL_MACHINE:
HKEY_CURRENT_USER
Software
Your Company Name
Your Product Name
Your Product Version (optional)
Key1
Valuel
Value2
Key2
Конечно, к этой иерархии можно обращаться и прямо через корневой раздел HKEY_USERS, но делать этого не рекомендуется. Если все-таки необходимо выполнить такую операцию, то используйте функцию RegOpenCurrentUser.
6.3. Работа с реестром c использованием функций Windows api
Дескриптор ключа (подраздела) (key handle) хранится в переменной типа HKEY. Чтобы получить дескриптор ключа HKEY, необходимо использовать функции RegOpenKeyEx или RegCreateKeyEx. Первый аргумент этих функций имеет тип HKEY. При вызове любой из этих функций в качестве первого аргумента можно указать константу, например имя одного из корневых ключей реестра (например, HKEY_CLASSES_ROOT). Windows позволяет воспользоваться несколькими константами типа HKEY, которые по умолчанию являются открытыми. Этими константами являются:
HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
HKEY_CURRENT_CONFIG
HKEY_DYN_DATA
Эти константы соответствуют корневым ключам реестра. Для работы с реестром из программы могут быть использованы функции API Windows (табл. 6.3), а в системах программирования как С++ Builder и Delphi для работы с реестром предусмотрен специальный класс TRegistry, который предоставляет все необходимые функции для работы с реестром.
Таблица 6.3 - Некоторые (часто используемые) функции API для работы с реестром
Функция |
Описание |
RegCloseKey |
Закрыть открытый ключ реестра |
RegConnectRegistry |
Подключиться к удаленному реестру |
RegCreateKeyEx |
Создать новый подключ |
RegDeleteKey |
Удалить ключ |
RegDeleteValue |
Удалить значение |
RegEnumKeyEx |
Перейти к следующему подключу (каждый раз возвращает новый ключ) |
RegEnumValue
|
Перейти к следующему значению (каждый раз возвращает новое значение) |
RegFlushKey
|
Внести значения ключа в реестр (чтобы убедиться в том, что все изменения сохранены на диске) |
RegLoadKey |
Загрузить ключ из специального файла (см. также RegSaveKey) |
RegOpenKeyEx |
Открыть ключ |
RegQueryInfoKey |
Запросить информацию о ключе |
RegQueryValueEx |
Прочитать значение |
RegReplaceKey |
Заменить ключ после перезапуска системы |
RegSaveKey |
Записать ключ в файл |
RegSetKeySecurity |
Установить разрешения на доступ к ключу |
RegSetValueEx |
Установить значение |
RegUnloadKey |
Выгрузить набор значений |
Если требуется получить пару имя/значение текущего ключа, следует воспользоваться функцией RegQueryValueEx, Этот вызов принимает имя и возвращает соответствующее этому имени значение ключа. Если не известно, какие значения содержит данный ключ, то необходимо использовать функцию RegEnumValue, при помощи которого можно последовательно перебирать пары имя/значение, хранящиеся в рамках открытого вами ключа.
При использовании вызова RegEnumValue следует учитывать, что если ключ обладает лишь одним значением по умолчанию, функция вернет это значение. Однако, если помимо значения по умолчанию ключ содержит в себе другие пары имя/значение, функция RegEnumValue последовательно вернет вам эти пары, однако при этом значение по умолчанию будет пропущено. Каждый ключ реестра может обладать значением по умолчанию (имя этого значения — пустая строка), а также набором других значений, каждое из которых идентифицируется при помощи символьного имени.
Следующая функция (пример 6.1) является примером работы с реестром и выполняет перечисление содержимого ключа реестра HKEY_CURRENT_USER\Software. Работа с реесторм реализована с использованием исключительно API функций, но в целом данную функцию можно будет применить только в приложениях ATL или MFC, в связи с использованием класса CString.
Пример 6.1. Функция перечисления содержимого ключа реестра HKEY_CURRENT_USER\Software
void RegReadSample (CString &strResult)
{
TCHAR szBuff[MAX_PATH];
DWORD dwBSize = MAX_PATH, dwIndex = 0;
HKEY hKey = 0;
LONG lResult = 0;
FILETIME ft;
lResult = ::RegOpenKeyEx(HKEY_CURRENT_USER, _T("software"), 0, KEY_ENUMERATE_SUB_KEYS, &hKey);
if(lResult==ERROR_SUCCESS)
{
while(lResult==ERROR_SUCCESS)
{
lResult=::RegEnumKeyEx(hKey,dwIndex,szBuff,&dwBSize,0,0,0,&ft);
if(lResult==ERROR_SUCCESS)
{
dwIndex++;dwBSize = MAX_PATH;
strResult += (CString(szBuff)+_T("\r\n"));
}
}
}
UpdateData(0);
}
При разработке приложения для реализации его интерфейса использованы классы MFC. В данном примере использованы следующие функции для работы с реестром: RegOpenKeyEx, RegEnumKeyEx.
Очень важно при работе с реестром помнить об особенности функции RegDeleteKey. При вызове этой функции необходимо обязательно проверять параметр, передаваемый в эту функцию, на наличие в нем информации. Этот параметр не должен быть пустым, в противном случае операционная система может быть очень серьезно повреждена, в особенности, если это Windows 98.
В случае успешного выполнения этих функций, возвращается значение ERROR_SUCCESS. При вызове функции RegOpenKeyEx использован параметр KEY_ENUMERATE_SUB_KEYS, который указывает тип маски доступа к ключам реестра. Указанное значение не единственное. Все возможные значения этого параметра приведены в таблице 6.4.
Таблица 6.4. Значения типов доступа к ключам реестра
Значение параметра |
Описание |
KEY_ALL_ACCESS |
Комбинация значений всех масок безопасности для доступа: KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, KEY_CREATE_SUB_KEY, KEY_CREATE_LINK, и KEY_SET_VALUE |
KEY_CREATE_LINK |
Разрешение создания символической ссылки |
KEY_CREATE_SUB_KEY |
Разрешение создания подключа |
KEY_ENUMERATE_SUB_KEYS |
Разрешение перечисления (перебора) подключей |
KEY_EXECUTE |
Разрешение для чтения |
KEY_NOTIFY |
Разрешение для уведомления об изменении |
KEY_QUERY_VALUE |
Разрешение для запроса значения подключа |
KEY_READ |
Комбинация масок безопасности: KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS и KEY_NOTIFY |
KEY_SET_VALUE |
Разрешение установки значения подключа |
KEY_WRITE
|
Комбинация масок доступа KEY_SET_VALUE и KEY_CREATE_SUB_KEY |
При работе с реестром необходимо помнить, что доступ к реестру в целом и к его ключам в частности регулируется правами пользователя, профиль которого активен в данный момент на компьютере. Это касается операционных систем семейства Windows NT, а в ОС Windows 98/Me эти ограничения не действуют. Учет прав пользователя крайне важен, поскольку программы, работающие с реестром могут не иметь доступа к тем или иным ключам в зависимости от прав пользователя. Полный доступ к реестру имеют программы, запускаемые в режиме администратора или пользователей с правами администратора.
6.4. Работа с реестром при помощи класса TRegistry (Delphi и C++ Builder)
Рассмотрим некоторые функции, которые предоставляются классом TRegistry.
Функция CreateKey предназначена для создания нового ключа в реестре. Входным параметром функции является имя ключа, который нужно создавать. Ключ может быть абсолютным или относительным параметром. Абсолютный ключ начинается со знака “\” и подключа главного (корневого) ключа. Относительный ключ - это подключ текущего ключа. После создания ключа он не имеет никакого значения и его надо установить при помощи специальных функций, таких как WriteBinaryData, WriteBool, WriteCurrency, WriteDate, WriteDateTime, WriteExpandString, WriteFloat, WriteInteger, WriteString, WriteTime.
Эта функция возвращает True, если создание прошло успешно. Попытка создания ключа, который уже существует и не приводит ни к какому результату.
Функция CreateKey создает ключи с уровнем доступа “для всех”. Если необходимо создавать ключи со специальным уровнем доступа, то необходимо напрямую вызывать функции Windows API.
Функция DeleteKey предназначена для удаления существующего ключа в реестре. Она возвращает True, если удаление прошло успешно.
Функция CloseKey используется для закрытия текущего ключа. Перед закрытием будет осуществлена запись текущего ключа. Вызов этой функции без текущего ключа не дает никакого эффекта.
Функция DeleteValue используется для удаления значения из текущего ключа. Параметром, передаваемым в эту функцию, является строка, которая содержит значение, которое надо удалить. Ключ может содержать несколько значений и каждое из этих значений должно иметь уникальное имя. Функция возвращает True, если удаление прошло успешно.
Функции GetDataInfo, GetDataSize, GetDataType, GetKeyInfo, GetKeyNames, GetValueNames предназначены для получения информации.
Функция HasSubKeys определяет, существует ли заданный подключ. Если он существует, то возвращается True.
Функция KeyExists определяет, существует ли заданный ключ реестра с указанным именем. Функция возвращает True если ключ существует.
Функция LoadKey. Эта функция создает подключ в указанном корневом ключе и загружает информацию из файла в созданный ключ. Файл, который загружается в реестр, должен содержать данные о значениях, подключах и значения для этих подключей.
Перед вызовом этой функции значение свойства RootKey объекта TRegistry должно быть установлено в HKEY_USERS, HKEY_LOCAL_MACHINE или в то значение, которое будет возвращено функцией RegistryConnect.
Параметр “имя файла”, передаваемый в функцию, не должен содержать расширение, если программа будет работать с файловой системой FAT. Загружаемый файл необходимо создавать вручную, следуя специальным требованиям, либо при помощи функции SaveKey из объекта TRegistry или RegSaveKey из Windows API.
Функция MoveKey перемещает существующий ключ реестра вместе со всем его содержимым в указанный ключ. Функция имеет два параметра. Первый параметр указывает старый ключ, откуда необходимо перемещать данные, а второй параметр содержит ключ, куда необходимо перемещать данные. Если указанный новый ключ не существует, то он будет создан.
Функция OpenKey. Эта функция открывает указанный ключ. Функция возвращает True, если открытие произошло успешно. Также функция имеет дополнительный параметр, который указывает на необходимость создания ключа в случае, если он не существует.
Функция OpenKeyReadOnly открывает ключ только для чтения. Функция возвращает True, если открытие произошло успешно.
Функции ReadBinaryData, ReadBool, ReadCurrency, ReadDate, ReadDateTime, ReadFloat, ReadInteger, ReadString, ReadTime позволяют прочитать из реестра данные соответствующего типа.
Функция RegistryConnect осуществляет подключение к реестру другого компьютера, подключенного по сети. Передаваемый параметр - это имя удаленного компьютера. Перед вызовом этой функции необходимо установить свойство RootKey объекта TRegistry в значения HKEY_USERS или HKEY_LOCAL_MACHINE. Функция возвращает True, если открытие реестра прошло успешно.
Функция RenameValue изменяет имя значения, ассоциированного с текущим ключом. Функция имеет два парметра: старое и новое имя значения.
Функция ReplaceKey осуществляет замену указанного ключа данными, сохраненными в файле. Функция возвращает True, если замена ключа произошла успешно. Файл должен быть сохранен при помощи функций SaveKey объекта TRegistry или RegSaveKey функции API Windows. Если на компьютере используется файловая система FAT, то имя файла не должно содержать расширение.
Функция SaveKey позволяет сохранить данные и подключи из указанного ключа (подключа) в файл на диске. При вызове этой функции будет использован уровень безопасности KEY_ALL_ACCESS. Если на компьютере используется файловая система FAT, то имя файла не должно содержать расширение. Если функция выполняется успешно, то возвращается True и ключ закрывается.
Функция ValueExists определяет наличие данных для указанного ключа реестра. Эта функция может использоваться для проверки наличия данных перед вызовом других функций записи и модификации реестра.
Функции WriteBinaryData, WriteBool, WriteCurrency, WriteDate, WriteDateTime, WriteExpandString, WriteFloat, WriteInteger, WriteString, WriteTime позволяют записывать данные в реестр соответствующего типа.
Функции API Windows для работы с реестром полностью аналогичны. Ниже приведен фрагмент программы, который демонстрирует использование функций класса TRegistry.
Пример 6.2. Получение списка программного обеспечения, установленного на компьютере (с использованием функций API Windows)
//Функции получения списка установленного ПО Используемые типы данных:
type
TInstallAppItem = class(TObject)
public
Apps : TStringList;
AppInfo : TInstallAppInfo;
constructor Create;
destructor Destroy; override;
procedure Collect;
end;
var
UninstallKey : String = 'Software\Microsoft\Windows\CurrentVersion\Uninstall';