Delphi 4. Использование реестра

Алексей Федоров

Модуль Registry

   TRegIniFile

Класс TRegistry

   Инициализация

   Задание корневой секции

    Чтение данных

   Чтение всей подсекции

   Запись бинарных данных

   Сохранение подсекции в файле

   Получение информации о подсекции

Использование программы 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