3

I would like to add an ini file to my delphi project as a resource file.

I know where you go to add a file as a resource file:

Project > Resources and Images > Add

But once thats done what else do I need to do to be able to read from the file? I haven't used resource files before.

Is there any documentation on the process?

Thanks,

6String_Coder
  • 517
  • 10
  • 30
  • Why? If you're adding the configuration to the exe anyway couldn't you hard-code it as well? – Uli Gerhardt Jun 08 '16 at 08:44
  • 2
    Here is a way to get text information from a resource file: [How do I add a TXT file a resource to my EXE file?](http://stackoverflow.com/a/8943364/576719). Use the stream to load it into `TMemIniFile`. – LU RD Jun 08 '16 at 08:50

4 Answers4

4

The built-in INI file classes in the RTL, providing in the System.IniFiles unit, require the INI file to be a disk file. So you could extract the resource to disk and read it from there.

If you don't like the idea of that then you could write your own INI file parser that operated on a stream rather than a file. You could use the code of TMemIniFile to guide you. Copy that code and replace LoadValues with code to read from a stream rather than a file. Or if you look hard enough then you may well find a third party INI parser that operates on streams.

If you are prepared to consider other formats then you might use JSON rather than INI. The built-in JSON parser does not require the input data to reside on disk. They can operate on in-memory strings, which sounds rather more convenient.

This above text is in fact nonsense. Thank you to Remy for pointing that out. You can use TMemIniFile and its SetStrings method to parse INI content that does not reside on disk. It goes like this:

  • Put your INI content into a resource as a string.
  • Load that resource into a string variable.
  • Create a TStringList, and assign the string variable to the Text property of the string list.
  • Create a TMemIniFile.
  • Call SetStrings on the TMemIniFile passing the string list.

Or:

  • Put your INI content into a resource as a string.
  • Create a TResourceStream object to read that resource.
  • Create a TStringList object.
  • Call LoadFromStream on the string list passing the resource stream.
  • Create a TMemIniFile.
  • Call SetStrings on the TMemIniFile passing the string list.

Having said all of this, it seems odd that you would choose to do this at all. Wouldn't it be simpler just to hard code the configuration information in a unit, as a series of constants?

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 2
    "*The built-in INI file classes in the RTL, providing in the System.IniFiles unit, require the INI file to be a disk file*" - TMemIniFile can load an INI from a TStrings (TMemIniFile.SetStrings()), a TStringList can be loaded from a TStream (TStrings.LoadFromStream()), and TResourceStream can be used to read a resource. – Remy Lebeau Jun 08 '16 at 15:29
  • @RemyLebeau Thank you – David Heffernan Jun 08 '16 at 15:50
3

Using the "Resources and Images" dialog, add the .ini file to the project as a RCDATA resource type. Then, you can load it at runtime like this:

uses
  ..., Classes, IniFiles;

var
  Ini: TMemIniFile;
  List: TStringList;
  Strm: TResourceStream;
begin
  Ini := TMemIniFile.Create;
  try
    List := TStringList.Create;
    try
      Strm := TResourceStream.Create(HInstance, 'ResourceIDHere', RT_RCDATA);
      try
        List.LoadFromStream(Strm);
      finally
        Strm.Free;
      end;
      Ini.SetStrings(List);
    finally
      List.Free;
    end;
    // use Ini as needed...
  finally
    Ini.Free;
  end;
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
2

To add the files in the executable, be sure to add a .rcfile (not the .ini files directly), for example inis.rc (so in the source file dpr you'll have {$R 'inis.res' 'inis.rc'}) and write in this file a list like this:

this 100 "this.ini"
that 100 "that.ini"

If you've stored the ini files in a (relative) directory, be sure to double the backslashes since this in C-syntax. (The 100here is the resource type, there's no number assigned to ini-files specifically so we'll use an unassigned number. The best next thing is 23 which is assigned to RT_HTML, see below)

If you're not using groups (and lines with just [GroupName]), I'd suggest you use plain TStringList objects and their Values property. To load them with the data, use something like this:

var
  sl:TStringList;
  r:TResourceStream;
begin
  sl:=TStringList.Create;
  try
    r:=TResourceStream.Create(HInstance,'this',MAKEINTRESOURCE(100));
    try
      sl.LoadFromStream(r);
    finally
      r.Free;
    end;

    //sl.Values['Setting']

  finally
    sl.Free;
  end;
end;
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
Stijn Sanders
  • 35,982
  • 11
  • 45
  • 67
1

imho, an ini file is just a text file to distribute with an application so you can control behavior of the application in one particular environment. For example, you could store a language in "language.ini", read it from your source code, and present the GUI based on that language.

To accomplish this, your ini file contains:

[general]
language=Russian

then read it from Delphi:

    ...
    uses Inifiles;
    ...
    var CurrentLanguage:string;
    ...    
    Ini := TIniFile.Create('C:\somedir\languages.ini');    
    CurrentLanguage := Ini.ReadString('General', 'language', 'English');//if key isn't found, language is English    
    Ini.free();

So basically it contains TEXT info... as said above, if you add it as a resource, you might as well hardcode it. Resources should be used primarily for binary data (an image, audio file, video, etc).

Jur
  • 520
  • 2
  • 18