Atualização do sistema automática

Foto de Anderson

Como implementar uma rotina para baixar uma atualização do seu sistema se ele está aberto e você não consegue renomear ou apagar ele enquanto aberto?

A maneira mais prática é você criar um atalho para um arquivo de lote (.bat) ao invés de apontar diretamente para o seu sistema. O nome do arquivo de lotes sempre será o mesmo, enquanto que, os arquivos executáveis terão um novo nome a cada versão.

Por exemplo, seu sistema chama-se SISTEMA001.EXE, então você cria um arquivo de lotes chamado SISTEMA.BAT (o nome do arquivo de lotes precisa ser diferente do nome seu sistema para não dar conflito) e dentro dele você chama SISTEMA001.EXE. Daí, você vai criar uma rotina para baixar um novo arquivo de lotes chamando a nova versão do seu sistema, seriam 2 arquivos SISTEMA.BAT e SISTEMA002.EXE. Visto que os usuários estarão executando o SISTEMA001.EXE não haverá problemas de parar a empresa para fazer a atualização.

CLS
@ECHO OFF
ECHO. Sistema v002
ECHO. Carregando...
SISTEMA002.EXE

Neste caso os usuários estão executanto SISTEMA001.EXE e você baixou os arquivos SISTEMA.BAT e SISTEMA002.EXE. Na próxima vez que algum usuário entrar no sistema chamando SISTEMA.BAT já vai chamar a nova versão SISTEMA002.EXE.

EXE de upgrade via BAT2EXE 

Agora vamos supor que já exista diversos atalhos para SISTEMA001.EXE e você não quer mudar. Além disso, você quer o ícone do sistema.

Existe uma ferramenta chamada BAT2EXE, eu tenho e vou disponibilizar aqui, mas só roda em 16bits como o Clipper.

Existem outros na internet, mas não funcionam como desejado. Tem um muito especial https://battoexeconverter.com/, mas muito caro para nós brasileiros por conta do preço do dólar.

EXE de upgrade via o próprio Clipper, Harbour ou xharbour

Bem, o arquivo fica muito grande, não menos que 300Kb já compactado com o UPX mesmo que você tire as libs rdd do arquivo .bc do hbmake.

Além disso, se você chamar o sistema com o comando RUN ele fica esperando na memória e não surte o efeito desejado porque não vai funcionar o upgrade, pois o arquivo ainda constará como aberto e dará acesso negado.

EXE de upgrade via Linguagem C++

Ora, é só um código pra chamar outro programa! Seria difícil? Como compilar? Certamente o arquivo gerado seria menor...

Sim, meu arquivo deu 50Kb e baixou para 25Kb com o UPX.

Tu acredita que podes compilar o programa com o próprio BCC que tu já usas para compilar via xHarbour?

Vamos criar um arquivo chamado sistema.cpp contendo o nosso código em Linguagem C++:

#include <stdio.h>
#include <process.h>

int main(void)
{
  
  puts("Sistema v002");
  puts("Carregando...");


  spawnl( P_OVERLAY, "sistema002.exe",
                     "sistema002.exe", "Using spawnl", "Arg1", "Arg2", NULL );
    
  return 0;
}

Existem vários exemplos na web para chamar um executável dentro de um programa em C++, mas nosso caso é específico: tem que chamar o sistema e sair da memória. Este exemplo acima é o que funciona para nós.

Voltando para o nosso caso, estamos rodando o sistema001.exe que detectou uma nova versão e vai baixar um zip contendo sistema.exe e sistema002.exe. Todos os links apontam para sistema.exe. A cada nova versão você vai dar um novo nome ao seu sistema e compilar sistema.cpp chamando esse novo nome.

Para compilar basta executar:

bcc32 sistema.cpp

Depois baixe mais ainda o tamanho do arquivo assim:

upx -9 sistema.exe

Agora só falta incluir um arquivo de ícone ao EXE!

Colocando um ícone dentro do EXE feito em C++

Para inserir um ícone no .exe você precisa compilar um arquivo de script de recurso (.rc) contendo o nome do ícone, é um arquivo de texto. Por exemplo, SISTEMA.RC e seria assim:

ICO_LOGO ICON "SISTEMA.ICO"

Daí você precisa compilar SISTEMA.RC (que é um arquivo de texto) para um arquivo de recurso (.RES) que é um arquivo binário do tipo objeto para imagens, assim:

brcc32 sistema.rc

O comando acima vai resulta num arquivo de recurso chamado SISTEMA.RES. Depois disso o arquivo de recurso pode ser incluído no arquivo executável SISTEMA.EXE.

Agora é diferente, precisa linkar os objetos SISTEMA.OBJ com SISTEMA.RES com o ilink32. Infelizmente não era tão simples como parecia: BRC32 -foSISTEMA.RES -feSISTEMA.EXE

Quando você chama ilink32 temos o seguinte:

