Embutindo arquivos como recursos em um executável delphi

Como embutir, ícones, cursores, cursores animados, bitmaps, imagens jpeg, arquivos wave, arquivos de texto e muitos outros dentro de um executável Delphi.

Como embutir, ícones, cursores, cursores animados, bitmaps, imagens jpeg, arquivos wave, arquivos de texto e muitos outros dentro de um executável Delphi.

Embutindo arquivos como recursos em um executável Delphi

É possível embutir qualquer tipo de arquivo em um executável usando arquivos de recurso (*.RES). Certos tipos de recursos são reconhecidos pelo API (ou Interface de Programação de Aplicativos) e podem ser usados diretamente. Outros são simplesmente tomados como dados binários e cabe a você usá-los. Neste artigo, nós veremos exemplos de ambos os tipos.

Para criar o arquivo recurso, nós começamos com o arquivo fonte (*.RC), por exemplo, nomeado RESOURCES.RC, que é um arquivo de texto simples que contém as entradas de recurso (nome, classe e arquivo):

sample_bmp BITMAP sample.bmp

  sample_ico ICON sample.ico

  sample_cur CURSOR sample.cur

  sample_ani ANICURSOR sample.ani

  sample_jpg JPEG sample.jpg

  sample_wav WAVE sample.wav

  sample_txt TEXT sample.txt

Os nomes dos recursos (sample_bmp, sample_ico, etc) são arbitrários. O tipo de recurso pode ser reconhecido pelos API’s (BITMAP, ICON, CURSOR) ou arbitrário (JPEG, WAVE, TEXT).  Os nomes dos arquivos especificam os arquivos que serão incluídos no arquivo .RES (e mais tarde no .EXE).

Agora nós temos de compilar o arquivo .RC para produzir o arquivo.RES., para que nós possamos usar o Compilador de Recurso Borland (brcc32.exe), que você provavelmente encontra na pasta BIN do Delphi. Ele é um utilitário de linha de comando simples que espera o nome do arquivo fonte como parâmetro:

C:\DELPHI\P0025>brcc32 resources

  Borland Resource Compiler Version 5.40

  Copyright (c) 1990, 1999 Inprise Corporation. All rights reserved.



  C:\DELPHI\P0025>_

Para instruir o vinculador a embutir o arquivo de recurso no executável, nós usamos o arquivo de recurso diretivo ($R ou $RESOURCE) em nosso código fonte Pascal:
{$R resources.res}

Carregar os recursos na sua aplicação é fácil para os recursos “reconhecidos” como BITMAP, ICON e CURSOR desde que o API do Windows forneça as funções (LoadBitmap, LoadICon eLoadCursor respectivamente) para obter handles para estes elementos, que, por exemplo, nós possamos atribuir para a propriedade Handle do objeto correspondente:

Image1.Picture.Bitmap.Handle :=

      LoadBitmap(hInstance, 'sample_bmp');

    Icon.Handle := LoadIcon(hInstance, 'sample_ico');

    Screen.Cursors[1] := LoadCursor(hInstance, 'sample_cur');

Outros recursos são um pouco mais difíceis de lidar. Vamos começar com imagens JPEG. A seguinte função usa TResourceStream para carregar o recurso como um stream que será carregado em um objeto TJPEGImage:

function GetResourceAsJpeg(const resname: string): TJPEGImage;

  var

    Stream: TResourceStream;

  begin

    Stream := TResourceStream.Create(hInstance, ResName, 'JPEG');

    try

      Result := TJPEGImage.Create;

      Result.LoadFromStream(Stream);

    finally

      Stream.Free;

    end;

  end;

Exemplo:
var

    Jpg: TJPEGImage;

  begin

    // ...

    Jpg := GetResourceAsJpeg('sample_jpg');

    Image2.Picture.Bitmap.Assign(Jpg);

    Jpg.Free;

    // ...

  end;

Para arquivos WAV, nós precisamos um indicador para o recurso carregado na memória, e, para o arquivo texto, nós precisamos carregar um recurso em uma corda. Nós podemos fazer isso usando o TResourceStream, mas vamos ver um exemplo usando o API:

