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.aspVocê pode encontrar o código fonte completo deste artigo no arquivo que acompanha
Pascal Newsletter #25.