Delphi 4. Использование реестра
Получение информации о подсекции
Использование программы REGEDIT
Реестр — это центральное хранилище информации о параметрах системы и установленных программах. В версиях Windows до Windows 95 программисты сохраняли параметры программ либо в INI-файлах WIN.INI и SYSTEM.INI, либо в дополнительных INI-файлах. Хотя использование INI-файлов поддерживается и в Win32, Microsoft настоятельно рекомендует для хранения необходимых в работе программы параметров пользоваться реестром. Реестр представляет собой иерархическую базу данных, cостоящую из секций, подсекций и элементов. Каждая секция имеет свое назначение. Хранить данные о пользовательских программах Microsoft рекомендует в секции HKEY_CURRENT_USER и подсекции Software. В этой подсекции вы создаете подсекцию, идентифицирующую вашу программу или фирму, и уже внутри нее располагаете данные.
Модуль Registry
Для упрощения работы с регистратором в состав Delphi (начиная с версии 2.0) входит модуль REGISTRY, содержащий реализацию трех классов, — TRegistry, TRegistryIniFile и TRegIniFile.
Внимание! Чтобы использовать свойства и методы классов TRegistry, TRegistryIniFile и TRegIniFile, необходимо включить в список uses модуль Registry.
TRegIniFile
Собственно говоря, задача класса TRegIniFile — упростить перенос 16-битных программ в среду Windows 95. Методы этого класса эквивалентны методам класса TIniFile в 16-битной версии Delphi. Класс TRegIniFile позволяет обращаться к секции HKEY_CURRENT_USER, считывать и записывать строки (методы ReadString и WriteString), целочисленные значения (методы ReadInteger и WriteInteger), логические значения (методы ReadBool и WriteBool), секции (методы ReadSection, ReadSections и ReadSectionValues), удалять секции (метод EraseSection) и элементы (метод DeleteKey). Рассмотрим на примерах, как используются функции этого класса.
Microsoft рекомендует записывать данные, относящиеся к вашей программе, в подсекции секции HKEY_CURRENT_USER_Software. Предположим (не особенно фантазируя на эту тему), что ваша программа называется RegDemo, и данные для нее располагаются в секции Software\RegDemo. Ниже мы покажем, как поместить в регистратор строчные, целочисленные и логические данные, а затем считать их, — этих операций будет достаточно для того, чтобы сохранить в регистраторе параметры нашей программы, а затем считать их.
Прежде чем записать данные в определенную секцию, ее необходимо создать. Это происходит при вызове конструктора объекта TRegIniFile. В качестве параметра вы указываете название секции, и если таковой не существует, она создается:
RegFile := TRegIniFile.Create(SubKey);
После того как файл регистратора открыт (и создана определенная секция), мы можем записать данные. Поддерживаются три типа данных: целочисленные, логические и строчные данные. Для записи этих данных существуют методы WriteInteger, WriteBool и WriteString. В качестве параметров указываются:
- название подсекции;
- название элемента;
- записываемые данные.
Так, чтобы записать значение элемента MyIntVal в подсекции IntKey, следует выполнить код
RegFile.WriteInteger(IntKey, 'Int_Val', 32000);
а для того чтобы прочесть значение, необходимо вызвать метод ReadInteger (в качестве параметров указываются название подсекции, название элемента и значение по умолчанию):
RegFile.ReadInteger(IntKey, 'Int_Val', 0));
Для чтения логических и строчных данных используются соответственно методы ReadBool и ReadStr, а для их записи — методы WriteBool и WriteString.
Расссмотрим пример использования
перечисленных выше методов класса TRegIniFile.
Расположим в форме компонент Memo, две группы GroupBox
и шесть кнопок — три в группе Write и три в группе
Read. Нажатие каждой кнопки в группе Write приведет к
записи соответствующего значения в реестр,
нажатие каждой кнопки в группе Read — к чтению
этого значения. ![]()
Ниже приведен исходный текст модуля, в котором содержатся обработчики нажатия кнопок, использующие методы класса TRegIniFile.
unit RDUnit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls, Registry;
TForm1 = class(TForm)
Memo1: TMemo;
GroupBox1: TGroupBox;
GroupBox2: TGroupBox;
Label1: TLabel;
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
Button5: TButton;
Button6: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
procedure Button6Click(Sender: TObject);
procedure FormClose(Sender: TObject;
var Action:
TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1 : TForm1;
implementation
{$R *.DFM}
var
RegFile : TRegIniFile;
const
//Подсекция
SubKey : String = 'Software\RegDemo';
// Элемент для хранения логических данных
BoolKey : String = 'BoolKey';
// Элемент для хранения целочисленных данных
IntKey : String = 'IntKey';
// Элемент для хранения строчных данных
StrKey : String = 'StrKey';
procedure TForm1.FormCreate(Sender: TObject);
begin
// Создать экземпляр класса
RegFile := TRegIniFile.Create(SubKey);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
// Записать целочисленное значение
RegFile.WriteInteger(IntKey, 'Value', 1998);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
// Записать булево значение
RegFile.WriteBool(BoolKey, 'Value', True);
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
// Записать строку
RegFile.WriteString(StrKey, 'Value', 'Demo');
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
// Считать целочисленное значение
Memo1.Lines.Add('Int Value = ' +
IntToStr(RegFile.ReadInteger(IntKey, 'Value',
0)));
end;
procedure TForm1.Button5Click(Sender: TObject);
begin
// Считать булево значение
if RegFile.ReadBool(BoolKey, 'Value', False)
then
Memo1.Lines.Add('Bool
Value = True')
else
Memo1.Lines.Add('Bool
Value = False');
end;
procedure TForm1.Button6Click(Sender: TObject);
begin
// Считать строку
Memo1.Lines.Add(RegFile.ReadString(StrKey, 'Value', ''));
end;
procedure TForm1.FormClose(Sender: TObject; var
Action: TCloseAction);
begin
// Удалить секцию
RegFile.EraseSection(SubKey);
// Освободить память
RegFile.Free;
end;
end.
На приведенном ниже рисунке показано,
как выглядит созданная нами подсекция в
редакторе REGEDIT. ![]()
Отметим, что рассмотренных выше функций вполне достаточно для того чтобы обеспечить минимальную функциональность приложения. Если же вам требуется читать и записывать данные из других секций реестра, вы можете воспользоваться методами класса TRegistry или (что мене удобно) непосредственно функциями Win32 API.
Класс TRegistry
Прежде чем рассмотреть пример использования свойств и методов класса TRegistry, давайте кратко перечислим их.
В следующей таблице перечислены свойства класса TRegistry.
| Свойство | Описание |
|---|---|
| CurrentKey | Позволяет узнать текущую подсекцию, в которой проводятся операции по чтению и записи. Для изменения подсекции следует использовать методы OpenKey и OpenKeyReadOnly |
| CurrentPath | Позволяет узнать полное название текущей подсекции |
| LazyWrite | Задает способ обновления информации в реестре — непосредственно или после вызова метода CloseKey. |
| RootKey | Задает корневую секцию в реестре. По умолчанию установлено значение HKEY_CURRENT_USER |
В следующей таблице перечислены методы класса TRegistry.
После того как мы кратко познакомились со свойствами и методами класса TRegistry, давайте рассмотрим несколько примеров их использования.
Инициализация
Перед использованием свойств и методов класса TRegistry, необходимо создать экземпляр этого класса. Например:
var R : TRegistry; ... R := TRegistry.Create;
Задание корневой секции
Если вы собираетесь работать с секцией, отличной от HKEY_CURRENT_USER (это значение задается по умолчанию), то после инициализации вы должны изменить значение свойства RootKey. Возможны следующие значения:
HKEY_CLASSES_ROOT HKEY_CURRENT_USER HKEY_LOCAL_MACHINE HKEY_USERS HKEY_PERFORMANCE_DATA HKEY_CURRENT_CONFIG HKEY_DYN_DATA
Например:
with R do
begin
RootKey := HKEY_LOCAL_MACHINE;
//
// Продолжаем работу с реестром
//
end;
Чтение данных
Для чтения данных в том или ином
формате используются методы ReadXXX, перечисленные
в приведенной выше таблице. Здесь нет каких-либо
тонкостей, за исключением случая, когда данные
представлены в формате binary data. Пример таких
данных приведен для элемента Capabilities на следующем
рисунке. ![]()
Как прочитать такие данные? Вспомним, что в нашем распоряжении есть метод GetDataType, позволяющий определить тип данных, метод GetDataSize, возвращающий размер данных и метод ReadBinaryData для чтения данных. Так как нам известен размер данных, мы можем воспользоваться динамическим массивом, устанавливая его размер с помощью метода SetLength. После считывания бинарных данных каждый элемент массива будет хранить один элемент данных. Нам останется только выполнить цикл, в каждой интерации которого мы будем извлекать один элемент данных, форматировать его и отображать на экране.
Ниже показан пример получения данных для элемента Capabilities.
procedure
TForm1.Button1Click(Sender: TObject);
const
Key : String = '\Enum\Network\Family\0000\';
Val : String = 'Capabilities';
var
Data : Array of Byte; // Динамический массив!
S : String;
sz : Word;
I : Word;
begin
R := TRegistry.Create;
with R do
begin
//
// Задать корневую секцию
//
RootKey :=
HKEY_LOCAL_MACHINE;
//
// Открыть подсекцию
//
OpenKey(Key, False);
//
// Если это — бинарные данные
//
if GetDataType(Val) =
rdBinary
then
begin
//
// Определить их размер
//
sz := GetDataSize(Val);
if sz > 0 then
begin
//
// Установить размер динамического массива
//
SetLength(Data, sz);
//
// Прочитать данные в массив
//
ReadBinaryData(Val, Data[0], sz);
S := Val + ' = ';
for I := 0 to sz — 1 do
begin
//
// Сформатировать
//
S := S + Format('%2x',[Data[I]]);
end;
//
// Показать
//
Edit1.Text := S;
end;
end;
Free;
end;
end;
Чтение всей подсекции
Иногда бывает необходимо прочитать всю подсекцию. Для выполнения этой задачи мы должны воспользоваться методами GetValueNames и уже занкомыми нам методами GetDataType и GetDataSize. После того как мы получили имена элементов подсекции, мы, в цикле, определяем тип хранимой в элементе информации и считываем ее. На приведенном ниже примере показано, как это сделать для секции, приведенной на рисунке в разделе «Чтение бинарных данных».
procedure
TForm1.Button1Click(Sender: TObject);
const
Key : String = '\Enum\Network\Family\0000\';
var
Data : Array of Byte;
L : TStringList;
S : String;
sz : Word;
I,J : Word;
begin
R := TRegistry.Create;
L := TStringList.Create;
with R do
begin
//
// Задать корневую секцию
//
RootKey :=
HKEY_LOCAL_MACHINE;
//
// Открыть подсекцию
//
OpenKey(Key, False);
//
// Получить названия элементов
//
GetValueNames(L);
If L.Count > 0 Then
begin
for I := 0 to L.Count — 1 do
begin
//
// Узнать тип данных каждого элемента
//
case GetDataType(L[I]) of
// Строка?
rdString,
rdExpandString :
S := '"' + ReadString(L[I]) + '"';
// Цедочисленный?
rdInteger :
S := IntToStr(ReadInteger(L[I]));
// Бинарный?
rdBinary :
begin
sz := GetDataSize(L[I]);
SetLength(Data, sz);
ReadBinaryData(L[I], Data[0], sz);
S := '';
for J := 0 to sz — 1 do
begin
S := S + Format('%2x',[Data[I]]);
end;
end;
// Неизвестный?
rdUnknown :
S := 'Unknown';
end;
Memo1.Lines.Add(L[I] + #9'' + S);
end;
end;
Free;
end;
L.Free;
end;
Запись бинарных данных
Для записи бинарных данных используется метод WriteBinaryData, при вызове которого мы указываем название элемента, буфер, в котором хранятся записываемые данные, и его размер.
Ниже показан пример записи бинарных данных с использованием метода WriteBinaryData.
procedure
TForm1.Button1Click(Sender: TObject);
var
B : Array [0..15] of Byte;
I : Byte;
Const
SubKey : String = 'Software\RegDemo';
begin
R := TRegistry.Create;
with R do
begin
//
// Инициализировать данные случайным образом
//
for I := 0 to 15 do
B[I] := Random(255);
//
// Создать подсекцию
//
OpenKey(SubKey +
'\BinKey', True);
//
// Записать данные
//
WriteBinaryData('Value', B, SizeOf(B));
Free;
end;
end;
Сохранение подсекции в файле
Для сохранения подсекции (и всех ее вложенных подсекций) в файле мы используем метод SaveKey. Например:
var
R : TRegistry;
Const
SubKey : String = 'Software\RegDemo\';
procedure TForm1.Button1Click(Sender: TObject);
begin
R := TRegistry.Create;
If R.SaveKey(SubKey, 'savedemo') then
ShowMessage('Подсекция сохранена')
else
ShowMessage('Ошибка сохранения подсекции');
R.Free;
end;
Получение информации о подсекции
Для получения информации о подсекции мы можем использовать функцию GetKeyInfo. Данная функция заполняет структуру типа TRegKeyInfo, из полей которой можно узнать:
- число вложенных подсекций;
- самое длинное название подсекции (в символах);
- число элементов;
- самое длинное название элемента;
- максимальный размер элемента;
- время последней записи подсекции/элемента.
Пример использования GetKeyInfo функции показан ниже.
var
R : TRegistry;
KI : TRegKeyInfo;
const
Key : String = '\Enum\Network\Family\0000\';
procedure TForm1.Button1Click(Sender: TObject);
begin
R := TRegistry.Create;
with R do
begin
//
// Задать корневую секцию
//
RootKey :=
HKEY_LOCAL_MACHINE;
//
// Открыть подсекцию
//
OpenKey(Key, False);
//
if GetKeyInfo(KI) then
begin
with KI do
begin
Memo1.Lines.Add(CurrentPath + #13#10);
Memo1.Lines.Add('MaxSubKeyLen' + #9 +
IntToStr(MaxSubKeyLen));
Memo1.Lines.Add('NumValues' + #9 +
IntToStr(NumValues));
Memo1.Lines.Add('MaxValueLen' + #9 +
IntToStr(MaxValueLen));
Memo1.Lines.Add('MaxDataLen' + #9 +
IntToStr(MaxDataLen));
Memo1.Lines.Add('FileTime' + #9#9 +
DateTimeToStr(FileTime.dwLowDateTime));
end;
end;
end;
end;
Использование программы REGEDIT
Если вам необходимо занести какие-то значения в системный реестр или просто создать пустую подсекцию — такие функции, например, могут быть возложены на программу установки, — то можно воспользоваться программой REGEDIT. Для этого необходимо создать специальный текстовый файл и указать его в качестве параметра при вызове программы REGEDIT. Для нашего примера (создание подсекции) этот файл может выглядеть следующим образом:
REGEDIT4 [HKEY_CURRENT_USER\Software\RegDemo]
Ниже показана подпрограмма, которая создает данный файл и вызывает REGEDIT для обновления содержимого реестра.
{///////////////////////////////////////////////////////////////
Подпрограмма REGUPDATE — создание файла REGDEMO.REG и
обновление
содержимого регистратора через вызов программы
REGEDIT
///////////////////////////////////////////////////////////////}
Procedure TForm1.RegUpdate;
Const
RegID : String = 'REGEDIT4'+#13#10;
RegPath : String = '[HKEY_LOCAL_MACHINE\SOFTWARE\';
Var
RegFile : TFileStream;
RegItem : String;
RegCmd : String;
P : PChar;
RegWnd : hWnd;
Begin
// Создать регистрационный файл
RegFile := TFileStream.Create('REGDEMO.REG', fmCreate);
RegItem := RegPath + 'RegDemo]'+#13#10;
RegFile.Write(RegID[1], Length(RegID));
RegFile.Write(RegItem[1], Length(RegItem));
RegFile.Free;
// Вызвать REGEDIT и обновить реестр
RegCmd := 'REGEDIT /s'+'REGDEMO.REG';
StrPCopy(P, RegCmd);
WinExec(P, SW_MINIMIZE);
// Завершающие действия
If FileExists('REGDEMO.REG') Then
DeleteFile('REGDEMO.REG');
End;
КомпьютерПресс 4'1999








