Muito
tempo se passou desde a primeira versão do
install personalizado. A internet virou um sucesso,
já estamos na versão 8
do Delphi, as políticas do governo... digo,
algumas coisas mudaram. Mas a necessidade de um bom
instalador não.
Portanto,
chegou a hora de um update. Usando as mais modernas
(e as nem tão modernas) técnicas de
programação, vamos criar uma nova versão
do install personalizado da TILT.
Agora ele vêm com código fonte completo,
afinado para as novas necessiadades de distribuição
que a internet impõe aos softwares em geral.
Trabalhos
Iniciais
Quais
os objetivos do novo instalador? Em primeiro lugar,
reduzir o tamanho dos arquivos que serão distribuídos
e em segundo lugar reduzir o número de volumes
utilizados para transferir o programa (ou seja, a
quantidade de arquivos que precisarão ser enviados
juntos).
Este
segundo objetivo é um claro ajuste aos novos
problemas que a internet traz na distribuição
de conteúdo: é melhor fazer o download
de apenas um arquivo (mesmo que seja um pouco maior
do que o estritamente necessário) do que obrigar
o usuário a "caçar" diversos
pequenos componentes de uma aplicação.
Portanto,
o sucesso será obtido construindo um programa
instalador que inclua todos os arquivos necessários
para sua execução (contando os arquivos
do programa que será instalado) e que possa
ser distribuído sozinho, sem a necessidade
de qualquer outro utilitário ou biblioteca
externa.
Mas
como fazer?
O Delphi
é um grande amigo nessas horas de dificuldade.
Na verdade, o Windows também é um grande
amigo nessas horas de dificultade, não importando
a má fama que muitas pessoas insistem em lhe
atribuir.
Todo
programa Windows contém uma área dentro
do seu executável que guarda uma série
de arquivos de recurso (resource files) que contém
desde os ícones que o programa usa até
sons, informação de menus, imagens,
etc.
De maneira
geral, o Delphi gerencia esses arquivos automaticamente.
É por causa desses arquivos que quando uma
imagem é colocada em um TImage
e o projeto é compilado, o arquivo original
pode até ser deletado que a imagem dentro do
programa não será perdida: ela estará
dentro de um recurso nessa área específica
do executável.
Com esse
conhecimento, a idéia mais simples, fácil
e rápida de se criar o instalador seria a de
inserir um resource file dentro do projeto Delphi
que contenha todos os arquivos que devem ser transportados.
Moleza, certo?
Bem,
nem tanto. O problema é que esses arquivos
não executam qualquer tipo de compressão.
E essa é uma das razões pelas quais
um formulário com imagens gera um programa
tão grande: elas foram salvas em arquivos não
comprimidos.
A solução
para esse dilema fica clara examinando o artigo Trocando
de Peles aqui mesmo da TILT:
compactar todos os arquivos da aplicação
e então colocar esse pacote dentro do resource
file.
Agora
sim, essa parece a solução ideal: a
compactação gera um pacote reduzido
que diminuirá o espaço total gasto pelo
instalador, e colocando-o dentro do executável
é possível criar um único volume
que pode ser distribuído sozinho - e melhor
de tudo, que pode ser customizado como qualquer programa
ou jogo criado no Delphi.
Criando
o arquivo de Recursos
Os resource
files (extensão .res) são criados a
partir de arquivos de script (extensão .rc)
com o auxílio de compiladores especiais. Como
a Borland é camarada, o Delphi
já vêm com um compilador chamado criativamente
de Borland Resource
Compiler. Se a instalação
foi feita corretamente, o compilador pode ser executado
simplesmente digitando-se brc32 no prompt de comando.
Para
simplificar as coisas, criamos um arquivo de lotes
que invoca o compilador para um pacote zip chamado
de "arquivos.zip" que deve
conter todos os arquivos necessários para a
execução do programa que será
instalado. Portanto, para modificar o instalador (além
é claro de colocar suas próprias imagens)
tudo o que precisará ser feito é atualizar
esse pacote, rodar o bat e recompilar o projeto.
Mas apenas
gerar o resource file não é o suficiente:
é preciso incluí-lo na aplicação.
Isso é feito através da diretiva {$RESOURCE
arquivos.res} (ou {$R arquivos.res}), que deve ser
incluída logo após a declaração
dos recursos do próprio formulário (a
sempre presente {$R *.dfm}).
Inserir
é simples o suficiente, mas como extrair os
recursos? Para isso é preciso criar um objeto
da classe TResourceStream
que indique qual o nome, tipo e local do recurso que
se deseja pegar. Colocando essa parte do código
em um procedimento à parte, ele fica:
procedure TForm1.lerZipDoResource;
var
str: TResourceStream;
begin
//arquivo zip
str:= TResourceStream.Create(hInstance, 'arquivos',
RT_RCDATA);
str.SaveToFile(appdir + '~arquivos.zip');
str.free;
end;
|
A variável hInstance
indica que o recurso deve ser pêgo do próprio
programa, arquivos é o identificador do recurso
(que é escolhido no script que constrói
o resource file) e RT_RCDATA é o tipo do recurso
desejado (tipo binário).
Com o
arquivo zip retirado do executável e salvo
disco rígido, agora ficou até sem graça
o resto do programa. Ele usa os mesmos conceitos do
artigo sobre skins: abrir o arquivo zip, ler o conteúdo
e fechá-lo. O trecho mais importante desse
código é o seguinte:
//pegar o nome de todos os arquivos do zip
arqs.Text:= zipdllListarArqs;
//extrair arquivos
for i:= 0 to arqs.Count -1 do begin
//se for um diretório (e não arquivo) pular
if arqs[i][length(arqs[i])] = '\' then begin
progbar.Position:= progbar.position + 1;
continue;
end;
//arquivo final
arq:= destDir + arqs[i];
//força a criação da árvore até o arquivo
ForceDirectories(extractFilePath(arq));
//ler para o stream, salvar e limpar stream
zipLerParaStream(arqs[i], str);
str.SaveToFile(arq);
str.clear;
end;
|
A primeira tarefa feita
é pegar o nome de todos os arquivos dentro
do pacote zip e colocá-los
em um TStringList
(arqs). Após isto, cada arquivo do pacote será
lido para um TMemoryStream
e logo em seguida salvo para o diretório desejado
(incluindo subpastas). Pronto, está feito o
instalador.
Ou quase.
Existe um pequenino problema que talvez tenha passado
desapercebido. A manipulação de arquivos
zip requer o uso da biblioteca dinâmica zipdll,
que precisa estar no mesmo diretório do instalador
ou no diretório system do windows.
Mas a
proposta inicial havia sido a de criar um instalador
completo, que pudesse ser distribuído sem qualquer
vínculo externo, portanto o que fazer?
Simples.
Incluir também a dll dentro do executável,
do mesmo modo que o pacote zip foi incluso. A única
questão é que será preciso uma
pequena modificação do arquivo zipdllimport.pas,
que precisa ter o carregamento automático da
biblioteca desligada.
Por que?
Porque as dlls podem ser ligadas ao executável
de duas maneiras: estaticamente ou dinamicamente.
Quando elas são ligadas de maneira estática,
assim que o programa é iniciado elas são
carregadas para a memória e as funções
ficam disponíveis ao programador. No entanto,
isso requer que o arquivo da biblioteca esteja disponível
logo após o programa ter sido iniciado, o que
não acontece nesse caso.
Nesse
projeto é preciso retirar a dll de dentro do
executável antes que seja possível carregá-la.
Portanto é preciso fazer um carregamento dinâmico
dela: o que significa chamar o procedimento zipInitDll
depois que ela for extraída para o sistema.
Agora
sim o programa está completo. Ele pode ser
distribuído sozinho, e é completamente
customizável às necessidades de cada
projeto. Por exemplo, ele poderia checar as configurações
do usuário e fazer o download de componentes
extras de um site, poderia exibir uma tela de registro
ou imagens da aplicação sendo instalada.
O código
fonte desse artigo está disponível para
download, usando é claro o próprio instalador
para copiar os arquivos. Experimente, mude ajuste-o
à sua própria maneira, e boa programação.