Delphi имеет маленький секрет, позволяющий рекурсивно сохранять в регистрах любые публичные свойства объектов. В качестве примера покажем как это работает для TFont.
uses TypInfo; { Определяем тип-набор для доступа к битам целого. } const BitsPerByte = 8;type TIntegerSet = set of 0..SizeOf(Integer)*BitsPerByte - 1; { Сохраняем набор свойств в виде подключа. Каждый элемент перечислимого типа - отдельная логическая величина. Истина означает что элемент включен в набор,Ложь - элемент в наборе отсутствует. Это позволит пользователюс помощью редактора ресурсов (REGEDIT) легко изменять конфигурацию. }procedure SaveSetToRegistry(const Name: string; Value: Integer; TypeInfo: PTypeInfo; Reg: TRegistry);var OldKey: string;I: Integer;begin TypeInfo := GetTypeData(TypeInfo)^.CompType;OldKey := '\' + Reg.CurrentPath;if not Reg.OpenKey(Name, True) thenraise ERegistryException.CreateFmt('Не могу создать ключ: %s',[Name]); { Организуем цикл для всех элементов перечислимого типа. }with GetTypeData(TypeInfo)^ dofor I := MinValue to MaxValue do{ Записываем логическую величину для каждого установленного элемента. }Reg.WriteBool(GetEnumName(TypeInfo, I), I inTIntegerSet(Value)); { Возвращаем родительский ключ. }Reg.OpenKey(OldKey, False);end; { Сохраняем объект в регистрах в отдельном подключе. } procedure SaveObjToRegistry(const Name: string; Obj: TPersistent; Reg: TRegistry);var OldKey: string;begin OldKey := '\' + Reg.CurrentPath;{ Открываем подключ для объекта. }if not Reg.OpenKey(Name, True) thenraise ERegistryException.CreateFmt('Не могу создать ключ: %s',[Name]); { Сохраняем свойства объекта. }SaveToRegistry(Obj, Reg); { Возвращаем родительский ключ. }Reg.OpenKey(OldKey, False);end; { Сохраняем в регистрах метод путем записи его имени. } procedure SaveMethodToRegistry(const Name: string; const Method: TMethod; Reg: TRegistry);var MethodName: string;begin { Если указатель на метод содержит nil, сохраняем пустую строку. }if Method.Code = nil thenMethodName := ''else{ Находим имя метода. }MethodName := TObject(Method.Data).MethodName(Method.Code);Reg.WriteString(Name, MethodName);end; { Сохраняем в регистре каждое свойство в виде значения текущего ключа. } procedure SavePropToRegistry(Obj: TPersistent; PropInfo: PPropInfo; Reg: TRegistry); begin with PropInfo^ docase PropType^.Kind oftkInteger,tkChar,tkWChar:{ Сохраняем порядковые свойства в виде целочисленного значения. }Reg.WriteInteger(Name, GetOrdProp(Obj, PropInfo));tkEnumeration:{ Сохраняем имена перечислимых величин. }Reg.WriteString(Name, GetEnumName(PropType, GetOrdProp(Obj,PropInfo))); tkFloat:{ Сохраняем реальные числа как Doubles. }Reg.WriteFloat(Name, GetFloatProp(Obj, PropInfo));tkString,tkLString:{ Сохраняем строки как строки. }Reg.WriteString(Name, GetStrProp(Obj, PropInfo));tkVariant:{ Сохраняем вариантные величины как строки. }Reg.WriteString(Name, GetVariantProp(Obj, PropInfo));tkSet:{ Сохраняем набор как подключ. }SaveSetToRegistry(Name, GetOrdProp(Obj, PropInfo), PropType,Reg); tkClass:{ Сохраняем класс как подключ, а его свойствав виде значений подключа. }SaveObjToRegistry(Name, TPersistent(GetOrdProp(Obj, PropInfo)),Reg); tkMethod:{ Сохраняем в регистрах метод путем записи его имени. }SaveMethodToRegistry(Name, GetMethodProp(Obj, PropInfo), Reg);end;end; { Записываем объект в регистр, сохраняя опубликованные свойства. } procedure SaveToRegistry(Obj: TPersistent; Reg: TRegistry); var PropList: PPropList;PropCount: Integer;I: Integer;begin { Получаем список опубликованных свойств. }PropCount := GetTypeData(Obj.ClassInfo)^.PropCount;GetMem(PropList, PropCount*SizeOf(PPropInfo));tryGetPropInfos(Obj.ClassInfo, PropList);{ Сохраняем каждое свойство в виде значения текущего ключа. }for I := 0 to PropCount-1 doSavePropToRegistry(Obj, PropList^[I], Reg);finallyFreeMem(PropList, PropCount*SizeOf(PPropInfo));end;end; { Сохраняем опубликованные свойства в виде значения данного ключа. Корневой улей - HKEY_CURRENT_USER. }procedure SaveToKey(Obj: TPersistent; const KeyPath: string); var Reg: TRegistry;begin Reg := TRegistry.Create;tryif not Reg.OpenKey(KeyPath, True) thenraise ERegistryException.CreateFmt('Не могу создать ключ: %s',[KeyPath]); SaveToRegistry(Obj, Reg);finallyReg.Free;end;end; |
[000225]