unit IniObj;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  IniFiles, TypInfo;

type
  TIniObject = class(TComponent)
  private
    { Private declarations }
    FFileName: shortstring;
    FIniExt: shortstring;
    FUseSectionPrefix: boolean;
    FFormNameIsIniName: boolean;
    FDisabled:boolean;
    FAutoSaved:boolean;
  protected
    { Protected declarations }
    procedure ReadWrite(read:boolean);
    procedure Loaded;override;
  public
    { Public declarations }
    procedure Read;
    { published properties of all Owner components from
      ini file }
    procedure Write;
    { properties of all Owner components to ini file }
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  published
    { Published declarations }
    property FileName:shortstring read FFileName write FFileName;
    { if not assigned than ExeName.Ini used in ExeDir;
      if assigned but no dir specified, then ExeDir used }
    property IniExt:shortstring read FIniExt write FIniExt;
    { extension for ini file; if not specified, then '.INI' used }
    property UseSectionPrefix:boolean read FUseSectionPrefix write FUseSectionPrefix default true;
    { if true, then section name consists from form name and
      component name separated with dot, if false, then
      just component name is used for the section name }
    property FormNameIsIniName:boolean read FFormNameIsIniName
      write FFormNameIsIniName;
    { Considered only if FileName not specified.
      if true then Owner form name is used as FileName
      (IniExt appended); if false then ExeName with IniExt
      used }
    property Disabled:boolean read FDisabled write FDisabled;
    { if set true, then read/write methods have no effect }

  end;

procedure Register;

implementation

procedure TIniObject.Read;
    { published properties of all Owner components from
      ini file }
begin
  ReadWrite(true);
end;

procedure TIniObject.Write;
begin
  ReadWrite(false);
end;

procedure TIniObject.ReadWrite(read:boolean);
var
  f: TIniFile;
  fn: string;
  i, { component index }
  j  { property index }
  : integer;
  c: TComponent;
  ti: PTypeInfo;
  td: PTypeData;
  pl: TPropList;
  pi: PPropInfo;
  vs: shortstring;
  ext: shortstring;
  secpref:shortstring;
begin
  if Owner = nil then
    exit;
  if FDisabled then
    exit;
  fn := FFileName;
  ext := FIniExt;
  if ext = '' then
    ext := '.INI';
  if fn = '' then begin begin
    if FFormNameIsIniName then begin
      fn := Owner.Name + ext;
    end else begin
      fn := ChangeFileExt(Paramstr(0), ext)
    end;
  end;
  end else begin
    if ExtractFileExt(fn) = '' then
      fn := ChangeFileExt(fn, ext);
  end;
  if ExtractFileDir(fn) = '' then begin
    fn := ExtractFileDir(Paramstr(0)) + fn;
  end;
  f := TIniFile.Create(fn);
  if FUseSectionPrefix then
    secpref := Owner.Name + '.'
  else
    secpref := '';

  for i := 0 to Owner.ComponentCount - 1 do begin
    c := Owner.Components[i];
    if c = Self then
      continue;
    ti := PTypeInfo(c.ClassInfo);
    td := PTypeData(GetTypeData(ti));
    GetPropInfos(ti, @pl);

    for j := 0 to td^.PropCount - 1 do begin
      pi := pl[j];

      if read then begin
        vs := f.ReadString(secpref + c.Name, pi^.Name, '');
        if vs <> '' then begin
          case pi^.PropType^^.Kind of
            tkInteger: SetOrdProp(c, pi, StrToInt(vs));
            tkFloat: SetFloatProp(c, pi, StrToFloat(vs));
            tkString: SetStrProp(c, pi, vs);
          end;
        end;
      end else begin
        vs := '';
        case pi^.PropType^^.Kind of
          tkInteger: vs := IntToStr(GetOrdProp(c, pi));
          tkFloat: vs := FloatToStr(GetFloatProp(c, pi));
          tkString: vs := GetStrProp(c, pi);
        end;
        if vs <> '' then
          f.WriteString(secpref + c.Name, pi^.Name, vs);
      end;
    end;

  end;

  f.Free;
end;

procedure TIniObject.Loaded;
begin
  Read;
end;

procedure TIniObject.Notification(AComponent: TComponent; Operation: TOperation);
begin
  if (Operation = opRemove) and (not FAutoSaved) then begin
    FAutoSaved := true;
    Write;
  end;
end;

procedure Register;
begin
  RegisterComponents('Samples', [TIniObject]);
end;

end.
