Inno Setup (Parte 7): Melhorando a execução de programas externos
Escrito por Carlos B. Feitoza Filho | |
Categoria: Tutoriais | |
Categoria Pai: Addicted 2 Delphi! | |
Acessos: 12733 |
Se você pensou que não havia forma de ocultar as janelas de console que aparecem quando executamos as aplicações responsáveis por configurar o PostgreSQL você errou mais uma vez ao subestimar o Inno Setup. Eu já disse e canso de repetir: É possível fazer qualquer coisa com o Inno Setup e mesmo quando não é possível, existem formas simples de resolver a grande maioria dos problemas, estendendo o Inno Setup com DLLs. O uso de DLLs com o Inno Setup será abordado posteriormente, hoje vamos nos focar apenas no básico: como executar programas externos com o Inno Setup sem a exibição de telas.
Ocultando a execução de um programa externo
O exemplo que estamos construindo neste tutorial executa 3 comandos na seção run: initdb.exe, pg_ctl.exe e net.exe. Estes comandos são os responsáveis por configurar o PostgreSQL na máquina de destino e funcionam perfeitamente, tal como pudemos ver em partes anteriores deste tutorial.
Os itens da seção Run possuem um flag (runhidden) que, se usado, oculta a janela do programa sendo executado. No nosso caso, ao usar este flag nos 3 comandos que estamos executando, suas janelas de console seriam ocultadas e o usuário apenas veria uma mensagem de status genérica dizendo "Finalizando a instalação..." acima da barra de progresso.
Como você deve estar imaginando, é possível alterar a mensagem de status para cada item da seção run. Para isso, na seção run, execute um duplo clique no item que deseja alterar. A caixa de diálogo Install Run Action será exibida:
Acima podemos ver a caixa de diálogo Install Run Action, onde podemos ver a opção de visibilidade runhidden marcada, de forma que a janela de console não seja exibida. Podemos ver também que o campo Status Message, está preenchido com aquilo que queremos que apareça durante a execução do comando. O efeito final destas configurações pode ser visto na tela de progresso de instalação:
Como se pode observar, quando o instalador executa um dos comandos da seção Run, é exibido o status configurado no campo Status Message correspondente ao comando atualmente sendo executado.
Os itens da seção UnistallRun também possuem o flag runhidden, que deve ser usado para ocultar as janelas de console que aparecem durante a desinstalação, responsáveis por parar o serviço do PostgreSQL e remover este serviço da lista de serviços executáveis do Windows. Ao contrário dos itens da seção Run, na seção UninstallRun, não é possível definir uma mensagem de status, o que eu, particularmente acho ruim, no entanto, como veremos maios adiante, apesar de não existir tal opção, ainda assim é possível definir uma mensagem de status durante a desinstalação.
Eu poderia parar por aqui, já que o objetivo deste artigo já foi alcançado, no entanto, quando eu pensei em falar a respeito da execução de programas externos foi porque eu pretendia, mais para frente neste tutorial, mostrar algo bem mais interessante que pode ser feito ao se executar um programa externo, por isso eu não posso parar por aqui. Como base para próximas partes deste tutorial, eu preciso mostrar para vocês como executar um programa externo usando o Pascal Script.
O comando Exec
As opções dos itens da seção Run são adequadas para a criação rápida de instaladores, no entanto só se consegue partir para coisas mais elaboradas ao se usar o comando por trás da seção Run, trata-se do comando Exec, o qual tem a seguinte assinatura:
function Exec(const Filename
, Params
, WorkingDir: String;
const ShowCmd: Integer;
const Wait: TExecWait;
var ResultCode: Integer): Boolean;
Não pretendo explicar de forma detalhada como esta função funciona, porque fica mais fácil de entendê-la na prática, no script, que será visto mais adiante, no entanto, de forma simplificada, esta função executa o programa definido no argumento Filename, com os parâmetros definidos no argumento Params, usando WorkingDir como diretório de trabalho. A função retorna true em caso de execução bem sucedida, ou false em caso de erro. O argumento ShowCmd pode receber o valor zero (0) para que, ao executar um programa, nenhuma janela seja exibida! Para maiores detalhes a respeito desta função, consulte a ajuda do Inno Setup.
Tchau seção run. Olá comando Exec!
Nada melhor para entender como as coisas funcionam do que pôr a mão na massa! Primeiramente, vamos definir um alias para guardar o AppId do nosso instalador. Isso é muito simples, veja a imagem a seguir:
Acima podemos ver que criamos um alias de nome MyAppId com o valor igual ao AppId que estava configurado na linha 22. Note que ao definir o alias (linha 9), ele NÃO PODE TER a chave inicial duplicada ({{). Perceba que a chave inicial duplicada permanece apenas na linha 22. A chave inicial duplicada é necessária em todas as seções do script, exceto ao se definir aliases, como fizemos aqui. Duplicar a chave inicial também não é necessário dentro do Pascal Script. Caso não tenha ficado claro, para utilizar um alias definido com a diretiva #define, usa-se a notação {#NomeDoAlias}. O efeito disto no script é que no exato local onde {#NomeDoAlias} for colocado, o compilador vai substituir pelo valor do alias sem as aspas.
O próximo passo para realizar a conversão e passar a usar o Pascal Script para executar programas externos é, obviamente, converter os itens das seções Run e UninstallRun de forma que eles sejam executados pelo comando Exec. Atualmente estas duas seções executam os programas de forma perfeita e não houve qualquer esforço adicional para que isso fosse possível. Como veremos a partir daqui, imitar aquilo que estas seções fazem é um pouco mais trabalhoso, mas vai compensar, eu garanto.
A seção Run contém 4 itens, dos quais apenas os 3 últimos precisam ser removidos:
O primeiro item diz respeito a execução do programa principal e precisa ficar. Marque os 3 itens finais desta lista e simplesmente exclua-os. O próximo passo é se livrar dos itens da seção UninstallRun:
Ao contrário da seção Run, todos os itens da seção UninstallRun devem ser removidos. Selecione-os e exclua-os normalmente. Neste momento nós "quebramos" o script, ou seja, o instalador não será mais capaz de configurar o PostgreSQL como era de se esperar.
Agora precisamos, finalmente, definir procedimentos e funções no Pascal Script que vão imitar aquilo que era feito automaticamente nas seções removidas. Inicialmente vamos alterar o procedure PGConfiguration. Simplesmente substitua todo seu código pelo código a seguir:
function PGConfiguration(AParam: String): String;
begin
Result := '';
if not IsUninstaller then
begin
if LowerCase(AParam) = 'username' then
Result := PGUserName
else if LowerCase(AParam) = 'password' then
Result := PGPassword
else if LowerCase(AParam) = 'port' then
Result := PGPort
else if LowerCase(AParam) = 'servicename' then
Result := PGServiceName;
end
else
begin
if LowerCase(AParam) = 'servicename' then
RegQueryStringValue(HKLM
,'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{#MyAppId}_is1'
,'PostgreSQL: ServiceName'
,Result);
end;
end;
Este procedure foi alterado para poder funcionar quando executado por meio do desinstalador. Durante a desinstalação obviamente não temos mais acesso às variáveis criadas e populadas durante a instalação, logo, a fim de podermos obter valores configurados durante a instalação precisamos salvá-los no Registro do Windows para podermos acessá-los quando quisermos. O procedimento de salvamento destas informações será explicado posteriormente neste artigo.
Na linha 5 a função IsUninstaller retornará false quando esta função for chamada a partir do instalador e retornará true, claro, quando o ela estiver sendo executada a partir do desinstalador. O código que é executado durante a instalação está intacto e não será explicado. A novidade está entre as linhas 18 e 22, que só serão executadas se este procedure for executado durante a desinstalação: durante a desinstalação, caso PGConfiguration seja chamado com o parâmetro ServiceName, será feita uma consulta à chave de registro de desinstalação criada pelo instalador.
A função RegQueryStringValue (linha 19) retorna em seu último parâmetro o valor da "variável" de registro de nome PostgreSQL: ServiceName, a qual encontra-se dentro da chave de nome HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{#MyAppId}_is1. Observe que a chave de registro contém uma referência ao alias que criamos anteriormente. Como dissemos, no local onde {#MyAppId} está, será colocado o valor do alias.
A próxima etapa é criar um procedure que realize exatamente aquilo que era feito na seção Run para os 3 itens que removemos. É aqui onde vamos finalmente usar a função Exec:
procedure ConfigurarPostgreSQL;
var
LabelStatus: TNewStaticText;
ResultCode: Integer;
begin
if IsComponentSelected('PostgreSQL') and IsTaskSelected('PGConfig') then
begin
LabelStatus := TNewStaticText(PageFromId(wpInstalling).Surface.Controls[1]);
LabelStatus.Caption := 'Inicializando a estrutra de pastas dentro da pasta "data" do PostgreSQL';
Exec(ExpandConstant('{app}\pg\bin\initdb.exe')
,ExpandConstant('-U "' + PGConfiguration('username') + '" -A password -E utf8 -D "{app}\pg\data" --pwfile="{tmp}\senha.xyz"')
,ExpandConstant('{app}\pg\bin')
,SW_HIDE
,ewWaitUntilTerminated
,ResultCode);
LabelStatus.Caption := 'Registrando o serviço do PostgreSQL';
Exec(ExpandConstant('{app}\pg\bin\pg_ctl.exe')
,ExpandConstant('register -N "' + PGConfiguration('servicename') + '" -U "NT AUTHORITY\NetworkService" -D "{app}\pg\data" -w -o "-p ' + PGConfiguration('port') + '"')
,ExpandConstant('{app}\pg\bin')
,SW_HIDE
,ewWaitUntilTerminated
,ResultCode);
LabelStatus.Caption := 'Iniciando o serviço do PostgreSQL';
Exec(ExpandConstant('{sys}\net.exe')
,'start "' + PGConfiguration('servicename') + '"'
,ExpandConstant('{sys}')
,SW_HIDE
,ewWaitUntilTerminated
,ResultCode);
end;
end;
O procedure ConfigurarPostgreSQL visto acima, deve ser colocado após a função PGConfiguration, que alteramos anteriormente. Na linha 6 podemos ver a utilização das funções IsComponentSelected e IsTaskSelected que precisam retornar true para que o PostgreSQL seja efetivamente configurado. Na linha 8 usamos a função PageFromId com o parâmetro wpInstalling para obtermos a instância da página do instalador que contém a barra de progresso, a página de progresso de instalação. Usamos a propriedade Surface para termos acesso aos controles da página, os quais estão listados na propriedade Controls. Surface.Controls[1] corresponde ao label de status, no qual aparecia aquela mensagem de status que configuramos nos itens da seção Run, lembra? Este label é do tipo TNewStaticText, logo nós realizamos um cast para salvar a referência a este label na variável LabelStatus, para facilitar o acesso e alterar a mensagem de status. A mensagem de status é alterada imediatamente antes de cada operação Exec ser realizada e isso está sendo feito nas linhas 10, 18 e 26.
As linhas 11, 19 e 27 executam os programas externos necessários para configurar efetivamente o PostgreSQL. Nestas linhas usamos a função Exec com os dados que estavam nos itens da seção Run. Observe o código, ele é Pascal simples, mas existem apenas dois pontos que eu preciso explicar. Primeiramente, em strings que contém constantes do Inno Setup, tais como {sys}, {app}, etc é necessário utilizar a função ExpandConstant. Esta função substitui na string passada em seu parâmetro as constantes do Inno Setup pelos seus valores reais. Isso era feito automaticamente dentro da seção Run, mas no Pascal Script precisamos realizar esta operação manualmente. A segunda coisa que precisa ser observada no código acima é que a chamada a função PGConfiguration agora é feita da forma tradicional, concatenando-a com a string, ao contrário do que era feito na seção Run, onde usávamos a forma {code:PGConfiguration|servicename}, por exemplo. Para não haver confusão, sempre que estiver trabalhando no Pascal Script lembre-se de que aquilo é pascal, logo, trabalhe nele como se fosse Pascal.
Se você é um cara esperto e atento, deve agora estar se perguntando: e se ao invés de eu concatenar a função PGConfiguration de forma tradicional como eu faço em Pascal, eu utilizar a função ExpandConstant na string completa, por exemplo, se eu usar ExpandConstant('start {code:PGConfiguration|servicename}'), o que vai acontecer? O que vai acontecer é óbvio: vai funcionar! Você poderia simplificar as strings passadas como parâmetros da função Exec se utilizasse ExpandConstant em todas elas e mantivesse as pseudo constantes {code:...}. Isso tornaria as strings mais legíveis, mas eu optei por usar a concatenação apenas porque eu acho que estando dentro do Pascal Script eu tenho que trabalhar no modo Pascal. Além disso, penso eu que o parser utilizado para executar a string com pseudo constantes {code:...} trabalha mais, e em tese pode haver perda de performance, logo, porque não usar a forma que estamos habituados? Se você quiser usar ExpandConstant em todo lugar, sinta-se à vontade, mas eu particularmente não gosto.
Agora que temos a função responsável por configurar o PostgreSQL, precisamos instruir o Inno Setup a usá-la, para isso, vamos declarar mais uma função de evento especial do Inno Setup:
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssPostInstall then
ConfigurarPostgreSQL;
end;
Declare esta função, exatamente como está mostrado acima, logo abaix do procedure que definimos anteriormente (ConfigurarPostgreSQL). Esta função de evento do Inno Setup é executada em 3 momentos durante a execução do instalador: antes de iniciar a instalação (CurStep = ssInstall), após terminar a instalação (CurStep = ssPostInstall) e ao concluir o instalador após uma instalação bem sucedida (CurStep = ssDone). No nosso caso, como se pode ver no código anterior, estamos detectando se a etapa é ssPostInstall a fim de executar o procedure ConfigurarPostgreSQL.
É necessário explicar agora o que o Inno Setup considera "instalação", já que eu tenho etapas de pré e pós instalação. Para o Inno Setup "instalar" consiste em executar todas as tarefas definidas nas seções do script que não fazem parte do Pascal Script. Isso inclui a cópia e criação de arquivos, criação de diretórios, alterações em arquivos .ini e manipulações no Registro do Windows. Todos os itens colocados na seção Run, são executados APÓS a execução de todas as tarefas definidas nas outras seções do script, logo, APÓS A INSTALAÇÃO, e é por este motivo que verificamos se CurStep = ssPostInstal, porque isso vai garantir que as etapas de configuração do PostgreSQL só sejam executadas após todos os seus arquivos terem sido copiados para a máquina de destino. Tenha sempre isso em mente quando for realizar tarefas programaticamente.
Tchau seção UnistallRun. Olá comando Exec!
Não, isto não é um Dèja-vu. Tudo que for instalado por um instalador precisa ter suporte a desinstalação. Como nós acabamos de definir o código para configurar o PostgreSQL, precisamos incluir código para remover o PostgreSQL.
Durante a desinstalação precisamos saber se o componente "PostgreSQL" foi instalado e se a tarefa "PGConfig" foi executada para podermos realizar as etapas de "desconfiguração" do PostgreSQL. Quando utilizamos a seção UninstallRun e configuramos cada um de seus itens com o componente PostgreSQL e a tarefa PGConfig, o Inno Setup se encarrega de fazer esta verificação automaticamente porque ele inclui no log de desinstalação o código necessário para executar os itens de UninstallRun baseando-se naquilo que foi efetivamente selecionado durante a instalação.
Ao não utilizar a seção UninstallRun, o log de desinstalação não vai incluir o código de desinstalação baseado em nossas escolhas durante a instalação, por isso precisamos de um meio de, durante a desinstalação, saber o que foi instalado e executado durante a instalação. Felizmente o Inno Setup já guarda no Registro do Windows os componentes selecionados e as tarefas executadas durante a instalaçã, precisamos apenas obter estes valores. O código abaixo contém duas funções que devem ser declaradas após o procedure CurStepChanged (explicado anteriormente):
function ComponentWasInstalled(AComponent: String): Boolean;
var
UninstallKey: String;
UninstallValue: String;
Value: String;
begin
Result := False;
AComponent := LowerCase(AComponent);
UninstallKey := 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{#MyAppId}_is1';
UninstallValue := 'Inno Setup: Selected Components';
if RegKeyExists(HKEY_LOCAL_MACHINE, UninstallKey) then
if RegValueExists(HKEY_LOCAL_MACHINE, UninstallKey, UninstallValue) then
if RegQueryStringValue(HKEY_LOCAL_MACHINE, UninstallKey, UninstallValue, Value) then
if Pos(AComponent, Value) > 0 then
Result := True;
end;
function TaskWasPerformed(ATask: String): Boolean;
var
UninstallKey: String;
UninstallValue: String;
Value: String;
begin
Result := False;
ATask := LowerCase(ATask);
UninstallKey := 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{#MyAppId}_is1';
UninstallValue := 'Inno Setup: Selected Tasks';
if RegKeyExists(HKEY_LOCAL_MACHINE, UninstallKey) then
if RegValueExists(HKEY_LOCAL_MACHINE, UninstallKey, UninstallValue) then
if RegQueryStringValue(HKEY_LOCAL_MACHINE, UninstallKey, UninstallValue, Value) then
if Pos(ATask, Value) > 0 then
Result := True;
end;
As duas funções acima são basicamente iguais, mudando apenas qual valor do registro elas lêem, por isso vou explicar ambas ao mesmo tempo. Nas linhas 10, 11, 29 e 30 atribuímos a duas variáveis, respectivamente a chave de registro de desinstalação e o valor que queremos acessar. Note que a variável UninstallKey contém uma referência ao alias MyAppId. O Inno Setup salva no registro do Windows os dados para desinstalação numa chave cujo nome é o AppId + a string "_is1". Já a variável UninstallValue recebe "Inno Setup: Selected Components" ou "Inno Setup: Selected Tasks" dependendo da função executada.
As linhas 13 a 15 e 32 a 34 executam várias funções para acesso ao registro utilizando as variáveis mencionadas anteriormente (Use a ajuda do Inno Setup para saber o que cada função Reg* faz). Já as linhas 16 e 35 executam a verificação da existência do componente ou da tarefa, dentro do valor retornado do registro. Caso haja em uma referência ao componente ou a tarefa a função retorna true, indicando que o componente foi instalado (ComponentWasInstalled) ou que a tarefa foi executada (TaskWasPerformed).
Anteriormente definimos a função ConfigurarPostgreSQL, agora precisamos definir sua contrapartida:
procedure DesconfigurarPostgreSQL;
var
ResultCode: Integer;
OriginalStatus: String;
begin
if ComponentWasInstalled('PostgreSQL') and TaskWasPerformed('PGConfig') then
begin
OriginalStatus := UninstallProgressForm.StatusLabel.Caption;
UninstallProgressForm.StatusLabel.Caption := 'Finalizando o serviço do PostgreSQL';
Exec(ExpandConstant('{sys}\net.exe')
,'stop "' + PGConfiguration('servicename') + '"'
,ExpandConstant('{sys}')
,SW_HIDE
,ewWaitUntilTerminated
,ResultCode);
UninstallProgressForm.StatusLabel.Caption := 'Removendo o serviço do PostgreSQL';
Exec(ExpandConstant('{app}\pg\bin\pg_ctl.exe')
,'unregister -N "' + PGConfiguration('servicename') + '"'
,ExpandConstant('{app}\pg\bin')
,SW_HIDE
,ewWaitUntilTerminated
,ResultCode);
UninstallProgressForm.StatusLabel.Caption := OriginalStatus;
end;
end;
A função DesconfigurarPostgreSQL primeiramente verifica se será necessário realizar a "desconfiguração" do PostgreSQL. Na linha 6 podemos ver o uso das funções ComponentWasInstalled e TaskWasPerformed. Se ambas retornarem true, significa que o PostgreSQL foi instalado e configurado, logo, precisaremos desconfigurá-lo antes de desinstalá-lo. A função DesconfigurarPostgreSQL é executada ANTES da remoção dos arquivos (mais adiante explicarei melhor isso).
Na linha 8 estamos salvando na variável OriginalStatus o valor do texto exibido no label de status da tela de desinstalação do Inno Setup, cuja referência é UninstallProgressForm. Isso é necessário porque ao iniciar a desinstalação, o Inno Setup coloca um texto neste label e como vamos realizar procedimentos ANTES de o Inno poder atuar sozinho, precisamos garantir que ao final de nossos procedimentos o label de status contenha o seu valor originalmente definido pelo Inno Setup. Nas linhas 10 e 18 podemos ver a alteração do label de status sendo feita antes de chamarmos a função Exec nas linhas 11 e 19. As duas chamadas a função Exec, executam os programas externos net.exe e pg_ctl.exe exatamente como estava sendo feito na seção UninstallRun. Não vou explicar os detalhes da execução das funções Exec aqui porque isso já foi feito quando eu expliquei a respeito da função ConfigurarPostgreSQL e o princípio é exatamente o mesmo!
Você deve ter percebido que ao imitarmos o comportamento da seção UninstallRun nós estamos fazendo algo que os itens dessa seção não faziam. Trata-se da definição de mensagens de status para cada programa externo sendo executado durante a desinstalação. Eu não sei ao certo porque não existe esta propriedade para os itens da seção UninstallRun, mas ao usarmos a forma programática, via Pascal Script como pudemos observar, a troca desta mensagem de status pode ser realizada. Considero isso mais uma vantagem desse modo de trabalho, já que ao usarmos apenas a seção UnistallRun, caso o flag runhidden estiver habilitado o usuário verá uma tela estática de progresso sem qualquer indicação do que está sendo feito, levando-o a pensar que o desinstalador travou.
Agora que definimos a função que "desconfigura" o PostgreSQL, claro, precisamos usá-la. Para isso após a declaração da função DesconfigurarPostgreSQL, declare o seguinte procedure:
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if CurUninstallStep = usUninstall then
DesconfigurarPostgreSQL;
end;
O procedure CurUninstallStepChange é a contrapartida do procedure CurStepChanged, e é executado durante a desinstalação em 4 momentos, dos quais apenas os 3 últimos momentos nos interessam: antes de iniciar a desinstalação (CurUninstallStep = usUninstall), após terminar a desinstalação (CurUninstallStep = usPostUninstall) e ao concluir o desinstalador após uma desinstalação bem sucedida (CurUninstallStep = usDone). Como estamos interessados em desconfigurar o PostgreSQL ANTES que a remoção dos seus arquivos seja realizada, precisamos executar a função DesconfigurarPostgreSQL apenas quando CurUninstallStep = usUninstall.
Finalmente, como último passo, precisamos salvar na chave de registro de desinstalação do Inno Setup os dados que serão acessados pelo nosso script durante a desinstalação. No nosso caso, existe apenas uma informação que precisamos acessar durante a desinstalação para desconfigurar corretamente o PostgreSQL, trata-se do nome do serviço, o qual é utilizado pelos programas externos executados em DesconfigurarPostgreSQL, e que são acessados por meio da função PGConfiguration('servicename'). Lá no início deste artigo, alteramos a função PGConfiguration de forma que, ao ser executada durante a desinstalação, a informação do nome do serviço fosse obtida diretamente do registro de desinstalação do Inno Setup. Agora faz sentido não é?
A fim de salvar esta informação no registro, declare no final do script a seguinte função:
function GetCustomSetupExitCode: Integer;
begin
Result := 0;
if IsComponentSelected('PostgreSQL') and IsTaskSelected('PGConfig') then
RegWriteStringValue(HKLM
,'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{#MyAppId}_is1'
,'PostgreSQL: ServiceName'
,PGConfiguration('servicename'));
end;
Esta função de evento só é executada caso a instalação chegue ao fim de forma bem sucedida, quando o código de saída da instalação foi zero. Aqui é um bom local para realizar operações que só devem ser realizadas se a instalação foi bem sucedida. Neste momento a chave de registro de desinstalação já foi criada, logo, aqui é o local ideal para inserirmos valores de registro na chave de registro da instalação atual. Note que, como sempre, verificamos se houve a seleção do componente PostgreSQL e se houve a seleção da tarefa PGConfig antes de escrevermos no registro o valor de nome "PostgreSQL: ServiceName" igual àquilo que foi escolhido na nossa tela personalizada, obtido com a função PGConfiguration('servicename')! O efeito da gravação do valor no registro pode ser visto abaixo:
O Inno Setup possui uma seção chamada Registry, a qual serve para manipular o registro do Windows então porque não usá-la? A resposta é simples: porque os itens da seção Registry são executados durante a instalação, ANTES da chave de registro de desinstalação do Inno Setup ser criada. Mesmo que você inclua um item na seção Registry, que faça menção a chave de registro de desinstalação que ainda não foi criada, esta entrada não será processada. O Inno Setup valida a chave de registro e caso ele detecte que a chave de registro que se quer acessar é a chave de desinstalação, ele simplesmente ignora a execução deste item. É por este motivo que nós criamos a chave de registro via Pascal Script em uma função de evento que só é executada caso a instalação tenha sido bem sucedida, o que indica que a chave de registro de desinstalação já encontra-se criada!
Se você seguiu à risca este artigo e executar agora o instaador, notará que ao selecionar o componente PostgreSQL e selecionar a tarefa de configurá-lo, você não vai mais ver as telas de console, vendo apenas a mensagem de status mudando na tela de progresso de instalação, tal como aconteceu quando você usou o flag runhidden nos itens da seção Run. Ao desinstalar, da mesma forma, nenhuma tela de console aparecerá, apenas as mensagens de status na tela de progresso de desinstalação, tal como pode ser visto abaixo:
Conclusão
Muita gente agora está pensando: "Eu não acredito que esse artigo inteiro gerou um monte de código que eu poderia suprimir se usasse simplesmente as seções Run e UninstallRun. Carlos, você é um estúpido! Eu te odeio!". Calma, jovem padawan, o esforço será recompensado mais adiante! Eu só modifiquei a forma de execução de programas externos para permitir a "exibição gráfica avançada de status de instalação" e é só isso que eu vou dizer. Se ficou curioso, aguarda as próximas partes deste tutorial ;)