Jump to content
dummzeuch

TCustomInifile.ReadSubSections in older Delphi versions

Recommended Posts

I just implemented some functionality using TCustomIniFile.ReadSubSections which depending on the type passed to it, either calls the TMemIniFile or the TRegistryIniFile method. Something like:

procedure doSomething(_Ini: TCustomIniFile);
var
  sl: TStringList;
begin
  sl := TStringList.Create;
  try
    _Ini.ReadSubSections(sl)
    for i := 0 to sl.Count - 1 do begin
      doSomethingWith(sl[i]);
    end;
  finally
    FreeAndNil(sl)
  end;
end;

This works fine in Delphi 10.2 but not in Delphi 7 because TCustomIniFile.ReadSubSections didn't exist back then.

 

I need that functionality for older Delphi versions, so I somehow must implement ReadSubSections there. Unfortunately the implementations differ greatly for TMemIniFile and TRegistryIniFile. I'd have to check which class is passed in and call the respective implementation.

if _Ini is TMemIniFile then
  HandleMemIniFile(_Ini)
else if _Ini is TRegistryIniFile then
  HandleRegistryIniFile(_Ini)
else
  raise Exception.Create('Only TMemIniFile or TRegistryIniFile supported');

But this just feels very clunky. Is there any better way?

(Just in case somebody wants to suggest them: Class helpers didn't exist in Delphi 7 either.)

Edited by dummzeuch

Share this post


Link to post
1 hour ago, dummzeuch said:

 


if _Ini is TMemIniFile then
  HandleMemIniFile(_Ini)
else if _Ini is TRegistryIniFile then
  HandleRegistryIniFile(_Ini)
else
  raise Exception.Create('Only TMemIniFile or TRegistryIniFile supported');

But this just feels very clunky. Is there any better way?

 

How about 

Type
  TdzIniFile = Class(TmemIniFile)
  {$if ver < 12} //
    procedure dealwithsubsections
  {$endif}             
  TdzRegFile = Class(TRegIniFile)
    procedure dealwithsubsections            
                

  

   Having two components  would match better with their mem or reg business. 

   Unsure if switch is usable or needed. 

      

Share this post


Link to post
34 minutes ago, Pat Foley said:

How about 


Type
  TdzIniFile = Class(TmemIniFile)
  {$if ver < 12} //
    procedure dealwithsubsections
  {$endif}             
  TdzRegFile = Class(TRegIniFile)
    procedure dealwithsubsections            
                

  Having two components  would match better with their mem or reg business. 

   Unsure if switch is usable or needed.      

(I must be CompilerVersion < 14 because the method was introduced in Delphi 2010.)

 

Unfortunately subclassing TMemIniFile and TRegistryIniFile wouldn't allow me to pass TCustomIniFile.

Share this post


Link to post
14 hours ago, Pat Foley said:

  Not that's important or relevant , found this https://stackoverflow.com/questions/7090053/read-all-ini-file-values-with-getprivateprofilestringthis . Would be able to go back to D1 🙂

 

Wouldn't the subclass work since would still descend from TcustomIniFile?   

Yes, but I would still have to use similar code as above to typecast to the correct class.

Share this post


Link to post
On 8/14/2021 at 3:59 PM, dummzeuch said:

(Just in case somebody wants to suggest them: Class helpers didn't exist in Delphi 7 either.)

But interposers did.

Share this post


Link to post
4 hours ago, Frickler said:

But interposers did.

Yes, but how could they help here?

Share this post


Link to post
On 8/14/2021 at 6:59 AM, dummzeuch said:

I need that functionality for older Delphi versions, so I somehow must implement ReadSubSections there. Unfortunately the implementations differ greatly for TMemIniFile and TRegistryIniFile. I'd have to check which class is passed in and call the respective implementation.

I really don't think you are going to be able to avoid that if you want to support different versions with varying implementations, eg:

procedure doSomething(_Ini: TCustomIniFile);
var
  sl: TStringList;

  {$IF CompilerVersion >= 14}

  procedure ReadSubSections(const Section: string; Strings: TStrings; Recurse: Boolean = False);
  begin
    _Ini.ReadSubSections(Section, Strings, Recurse);
  end;

  {$ELSE}

  procedure ReadMemSubSections(_MIni: TMemIniFile; const Section: string; Strings: TStrings; Recurse: Boolean = False);
  begin
    // add to Strings as needed...
  end;

  procedure ReadRegistrySubSections(_RIni: TRegistryIniFile; const Section: string; Strings: TStrings; Recurse: Boolean = False);
  begin
    // add to Strings as needed...
  end;

  procedure ReadSubSections(const Section: string; Strings: TStrings; Recurse: Boolean = False);
  begin
    if (_Ini is TMemIniFile) then
      ReadMemSubSections(TMemIniFile(_Ini), Section, Strings, Recurse)
    else if (_Ini is TRegistryIniFile) then
      ReadRegistrySubSections(TRegistryIniFile(_Ini), Section, Strings, Recurse)
    else
      raise Exception.Create('Only TMemIniFile or TRegistryIniFile are supported');
  end;

  {$IFEND}

begin
  sl := TStringList.Create;
  try
    ReadSubSections('Section', sl);
    for i := 0 to sl.Count - 1 do begin
      doSomethingWith(sl[i]);
    end;
  finally
    sl.Free;
  end;
end;

 

Edited by Remy Lebeau
  • Like 1

Share this post


Link to post
On 8/15/2021 at 12:39 AM, dummzeuch said:

Yes, but I would still have to use similar code as above to typecast to the correct class.

Actually, maybe you could try something like this:

type
  ICanReadSubSections = interface
    ['{...}']
    procedure ReadSubSections(const Section: string; Strings: TStrings; Recurse: Boolean = False);
  end;

  TdzMemIniFile = class(TMemIniFile, ICanReadSubSections)
  public
    {$IF CompilerVersion < 14}
    procedure ReadSubSections(const Section: string; Strings: TStrings; Recurse: Boolean = False);
    {$IFEND}
  end;
                
  TdzRegistryIniFile = class(TRegistryIniFile, ICanReadSubSections)
  public
    {$IF CompilerVersion < 14}
    procedure ReadSubSections(const Section: string; Strings: TStrings; Recurse: Boolean = False);
    {$IFEND}
  end;
  
{$IF CompilerVersion < 14}
procedure TdzMemIniFile.ReadSubSections(const Section: string; Strings: TStrings; Recurse: Boolean = False);
begin
  // add to Strings as needed...
end;

procedure TdzRegistryIniFile.ReadSubSections(const Section: string; Strings: TStrings; Recurse: Boolean = False);
begin
  // add to Strings as needed...
end;
{$IFEND}

And then you can do this:

procedure doSomething(_Ini: TCustomIniFile);
var
  Intf: ICanReadSubSections;
  sl: TStringList;
begin
  if not Supports(_Ini, ICanReadSubSections, Intf) then raise Exception.Create('ICanReadSubSections not implemented');
  sl := TStringList.Create;
  try
    Intf.ReadSubSections('Section', sl);
    for i := 0 to sl.Count - 1 do begin
      doSomethingWith(sl[i]);
    end;
  finally
    sl.Free;
  end;
end;
Edited by Remy Lebeau
  • Thanks 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×