Link to home
Start Free TrialLog in
Avatar of Narusegawa
Narusegawa

asked on

IniFile to HashStringList

Does anyone have a function/procedure on how to read through an ini file into a THashStringList?

I've got an ini file which contains registration information and database settings for programs. This file get's decrypted, read, then re-encypted. This works fine in my user registration dll, however I'd have to rewrite the encypt/decrypt routines into each application, this is not efficient. And I'd rather not have to keep un-encrypting the inifile as I don't want end-users to even really look at it at all, but instead use my GUI.

I figure the best way to do this would be to have a function in a DLL called LoadIniFile and call it on start of my program to load the IniFile into a HashStringList in the .dll (I have a unit for storing information globally). I can then have a function called GetIniValue which accepts a string and returns a string (This does restrict me to not having 'Sections' like an IniFile normally would do), unless a 3d HashStringList can be created rather than a 2d? Anyway my question is how to read an IniFile into a HashStringList.

Thanks
Avatar of Wim ten Brink
Wim ten Brink
Flag of Netherlands image

The IniFiles unit has a class called TCustomIniFile that you can use to build your own special-formatted ini files. The same unit also has a TMemIniFile which reads a whole INI file and can write it too. Based on these two classes you might even create your own INIfile class that reads/writes the file in encrypted form.

However, encrypting data in an INI file defeats the purpose of using an INI file. Basically, an INI file is a configuration file that allows you to change the configuration without starting the application. If you want to store data in encrypted form, just dump it in a custom file format, like a stream.

Another solution if you're using Delphi 7 is to use XML instead, for storing configuration data. This allows you to divide the data on multiple levels, noy just section.key=value levels. And with XML you can just read/write the contents in encrypted form quite easily.
Avatar of Narusegawa
Narusegawa

ASKER

IniFiles and Registry are the only methods I know of storing configuration information using Delphi 6, and as my programs are ran on network shares, IniFiles seem to be the best way for me. Never created a custom file format myself and really wouldn't know where to start.
This is actually pretty simple.  Though it's unclear how you want to load the data.  If the ini file is encrypted then you have to change LoadFromFile to LoadFromStream.  And you have to decrypt the ini file and put it into a TMemoryStream.  Then call hsl.LoadFromStream(myStream);  
var
    hsl : THashedStringList;
    r : Integer;
begin
    hsl := THashedStringList.Create;
    hsl.LoadFromFile('myini.ini');

    r := 0;
    while r < hsl.Count - 1 do
    begin
        if(hsl[r][1] = '[') then // Remove any sections
        begin
            hsl.Delete(r);
            continue;
        end;

        Inc(r);
    end;
end;

Once this is done hsl contains your ini file.  Just call hsl.IndexOf('key') which returns the value of key.  
Just a quick thought, and thanks for that Tyrsis. Is it possible to load an ini file to memory? I use the following on ini files currently...

    FIniFile := TIniFile.Create(ChangeFileExt(Application.ExeName,'.ini'));
    edRegName.Text := Trim(FIniFile.ReadString('Registration','RegName',''));
    FIniFile.Free;

As I understand it the .Free clears the inifile in memory. Is there a way to keep this in memory, but close the link to the physical file.
ASKER CERTIFIED SOLUTION
Avatar of Wim ten Brink
Wim ten Brink
Flag of Netherlands image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Would something like the following work:

    FStringList := TStringList.Create;
    FStringList.LoadFromFile(ChangeFileExt(Application.ExeName,'.ini'));
    Variables.FMemIniFile.Create('');
    Variables.FMemIniFile.SetStrings(FStringList);
    FStringList.Free;

I'm trying the above but it crashes when I load my program up. I have the above in the .dpr file. But that shouldn't make a difference.
I just played a little, and the following works though. Now to just convert my project to reference the FMemIniFile instead. And a procedure to write back any changes to the inifile once I exit the program.

    FStringList := TStringList.Create;
    FStringList.LoadFromFile(ChangeFileExt(Application.ExeName,'.ini'));
    Variables.FMemIniFile := TMemIniFile.Create('');
    Variables.FMemIniFile.SetStrings(FStringList);
    FStringList.Free;

Now I'm right in understanding that if I call Variables.FMemIniFile.Free I will clear the IniFile in Memory contents? So I shouldn't do that until I exit the program (in a clean way). Obviously a crash wouldn't save changes.
Basically, you should save the INI file after you've made changes to some of the values in it. In general, INI files are configured through some configuration form. When that form closes, save the INI file. Not before, not after.
You could also save the settings when the application ends, but that's a bit useless if no settings have changed. So in general save settings after they've changed.
Thanks Workshop_Alex. Your a star!

How would I write that TMemIniFile data back to an IniFile again?

I've loaded it with the following:

  if FileExists(ChangeFileExt(Application.ExeName,'.ini')) then
  begin
    _DecryptFile(ChangeFileExt(Application.ExeName,'.ini'),Variables.FPassword);
    FStringList := TStringList.Create;
    FStringList.LoadFromFile(ChangeFileExt(Application.ExeName,'.ini'));
    Variables.FMemIniFile := TMemIniFile.Create('');
    Variables.FMemIniFile.SetStrings(FStringList);
    FStringList.Free;
    _EncryptFile(ChangeFileExt(Application.ExeName,'.ini'),Variables.FPassword);
  end;

I can't call .create on FMemIniFile again because it already exists.

Thanks
I've figured it out, I've got 2 functions now. These let me load the IniFile in and save to it later on. While maintaining it's encryption. Only thing I'm trying to figure out now is how to read the entire contents of FMemIniFile (A TMemIniFile) into something like a StringGrid (So the IniFile can be administered using a GUI form I'm designing). It's a generic optinos form that's in my .dll file so I can reuse this on all programs, each program will have it's own options screen at some point but this is for those that don't. If that makes sense. I'll probably post a question about loading a TMemIniFile into a StringGrid later on seperately.

procedure LoadIniFile();
begin
  if FileExists(ChangeFileExt(Application.ExeName,'.ini')) then
  begin
    _DecryptFile(ChangeFileExt(Application.ExeName,'.ini'),Variables.FPassword);
    Variables.FMemIniFile := TMemIniFile.Create(ChangeFileExt(Application.ExeName,'.ini'));
    _EncryptFile(ChangeFileExt(Application.ExeName,'.ini'),Variables.FPassword);
  end;
end;

function SaveIniFile():boolean;
begin
  if FileExists(ChangeFileExt(Application.ExeName,'.ini')) then
    begin
      _DecryptFile(ChangeFileExt(Application.ExeName,'.ini'),Variables.FPassword);
    end;
  try
    begin
      FMemIniFile.UpdateFile;
      FMemIniFile.Free();
      result := true;
    end
  except
    result := false;
  end;
  _EncryptFile(ChangeFileExt(Application.ExeName,'.ini'),Variables.FPassword);
end;