Resources no Delphi: Como embutir arquivos no executável

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (13)  (0)

Aprenda neste artigo a embutir textos, imagens, sons, DLLs e outros recursos dentro do executável e reutilizá-los quando necessário.

Motivação

Para gerar um executável pequeno, uma das práticas mais utilizadas é a de modularizar o projeto em vários EXEs, DLLs, BPLs, e manter separados os arquivos auxiliares de texto, imagens ou sons. Essa prática é útil para diminuir o tráfego de arquivos durante as atualizações do sistema, executando o update apenas daqueles que realmente sofreram modificações.

No entanto, caso seja necessário manter um único arquivo para todo o sistema, o Delphi oferece a possibilidade de trabalhar com resources, uma forma de embutir arquivos externos dentro do executável e acessá-los posteriormente quando necessário.

Nesse artigo veremos como utilizar essa funcionalidade a partir do Delphi 2010, versão na qual o IDE passou a oferecer uma interface amigável para gerenciar os recursos.

Saiba mais sobre o Delphi no Guia de Referência

Adicionando arquivos ao projeto

Embora esse recurso exista desde a versão 3 do Delphi, a forma de incorporar arquivos externos ao executável foi melhorada significativamente a partir da versão 2009. Atualmente, é possível utilizar um gerenciador de recursos que pode ser acessado através do menu Project > Resources and Images. Na Figura 1 é possível observar diversos arquivos adicionados através da tela de gerenciador de recursos.


Figura 1. Tela de gerenciamento de Resources

Assim que os arquivos são adicionados, eles aparecem no Projetct Manager do Delphi, onde você poderá selecioná-los e alterar suas propriedades no Object Inspector conforme mostra a Figura 2.


Figura 2. Project Manager com arquivos adicionados aos recursos

Uma vez que os arquivos tenham sido adicionados, quando o projeto é compilado, é gerado um arquivo de texto com extensão *.rc, que contém em cada linha um “alias” (apelido) para referenciar o arquivo, seu caminho físico e o tipo de dado do recurso. O conteúdo desse arquivo referente à Figura 2 pode ser visto na Listagem 1.

  WAVRelogio RCDATA "8672.mp3"
  DllAuxiliar RCDATA "auxiliar.dll"
  ExeCalc RCDATA "calc.exe"
  IMGDevmediaLogo RCDATA "devmedia2peq.PNG"
  TXTuf RCDATA "Siglas-UF.txt"
  IMGPredio BITMAP "Company-icon.bmp"
  
Listagem 1. Conteúdo do arquivo ProjectResourcesTestResource.rc

Depois do arquivo *.rc ter sido gerado, o Delphi o compila em uma versão intermediária com extensão *.dres, que será utilizada durante o processo de linkagem e posteriormente gerará um novo arquivo de extensão *.res, que finalmente é encapsulado dentro do executável.

Reutilizando arquivos de texto

Os arquivos que não se encaixam nos padrões pré-definidos para resources (bitmaps, ícones e arquivos de fontes), como os de texto, são encapsulados como um tipo binário denominado RCData. A partir disso, para acessá-los, é necessário fazer uso de uma classe denominada TResourceStream, que permite carregar o arquivo em qualquer componente que tenha uma propriedade do tipo TStrings, utilizando para isso uma única linha de código. Por exemplo, podemos carregar facilmente o conteúdo do arquivo e exibi-lo em um ListBox com o seguinte comando:

  ListBox1.Items.LoadFromStream(TResourceStream.Create(HInstance,'TXTuf',RT_RCDATA)); 
  

Ao instanciar a classe TResourceStream na chamada do método LoadFromStream da classe TStrings, por exemplo, é necessário passar ao menos três parâmetros: uma variável de ponteiro chamada HInstance, o “alias” que faz referência ao recurso e uma constante que representa o tipo de dado no qual o recurso está armazenado no executável.

Reutilizando arquivos de imagens

Os arquivos de imagem podem ser reutilizados de duas formas, dependendo do seu tipo. Caso sejam imagens de ícones, arquivos *.bmp e cursores, existe o método LoadFromResourceName, que permite carregá-los com apenas uma linha de código:

  Image2.Picture.Bitmap.LoadFromResourceName(HInstance,'IMGPredio'); 
  

Observe que por se tratar de uma imagem com extensão *.bmp, o método não contém rotinas de conversão adicionais, algo que não ocorre com imagens de outros formatos, que são compiladas como binários.

A segunda forma é utilizada quando tratamos de imagens do tipo PNG ou JPEG, por exemplo, casos em que é preciso utilizar classes que tratem adequadamente o recurso. Podemos ver um exemplo disso na Listagem 2.

01 procedure TForm3.Button2Click(Sender: TObject);
02 var
03   png: TPngImage;
04 begin
05   png:=TPngImage.Create;
06   png.LoadFromResourceName(HInstance, 'IMGDevmediaLogo');
07   Image1.Picture.Graphic:=png;
08 end; 
Listagem 2. Exemplo de reutilização de um uma imagem *.png como resource

Linha 05: Instanciamos um objeto do tipo TPngImage;

Linha 06: O método LoadFromResourceName recebe o “alias” da imagem do tipo *.png que foi compilada como RCData;

Linha 07: Atribuímos a instância png para a propriedade Graphic, que resulta na exibição da imagem no componente.

Reutilizando arquivos de áudio, executáveis, DLLs, entre outros

Os arquivos de tipos diferentes dos que vimos até agora também são compilados como RCData, mas para utilizá-los é preciso extraí-los utilizando a combinação das classes TResourceStream e TFileStream, conforme apresentado na Listagem 3. Nesse exemplo fizemos uso de um arquivo MP3, mas o mesmo código serviria para os demais tipos, como executáveis ou DLLs.

01 procedure TForm3.btnExecutarMP3(Sender: TObject);
02 var
03   fs: TFileStream;
04   rs: TResourceStream;
05   s : string;
06   m : TMediaPlayer;
07 begin
08   rs := TResourceStream.Create(hInstance, 'WAVRelogio', RT_RCDATA);
09   s  := ExtractFilePath(Application.ExeName)+'file.mp3';
10   fs := TFileStream.Create(s,fmCreate);
11   rs.SaveToStream(fs);
12   fs.Free;
13 
14   MediaPlayer.Close;
15   MediaPlayer.FileName:=s;
16   MediaPlayer.Open;
17   MediaPlayer.Play;
18 end;
Listagem 3. Exemplo de reutilização de um arquivo MP3 como resource

Linha 08: Instanciamos um TResourceStream, passando como parâmetro o “alias” do arquivo MP3 e o tipo de dado (RCData);

Linha 09: Atribuímos à variável string o caminho de um diretório para extrair o arquivo;

Linhas 10 e 11: Instanciamos a classe TFileStream, passando o caminho onde o arquivo será criado. Na sequência, salvamos todo o conteúdo do resource carregado na linha 8 no arquivo;

Linhas 14 a 17: Executamos o arquivo MP3 extraído do executável.

Embora sejam muito úteis para transportar arquivos no próprio executável e reutilizá-los dentro do sistema, deve-se ter cuidado com o uso de resources. Como não há uma compactação efetiva do arquivo, seu tamanho normalmente acaba aumentando mais do que o esperado.

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Ficou com alguma dúvida?