dummzeuch 1505 Posted August 14, 2021 (edited) 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 August 14, 2021 by dummzeuch Share this post Link to post
Pat Foley 51 Posted August 14, 2021 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
dummzeuch 1505 Posted August 14, 2021 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
Pat Foley 51 Posted August 14, 2021 (edited) 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? Edited August 14, 2021 by Pat Foley Fixed link added question Share this post Link to post
dummzeuch 1505 Posted August 15, 2021 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
Frickler 11 Posted August 16, 2021 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
dummzeuch 1505 Posted August 16, 2021 4 hours ago, Frickler said: But interposers did. Yes, but how could they help here? Share this post Link to post
Remy Lebeau 1394 Posted August 16, 2021 (edited) 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 August 16, 2021 by Remy Lebeau 1 Share this post Link to post
Remy Lebeau 1394 Posted August 16, 2021 (edited) 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 August 16, 2021 by Remy Lebeau 1 Share this post Link to post