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