There is a lot of difference between resources files in Delphi and Lazarus.
Resources is any file you want to embed along with the executable. Common practice is to have images, sound effects, html/dll/etc files scattered or distributed on disk during installation. Using resources means that you can embed it in the executable and when you run it then take advantage of those resources however you want. For example, using CEF4 (Chromium Browser) built into our application will require some DLLs in the same directory as the executable, of course I can create an installer that distributes these DLLs to my application or use resources to transfer these DLLs from within the executable to the installation folder and ensure the program works with the planned DLLs. But its use is not restricted to extracting files to disk, this is just one of the possibilities, the most common is loading images or playing sound effects with .jpg and .wav files without having to extract anything.
The way Lazarus handles resources – in my opinion – is much better than the way Delphi handles it, let's see the differences:
In Delphi, at the beginning of the project or form you would do like this:
{$R arquivo.res}
In Lazarus we will use it like this:
{$R file.lrs} or {$I file.lrs}
It's not just the extension or directive that changes, the way the .lrs file is generated will also be different. While in Delphi you need to create an intermediate file (.rc) containing the list of files that will later be transferred to a .res, for example a .rc file like this:
MYDATA RCDATA "mydata.dat"
Where each line of this file(.rc) indicating a different file to later generate a .res file. Delphi uses a built-in utility – available in the IDE – to convert this .rc->.res file, in Lazarus we'll do it through a command line program without needing an intermediate file (.rc), just:
C:\Lazarus\Tools\lazres.exe file.lrs image1.jpg image2.jpg myDLL.dll
And the file.lrs file will be generated which, unlike Delphi, is not binary and can be versioned by tools such as git. There is also a GUI that simplifies this operation and can be found at this link:
The way to use resources that I found most suitable is to include in the Uses section:
uses …LResources…;
And to enjoy, let's avoid doing what most Delphi programmers do which is to include the {$R} directive next to the implementation statement. Lazarus documentation recommends it should be in the section initialization (we will probably create it) in the first unit to be loaded into the project:
initialization
{$I file.lrs}
And to enjoy the content there are several ways, for images it is done this way:
procedure exampleproc;
var
Image: TImage
begin
Image := TImage.Create;
// note que não precisamos da extensão
Image.Picture.LoadFromLazarusResource('image1');
end;
The best way to use it is as shown in the example above, loading the resource directly to the component without having to write it to disk first, it seems that most of the components that use Lazarus' TGraphic have been adapted to allow loading directly from the resources this way. In Delphi we would do this using a TStream.
However, life is not just made up of pictures and sometimes we use files of other formats like .dll to ensure that the program works correctly. So on initial program load we will need to instruct it to extract them to the proper folder.
We would go to the section initialization (or create it) from the first unit to be loaded in the project and we would extract it like this:
initialization
{$I arquivo.lrs}
RootDir:=ExtractFilepath(ParamStr(0));
Extract_ResFileTo('image1', RootDir+PathDelim+'img’+PathDelim+’image1.jpg');
Extract_ResFileTo('image2', RootDir+PathDelim+'img’+PathDelim+’image2.jpg');
Extract_ResFileTo('minhaDLL', ExtractFilepath(ParamStr(0))+PathDelim+'minhaDLL.dll');
The example above used the Extract_ResFileTo function that does not exist in Lazarus, here is its code:
function Extract_ResFileTo(AResName: String; ASaveFileTo: String):String; var res: TLResource; st: TLazarusResourceStream; begin Result:=emptyStr; st := nil; if Result=emptyStr then begin if not DirectoryExists(ExtractFilePath(ASaveFileTo)) then begin // Create extract directory if it does not exist if not ForceDirectories(ExtractFilePath(ASaveFileTo)) then begin Result:='Directory does not exist: '+ExtractFilePath (ASaveFileTo); end; end; end; if Result=emptyStr then begin res:=LazarusResources.Find(AResName); if res=nil then begin Result:='RC with name "'+AResName+'" was not found.'; end else begin try st := TLazarusResourceStream.Create(AResName, nil); // saving to disk st.SaveToFile(ASaveFileTo); finally st.Free; end; end; end; end;
You will find this need to extract resources files to disk when using components like CEF4, MPlayer and others that need specific DLLs to be in your project's executable directory. Of course I could copy them manually, but this is unproductive and prone to errors so the best thing is to get those DLLs and embed them as resource files and when the program starts then check for the existence of DLLs and if they don't exist then extract them to the appropriate folder.
Credits:
Adding resources to your program