Для начала, немного теории о реестре Windows.
История появления реестра
Давным-давно все настройки программ хранились в Ini-файлах, которые представляли из себя обычные текстовые файлы с структурированной записью всех параметров программ. Со временем программы стали расти, как и количество их параметров, и в следствии чего INI-файлы превратились в настоящую свалку, в которой что-либо разобрать было очень сложно.
Поэтому в Microsoft решили создать одну единую базу данных, где хранились бы все настройки и параметры Windows — так появился реестр.
Что из себя теперь представляет реестр Windows
Итак, сегодняшний реестр — это структурированая база данных, в которой хранятся настройки операционной системы, установленных программ, профилей пользователей, сведения о типах файлов и много чего еще. Теперь, обычный двоичный файл размером в 64 кб(Win 3.1) стал одним из основных компонентов Windows, от которого отказаться будет очень сложно…
Реестр состоит из 5 основных разделов, которые включают в себя огромное множество под-разделов, на описание которых уйдет не одно сотня страниц. Поэтому опишу только главные разделы:
HKEY_CLASSES_ROOT — в этом разделе хранится информация о зарегистрированных типах файлов, а также об обьектах COM и ActiveX.
HKEY_CURRENT_USER — в этом разделе хранится информация о пользователе, вошедшем в данный момент в систему: папки пользователя, параметры панели управления и другие настройки.
HKEY_LOCAL_MACHINE — в этом разделе содержится информация о параметрах конфигурации всех пользователей.
HKEY_USERS — в этом разделе находится информация о всех загруженных профилях пользователей данного комьютера.
HKEY_CURRENT_CONFIG — в этом разделе содержится информация о профиле обурудования, которую локальный компьютер использует при запуске системы.
Минусы реестра
Реестр подвержен фрагментации, поэтому чем больше в нем записей, тем медленнее он работает. Поэтому засорять его своими настройками не хорошо, если эти настройки не будут впоследствии удалены.
В реестре хранится системная информация от которой записит работа всего компьютера, и если что-то нечаянно испортить, то вам будет плохо.
А теперь практика
Для того чтобы работать с реестром нужно подключить файл «Registry.hpp«
1 |
#include "Registry.hpp" |
Теперь нам доступен класс TRegistry. Для начала работы необходимо создать объект класса, после чего указать раздел с которым мы будем работать:
1 2 3 4 5 |
TRegistry reg->RootKey=HKEY_LOCAL_MACHINE; // Теперь мы будем работать с разделом // HKEY_LOCAL_MACHINE все записи ключей, // удаление, перемещение будут происходить // в этом разделе) |
Запись параметров в реестр
Для записи параметров в реестр у класса TRegistry существует множество функций, которые очень похожи и различаются только в типе записываемой информации. Для обычных строк это WriteString(«Name«,»Value«), для записи целых чисел это WriteInteger(«Name«,int) и так далее… Список наиболее часто-используемых функций будет приведен ниже.
Прежде чем записать какой-то параметр в определенную ветку реестра, ее нужно открыть Для этого используется функция OpenKey(«Key«,CanCreate). Первым параметром функции идет имя ключа, открываемого для записи, а вторым параметром идет значение типа bool — при включении этого значения, в случае отсутствия открываемого ключа, он будет создан автоматически. В противном случае, запись в несуществующий ключ не произойдет (что и вполне логично).
Доступ к подключам происходит точно так же как и к самим ключам: допустим, у нас есть ветка реестра «TestProgramm\\Options\\ID«.
Для того, чтобы записать какой-то параметр в ключ «TestProgramm» нужно написать так:
1 2 |
TRegistry *reg=new TRegistry; reg->OpenKey("TestProgramm",true); |
Если же нужно записать что-то в подветку этого ключа, то следует написать вот так:
1 2 |
TRegistry *reg=new TRegistry; reg->OpenKey("TestProgramm\\Options",true); |
И так далее….
Теперь пример записи обычной строки в реестр:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
TRegistry *reg=new TRegistry(); // Создали обьект reg класса TRegistry reg->RootKey=HKEY_CURRENT_USER; // Для начала необходимо указать раздел, // с которым мы будем работать (список // всех разделов был приведен выше). // В нашем случае это будет HKEY_CURRENT_USER, // который стоит по умолчанию // Теперь нам нужно указать ключ реестра, // в который будет происходить запись. reg->OpenKey("\NitanTest",true); // Мы создали ключ, если же такой ключ уже // существовал, то он был бы открыт для записи reg->WriteString("MyName","Nitan"); // Теперь мы записали параметр MyName и // задали ему значение Nitan reg->CloseKey(); // Закрываем ключ delete reg; // Освобождаем память // Можно открыть реестр и полюбоваться на // проделанную работу. |
Список наиболее часто-используемых функций для записи ключей в реестр:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
TRegistry *reg=new TRegistry(); reg->OpenKey("Test",1); //----------------------------------------------------------------------- int i=150; reg->WriteInteger("Int",i); // Записывает целое число i в параметр "Int" // открытого ключа //----------------------------------------------------------------------- bool b=true; reg->WriteBool("Bool",b); // Записывает булевое значение b в параметр "Bool" // открытого ключа //----------------------------------------------------------------------- float f=3.1416; reg->WriteFloat("Float",f); // Записывает действительное число f в параметр // "Float" открытого ключа //----------------------------------------------------------------------- String s="String"; reg->WriteString("String",s); // Записывает обычную строку в параметр // "String" открытого ключа //----------------------------------------------------------------------- TDateTime *dt; reg->WriteDateTime("DateTime",dt->CurrentDateTime()); // Записывает значение // даты и времени // из dt в параметр // "DateTime" открытого // ключа //----------------------------------------------------------------------- char *buffer=new char; reg->WriteBinaryData("BinaryData",buffer,strlen(buffer)); //Записывает // двоичное значение из buffer заданным размером. Размер записываемых // данных не должен превышать 2048 байт. //Таким образом можно хранить любую информацию в реестре // (даже какой-нибудь файл), но в Microsoft этого не одобряют и советуют // в реестре хранить имя файла, а сам файл отдельно. //----------------------------------------------------------------------- reg->CloseKey(); delete reg; |
Во всех выше-описанных функциях поле «Name«, если оно не существует, будет созданно автоматически.
Чтение параметров из реестра
Чтение параметров из реестра происходит точно также, как и запись, только в этом случае каждая функция возвращает значение определенного типа. К примеру, чтобы прочитать параметр, содержащий обычную строку, сделать это стоит следующим образом:
1 2 |
String s=reg->ReadString("Name"); //Name - это имя считываемого параметра |
Список основных функций для считывания опять будет приведен в конце.
Теперь простой пример считывания параметра из реестра:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
TRegistry *reg=new TRegistry(); // Создали обьект reg класса TRegistry reg->RootKey=HKEY_CURRENT_USER; // Как и при записи указываем раздел с которым // будем работать reg->OpenKeyReadOnly("NitanTest"); // Теперь открываем ключ для чтения // (можно было бы и использовать OpenKey(), // но эта функция позволяет только читать // параметры ) AnsiString test; //Строка в которую мы занесем значение // параметра из реестра test=reg->ReadString("MyName"); //Заносим значение, указан при этом нужный // нам параметр ShowMessage(test); //Любуемся правильным результатом reg->CloseKey(); //Закрываем ключ delete reg; //Освобождаем память |
Список основных функций для чтения параметров из реестра
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
TRegistry *reg=new TRegistry(); reg->OpenKey("Test",1); int i; i=reg->ReadInteger("Int"); // Считываем целое значение параметра "Int" и // присваиваем его переменной i //----------------------------------------------------------------------- bool b; b=reg->ReadInteger("Bool"); //Считываем булевое значение из параметра // "Bool" и присваиваем его переменной b //----------------------------------------------------------------------- String s; s=reg->ReadString("String"); //Считываем обычную строку из параметра // "String" и присваиваем его переменной s //----------------------------------------------------------------------- char *buffer=new char; int size=reg->GetDataSize("BinaryData"); //Получаем длину записанного // параметра, потому как ReadBinary требует размер строки для считывания /* Читаем двоичное значение в buffer заданным размером. */ reg->ReadBinaryData("BinaryData",buffer,size); //----------------------------------------------------------------------- reg->CloseKey(); delete reg; |
Удаление ключей и разделов
Мусорить не хорошо, потому нужно после себя убирать (удалять параметры из реестра, естественно, нужно тогда, когда программа больше не будет к ним обращаться, на пример, при деинсталяции(удалении с компьютера) программы. Для этого существует две функции:
DeleteValue() — удаление параметра:
1 2 3 4 5 6 7 |
TRegistry *reg=new TRegistry(); // Создали обьект reg класса TRegistry reg->RootKey=HKEY_CURRENT_USER; // Как и при записи указываем раздел с которым // будем работать reg->OpenKey("NitanTest",false); //Октрываем ключ, над которым будем работать reg->DeleteValue("MyName"); //Удаляем параметр reg->CloseKey(); //Закрываем ключ delete reg; //Освобождаем память |
DeleteKey() — удаление всего ключа:
1 2 3 4 5 6 7 8 9 10 11 |
TRegistry *reg=new TRegistry(); //Создали обьект reg класса TRegistry reg->RootKey=HKEY_CURRENT_USER; //Как и при записи указываем раздел с которым // будем работать //Здесь окрывать ключ не надо, так как мы его // не сможем удалить перед того, как к нему // обратились, для этого его нужно будет // закрыть reg->DeleteKey("NitanTest"); //Удаляем ключ delete reg; //Освобождаем память |
Переименовывание параметров
Для того, чтобы переименовать параметр нужно чтобы этот параметр существовал и чтобы параметра, который бы соответствовал новому имени не существовало:
1 2 3 4 5 6 |
TRegistry *reg=new TRegistry(); reg->OpenKey("Test",0); reg->RenameValue("OldName","NewName"); // OldName - старое имя параметра. // NewName - новое имя. reg->CloseKey(); delete reg; |
Как узнать, имеется-ли в определенном ключе какой-то параметр?
Для этого существует функция ValueExists(«Name»), которая вовращает 1, если параметр существует и 0, если параметра не существует:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
TRegistry *reg=new TRegistry(); reg->OpenKey("Test",0); if(reg->ValueExists("BBala")) //Если параметр в заданном ключе существует MessageBox(0,"Параметр \"BBala\" в ключе \"Test\" существует", "Проверка",MB_OK); //Сообщаем радостную новость else //В противном случае MessageBox(0,"Параметр \"BBala\" в ключе \"Test\" не существует", "Проверка",MB_OK); //Огорчаем reg->CloseKey(); delete reg; |
Как скопировать, переместить ключ?
Для этого можно воспользоваться функцией MoveKey(String OldName, String NewName, bool Delete) — копируем ключ «OldName» в «NewName«, если Delete=true, то автоматически удаляется ключ OldName:
1 2 3 |
TRegistry *reg=new TRegistry(); reg->MoveKey("Test","Environment\\Test",false); //Копируем ключ Test в подраздел Environment delete reg; |
Сохранение и загрузка ключей в файл
Для сохранения и загрузки ключей в TRegistry существует 2 функции: SaveKey(«Key«,»FileName«) и LoadKey(«Key«,»FileName«). Первым параметром в этих функциях идет имя ключа, над которым будет происходить загрузка/сохранения, а вторым — имя файла в который будет сохранен или загружен ключ реестра.
1 2 3 4 |
TRegistry *reg=new TRegistry(KEY_ALL_ACCESS); reg->RootKey=HKEY_CURRENT_USER; reg->SaveKey("Test","E:\\test"); //Сохранение delete reg; |
Как получить список всех параметров заданного ключа?
Для этого предназначена функция GetValueNames(TStringList *List), которая передает все параметры ключа в заданный список List.
1 2 3 4 5 6 |
TRegistry *reg=new TRegistry(); reg->OpenKey("Test",0); //Окрываем нужный нам ключ TStringList *l=new TStringList; //Обьект типа TStringList в котором будет храниться список всех параметров reg->GetValueNames(l); //Получаем список всех параметров и передаем его в l ShowMessage(l->Text); //Просто проверка delete reg; //Очищаем память |
Как получить список всех подключей заданного ключа?
Для этого предназначена функция GetKeyNames(TStringList *List), которая передает все параметры ключа в заданный список List.
1 2 3 4 5 6 |
TStringList *l=new TStringList; //Список, в котором будет хранится TRegistry *reg=new TRegistry(); reg->OpenKey("Software",0); //Открываем ключ reg->GetKeyNames(l); ShowMessage(l->Text); delete reg; |
Класс TRegistry имеет перегруженный конструктор, задекларированный как:
1 2 |
__fastcall TRegistry(void)/* overload */; __fastcall TRegistry(unsigned AAccess)/* overload */; |
Как мы видим, при создании объекта класса TRegistry, можно управлять атрибутом безопасности.
Параметр AAccess может принимать следующие значения:
- KEY_CREATE_LINK — Permission to create a symbolic link.
- KEY_CREATE_SUB_KEY — Permission to create subkeys.
- KEY_ENUMERATE_SUB_KEYS — Permission to enumerate subkeys.
- KEY_EXECUTE — Permission for read access.
- KEY_NOTIFY — Permission for change notification.
- KEY_QUERY_VALUE — Permission to query subkey data.
- KEY_READ — Combination of KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, and KEY_NOTIFY access.
- KEY_SET_VALUE Permission to set subkey data.
- KEY_WRITE Combination of KEY_SET_VALUE and KEY_CREATE_SUB_KEY access.
- KEY_ALL_ACCESS — Combination of KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, KEY_CREATE_SUB_KEY, KEY_CREATE_LINK, and KEY_SET_VALUE access.
Соответственно, могут возникнуть моменты, когда доступ к определённым действиям в реестре ограничить. В таком случае, программа может прервать выполнение нужного действия.
Для того, чтобы избежать подобных проблем, необходимо выполнять проверку на успешность создания объекта.
Вариант 1 (упрощённый):
1 2 3 4 |
TRegistry *reg = new TRegistry(KEY_ALL_ACCESS); if (reg) { // набор действий... } |
Вариант 2 (заключается в использовании блоков try … catch):
1 2 3 4 5 6 7 8 9 10 11 |
TRegistry *reg = NULL; try { // предпринимаем попытку выполнить блок нижеописанного кода reg = new TRegistry(KEY_ALL_ACCESS); if (reg) { // проверка создания // набор действий при успешном создании ... } else { // набор действий при возвращении нулевого указателя ... } } catch (...) { // перехват всех неудачных действий, возникших в вышеописанном участке кода // набор действий в случае возникновения исключений ... } |
Соответственно, можно использовать и блоки с __finally.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
String MotherboardName="Unknown"; TRegistry *reg = new TRegistry(KEY_READ); if (reg) { // если всё ОК try { reg->RootKey = HKEY_LOCAL_MACHINE; reg->OpenKey("Hardware\\Description" "\\System\\BIOS", false); MotherboardName=reg->ReadString("BaseBoardManufacturer").t_str(); MotherboardName += " "; MotherboardName +=reg->ReadString("BaseBoardProduct"); } __finally { delete reg; } } else ShowMessga("Error registry !!!"); |
После завершении использования не забываем очищать память:
1 2 3 4 |
if (reg) { delete reg; reg = NULL; } |
пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
//--------------------------------------------------------------------------- String id_mb( void ) { String MotherboardName; TRegistry *reg = new TRegistry(KEY_READ); if (reg) { // если всё ОК try { reg->RootKey = HKEY_LOCAL_MACHINE; reg->OpenKey("Hardware\\Description" "\\System\\BIOS", false); MotherboardName=reg->ReadString("BaseBoardManufacturer"); MotherboardName += " "; MotherboardName +=reg->ReadString("BaseBoardProduct"); } __finally { delete reg; } } else //ShowMessga("Error registry !!!"); return MotherboardName; } |