C:\SISTEMA>ilink32
Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland
Syntax: ILINK32 objfiles, exefile, mapfile, libfiles, deffile, resfiles
@xxxx indicates use response file xxxx
General Options:                        -Af:nnnn Specify file alignment
  -C       Clear state before linking   -Ao:nnnn Specify object alignment
  -wxxx    Warning control              -ax      Specify application type
  -Enn     Max number of errors         -b:xxxx  Specify image base addr
  -r       Verbose linking              -Txx     Specify output file type
  -q       Supress banner               -H:xxxx  Specify heap reserve size
  -c       Case sensitive linking       -Hc:xxxx Specify heap commit size
  -v       Full debug information       -S:xxxx  Specify stack reserve size
  -Gn      No state files               -Sc:xxxx Specify stack commit size
  -Gi      Generate import library      -Vd.d    Specify Windows version
  -GD      Generate .DRC file           -Dstring Set image description
Map File Control:                       -Vd.d    Specify subsystem version
  -M       Map with mangled names       -Ud.d    Specify image user version
  -m       Map file with publics        -GC      Specify image comment string
  -s       Detailed segment map         -GF      Set image flags
  -x       No map                       -Gl      Static package
Paths:                                  -Gpd     Design time only package
  -I       Intermediate output dir      -Gpr     Runtime only package
  -L       Specify library search paths -GS      Set section flags
  -j       Specify object search paths  -Gt      Fast TLS
Image Control:                          -Gz      Do image checksum
  -d       Delay load a .DLL            -Rr      Replace resources

Agora me diga: Como é que você iria imaginar que teria que fazer assim: 

ilink32 /aa /Tpe c0x32 sistema,sistema,,import32 cw32mt,,sistema.res

Complicado, né? Mas, vejamos: 

/aa = 32 bit Windows application
/Tpe = output é um arquivo executável
c0x32.obj = código de arranque (startup) para programas em modo console (texto)
import32.lib = a biblioteca contendo referências para itens que o Windows fornece
cw32.lib = é a biblioteca de tempo de execução (runtime) do compilador

Sendo que você já deve ter compilado antes com o 'BCC32 SISTEMA' para que tenha sido gerado o SISTEMA.OBJ como também o 'BRCC32 SISTEMA.RC' para ter o SISTEMA.RES.

Consulte a lista completa de obj e lib da linguagem C++ aqui.

Estas informações de linkar o ícone eu pesquisei na internet, mas se você olhar para dentro do arquivo .BC gerado pelo hbmake do xharbour você verá algo semelhante, vejamos um trecho:

#BCC
LINKER = ilink32

ALLOBJ = c0x32.obj $(OBJFILES) $(OBJCFILES)
ALLRES = $(RESDEPEN)
ALLLIB = $(USERLIBS) $(LIBFILES) import32.lib cw32.lib
 
#COMMANDS
.cpp.obj:
$(CC_DIR)\BIN\bcc32 $(CFLAG1) $(CFLAG2) -o$* $**
 
.c.obj:
$(CC_DIR)\BIN\bcc32 -I$(HB_DIR)\include $(CFLAG1) $(CFLAG2) -o$* $**
 
.prg.obj:
$(HB_DIR)\bin\harbour -D__EXPORT__ -n -go -I$(HB_DIR)\include $(HARBOURFLAGS) -o$* $**
 
.rc.res:
$(CC_DIR)\BIN\brcc32 $(RFLAGS) $<
 
#BUILD
 
$(PROJECT): $(CFILES) $(OBJFILES) $(RESDEPEN) $(DEFFILE)
    $(CC_DIR)\BIN\$(LINKER) @&&!  
    $(LFLAGS) +
    $(ALLOBJ), +
    $(PROJECT),, +
    $(ALLLIB), +
    $(DEFFILE), +
    $(ALLRES) 
!

Observa-se que o xharbour compila aquele tal c0x32.obj da linguagem C++ na variável ALLOBJ na linha nº 4 e na variável ALLLIB, linha nº6, temos as libs da linguagem C++ compiladas juntas com as LIBs do xharbour que são: import32.lib e cw32.lib. Na linha nº24 [em conjunto com a linha nº2] observamos a chamada do ilink32 e a ordem de seus parâmetros.

Arquivo de lote para compilar o programa em C++ com o ícone

Vamos poupar o trabalho e criar um arquivo de lotes para compilar o sistema.exe automaticamente. Vamos chamá-lo de comp.bat. Vejamos como ficaria:

bcc32 %1.cpp
brcc32 %1.rc
ilink32 /aa /Tpe c0x32 %1,%1,,import32 cw32,,%1.res
upx -9 %1.exe

%1 = primeiro parâmetro. Irá receber o nome do programa que será compilado pressupondo que todos os arquivos possuam o mesmo nome para poder funcionar. Exemplo: sistema.cpp; sistema.rc; sistema.res; que irá gerar o sistema.exe.

Linha 1: Compila o programa em C++, transforma .cpp em .obj
Linha 2: Compila o arquivo de script de recurso (.rc) que contém o ícone em um arquivo de recurso (.res)
Linha 3: Linka o arquivo OBJ com o RES transformando-os em um arquivo executável com ícone (.exe)
Linha 4: Compacta o arquivo executável no nível máximo (nº 9)

Para compilar o sistema.exe basta agora chamar "comp sistema":

C:\SISTEMA>comp sistema

Total votes: 0

Comentários

Show de bola

Comentário: 

 Não sabia dessa função em C++ . Ficou muito bem explicado esse seu texto.

Páginas