function GetResourceAsPointer(ResName: pchar; ResType: pchar;

                                out Size: longword): pointer;

  var

    InfoBlock: HRSRC;

    GlobalMemoryBlock: HGLOBAL;

  begin

    InfoBlock := FindResource(hInstance, resname, restype);

    if InfoBlock = 0 then

      raise Exception.Create(SysErrorMessage(GetLastError));

    size := SizeofResource(hInstance, InfoBlock);

    if size = 0 then

      raise Exception.Create(SysErrorMessage(GetLastError));

    GlobalMemoryBlock := LoadResource(hInstance, InfoBlock);

    if GlobalMemoryBlock = 0 then

      raise Exception.Create(SysErrorMessage(GetLastError));

    Result := LockResource(GlobalMemoryBlock);

    if Result = nil then

      raise Exception.Create(SysErrorMessage(GetLastError));

  end;



  function GetResourceAsString(ResName: pchar; ResType: pchar): string;

  var

    ResData: PChar;

    ResSize: Longword;

  begin

    ResData := GetResourceAsPointer(resname, restype, ResSize);

    SetString(Result, ResData, ResSize);

  end;

Chamadas de exemplo:
var

    sample_wav: pointer;



  procedure TForm1.FormCreate(Sender: TObject);

  var

    size: longword;

  begin

    ...

    sample_wav := GetResourceAsPointer('sample_wav', 'wave', size);

    Memo1.Lines.Text := GetResourceAsString('sample_txt', 'text');

  end;

Uma vez que nós temos o recurso wave carregado na memória, nós podemos tocá-lo quantas vezes quisermos usando o API sndPlaySound declarado na unidade MMSystem:

procedure TForm1.Button1Click(Sender: TObject);

  begin

    sndPlaySound(sample_wav, SND_MEMORY or SND_NODEFAULT or SND_ASYNC);

  end;

Há alguns recursos (como fontes e cursores animados) que não podem ser usados da memória. Nós, necessariamente, temos de salvar estes recursos em um arquivos de disco temporário e carregá-los de lá. As seguintes funções salvam um recurso para um arquivo:

procedure SaveResourceAsFile(const ResName: string; ResType: pchar;

    const FileName: string);

  begin

    with TResourceStream.Create(hInstance, ResName, ResType) do

      try

        SaveToFile(FileName);

      finally

        Free;

      end;

  end;

As seguintes funções fazem uso das anteriores para salvar um recurso em um arquivo temporário:

function SaveResourceAsTempFile(const ResName: string;

    ResType: pchar): string;

  begin

    Result := CreateTempFile;

    SaveResourceAsFile(ResName, ResType, Result);

  end;

A discussão da função CreateTempFile vai além do escopo desse artigo e sua implementação pode ser vista no exemplo anexado a newsletter.

A seguinte função faz uso do SaveResourceAsTempFile para salvar um cursor animado para um arquivo de recurso, então ela carrega o cursor de um arquivo com LoadImage e finalmente deleta o arquivo temporário. A função retorna o ‘handle’ retornado pelo LoadImage:

function GetResourceAsAniCursor(const ResName: string): HCursor;

  var

    CursorFile: string;

  begin

    CursorFile := SaveResourceAsTempFile(ResName, 'ANICURSOR');

    Result := LoadImage(0, PChar(CursorFile), IMAGE_CURSOR, 0,

                        0, LR_DEFAULTSIZE or LR_LOADFROMFILE);

    DeleteFile(CursorFile);


    if Result = 0 then

      raise Exception.Create(SysErrorMessage(GetLastError));

  end;

Chamadas de exemplo:
Screen.Cursors[1] := GetResourceAsAniCursor('sample_ani');

  Form1.Cursor := 1;

É isso. Espero que você ache isso útil. Você pode encontrar mais informações sobre arquivos de recursos na Biblioteca MSDN.

http://msdn.microsoft.com/library/en-us/winui/hh/winui/rc_6cs3.asp

Você pode encontrar o código fonte completo deste artigo no arquivo que acompanha Pascal Newsletter #25.