As actualizações nos programas são frequentes e obrigam muitas as vezes a um trabalho moroso na actualização dos clientes finais (os utilizadores). Este processo pode e deve ser automatizado efectuando uma actualização directa de um servidor ou via Internet.
Um dos métodos aconselhados para fazer a distribuição e actualização das aplicações é o ClickOnce da Microsoft (mais informações em ClickOnce Deployment).
No entanto muitos programadores preferem não utilizar o ClickOnce por diversos motivos, com por exemplo, apenas permite fazer a actualização do executável, não permite indicar o local de instalação, não cria automaticamente os atalhos, etc.
Mas é possível criar o nosso próprio sistema de actualização da aplicação apenas com um ficheiro. É verdade que não é possível apagar um ficheiro quando este está a ser utilizado mas é possível renomeá-lo. Assim o sistema é simples:
1 - Verificar se existem actualizações
2 - Descarregar o ficheiro de actualização
3 - Renomear o executável para um nome diferente
4 - Renomear o ficheiro de actualização para o nome do executável
5 - Reiniciar a aplicação
É claro que são necessárias mais algumas validações pelo meio mas isto é o essencial!
É possível ler a versão directamente no ficheiro mas se o mesmo for grande então existe um grande tempo de espera para a verificação. Daí a utilizações de um ficheiro de actualização auxiliar (formato txt pela sua simplicidade).
Estrutura do ficheiro txt:
Linha 1 - Versão do ficheiro de actualização
Linha 2 - Ficheiro de actualização com a extensão .update
Linha 3 e restantes - Ficheiros a actualizar
Exemplo:
1.1.0.0
ftp://74.82.141.111/private/exemplo.exe.update
ftp://74.82.141.111/private/exemplo.dll
ftp://74.82.141.111/private/exemplo.xml
Vamos agora ver o código:
Imports System.IO
Imports System.Net
' ------------------------------------------------------
' Informação a alterar
' ------------------------------------------------------
Private updateServer As String = "74.82.141.111"
Private updateFileName As String = "ftp://74.82.141.111/private/demo_update.txt"
Private updateUserName As String = "username"
Private updatePassword As String = "password"
Private msgboxTitle As String = "Actualização da Aplicação"
Private connTimeout As Integer = 8000
' ------------------------------------------------------
' Constantes
Private Const delExtension As String = ".delete"
Private Const uptExtension As String = ".update"
' Variáveis
Private MyWebClient As New WebClient
Private txtInfo As String
Private txtInfoArray() As String
Private appFullName As String
Private appDirectory As String
Private appName As String
''' <summary>
''' Formatação da versão do ficheiro
''' </summary>
''' <param name="Version">String com a versão a formatar</param>
Private Function GetVersion(ByVal
Version As String) As String
Dim x()
As String = Split(Version, ".")
Return String.Format("{0:00000}{1:00000}{2:00000}{3:00000}",
Int(x(0)), Int(x(1)), Int(x(2)), Int(x(3)))
End Function
''' <summary>
''' Apaga ficheiros antigos (caso existam)
''' </summary>
''' <param name="FileName">Nome
do ficheiro</param>
Private Sub DeleteFile(ByVal
FileName As String)
Try
Dim
sFile As String = Dir(FileName)
Do While
sFile <> ""
Try
File.Delete(sFile)
Catch
ex As Exception
End
Try
sFile = Dir()
Loop
Catch
ex As Exception
' ignora o erro
End Try
End Sub
''' <summary>
''' Inicia a verificação/update do ficheiro caso esteja disponível
''' </summary>
Public Sub CheckUpdate()
' Informação da aplicação
appFullName = Application.ExecutablePath.ToString
appDirectory = Application.StartupPath.ToString + "\"
appName = Application.ProductName.ToString
' Elimina os ficheiros antigos
Call DeleteFile(appFullName + delExtension)
' Apaga updates antigos
Call DeleteFile(appFullName + uptExtension)
Try
' Verifica a existência do servidor onde está o ficheiro txt
If Not My.Computer.Network.Ping(updateServer)
Then Exit Sub
' Descarrega o ficheiro TXT para uma variável
Dim networkCredentials
As New Net.NetworkCredential()
With networkCredentials
.UserName = updateUserName
.Password = updatePassword
End With
MyWebClient.Credentials = networkCredentials
txtInfo = MyWebClient.DownloadString(updateFileName.ToString)
' Separa a variável em linhas
txtInfoArray = txtInfo.Split(vbNewLine)
' Verifica a versão do ficheiros (original e update)
Dim fInfo As FileVersionInfo = FileVersionInfo.GetVersionInfo(appFullName)
Dim appVersion
As String = GetVersion(fInfo.FileMajorPart + "." + fInfo.FileMinorPart + "." + fInfo.FileBuildPart + "." + fInfo.FilePrivatePart)
Dim UpdateVersion
As String = GetVersion(txtInfoArray(0))
' Verifica se é necessário fazer a actualização
Dim UpgradeRequired
As Boolean = UpdateVersion > appVersion
' Caso seja necessário actualizar
If UpgradeRequired
Then
' Confirma a intenção de actualizara aplicação
Dim msgStart
As String = "Existe uma nova actualização do programa." + vbCrLf + vbCrLf +
"Deseja efectuar a actualização agora ?"
Dim
resultStart As DialogResult = MessageBox.Show(msgStart, msgboxTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation)
If
resultStart <> Forms.DialogResult.Yes Then
Exit Sub
End If
Application.DoEvents()
' Descarrega o ficheiro principal
Dim updateName
As String = txtInfoArray(1).Substring(txtInfoArray(1).LastIndexOf("/") + 1)
My.Computer.Network.DownloadFile(txtInfoArray(1).ToString,
appDirectory + updateName, _
updateUserName,
updatePassword, False, connTimeout,
True)
' Caso existam mais ficheiros
If
txtInfoArray.Length - 1 >= 2 Then
' Descarrega o(s) ficheiro(s) que estão na lista
For x As Byte = 2 To txtInfoArray.Length - 1
Try
' Caso a linha não esteja em branco
If Not String.IsNullOrEmpty(txtInfoArray(x).Trim)
Then
' Nome e localização dos ficheiro
Dim updateFile
As String = txtInfoArray(x).Trim
Dim updateFiles
As String = txtInfoArray(x).Substring(txtInfoArray(x).LastIndexOf("/") + 1)
' Inicia o Download do ficheiro
My.Computer.Network.DownloadFile(updateFile,
appDirectory + updateFiles, _
updateUserName, updatePassword, False, connTimeout,
True)
End If
Catch
ex As Exception
' Ignora os erro ...
End Try
Next
End If
' Verifica se está disponível o novo ficheiro
If File.Exists(appDirectory + updateName) Then
' Renomeia o principal e depois o ficheiro a actualizar
With My.Computer.FileSystem
.RenameFile(appFullName, appName + ".exe" + delExtension)
.RenameFile(appDirectory + updateName, appName + ".exe")
End
With
' Mensagem final de actualização
Dim
msgFinish As String =
"Terminou a actualização da aplicação." + vbCrLf + vbCrLf +
"Deseja reiniciar o programa agora ?"
Dim
resultFinish As DialogResult = MessageBox.Show(msgFinish, msgboxTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Information)
If
resultFinish = MsgBoxResult.Yes Then
Application.DoEvents()
Application.Restart()
End If
End If
End If
Catch ex As
Exception
MessageBox.Show("Ocorreu
um erro na actualização do ficheiro. Mensagem original: " + ex.Message, msgboxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub
PS: Como sempre, qualquer dúvida, comentário ou correcção ao artigo é sempre bem vinda!
Subscrever:
Enviar feedback (Atom)
8 comentários:
ola,
em primeiro lugar gostava de dar os parabens pelo excelente trabalho que tem sido feito neste blog.
Será possivel disponibilizares um código para fazer uma aplicação relacionada com o euromilhoes.
O objectivo é ter uma lista de chaves sorteadas e o programa ler essas chaves e criar chaves que ainda não tenham sido sorteadas, além disso, verificar se uma determinada lista contem algum premio em relação a uma chave inserida....
Se kiseres tb posso ajudar a divulgar o teu trabalho no meu blog http://celestinoxp.blogspot.com
boas, felicito pelo trabalho que apresentas que é bom....eu usei o teu updater mas eu reparei que se tornava demoroso e tomei a liberdade que acrescentar umas pequenas coisas...como uma form, com progressbar, indicadores de velocidade, tamanho, etc...posso e acho que devo, ceder o código fonte já que fizeste o mesmo por mim e por muitos outros....se assim o pretenderes manda-me um pm no p@p, o meu utilizador é o pbreda..
Cumprimentos....
Olá pbreda!
Acho que deves mostrar o teu código e com isso estás a ajudar os outros.
Coloca na wiki do p@p ... parece-me que é um local adequado ;)
Um abraço
Jorge Paulino
Olá pbreda,
Podias deixar o teu código no p@p para verificar como utilizas-te algumas das funcionalidades que referiste?
Abraço,
Sérgio Oliveira
Sérgio, não entendi o que queres! Qual é a dúvida?
Boas,
Eu estava a solicitar o código fonta da pbreda referente à actualização automática do programa.
Com os melhores cumprimentos,
Sérgio Oliveira
Boas tardes, o que me pedem esta no P@P em Armazém de código com o nome de [VB.NET 2005/2008] Actualização automática de aplicações o link é http://www.portugal-a-programar.org/forum/index.php/topic,49899.0.html
Cumprimentos,
Paulo Breda
Eu joguei o código no VB e apareceu uma mensagem de erro no trecho
If resultStart <> Forms.DialogResult.Yes Then
Exit Sub
End If
"Forms"
Como posso corrigir este erro ?
Enviar um comentário