Visual Basic em Português

Página pessoal de Jorge Paulino sobre o Visual Basic (VB.NET, ASP.NET, VB6, VBA) e algumas noticias de tecnologia

VB.NET: Actualizações Automáticas da Aplicação

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!

8 comentários:

celestinoxp disse...

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

pbreda disse...

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....

Jorge Paulino disse...

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

Sérgio Oliveira disse...

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

Jorge Paulino disse...

Sérgio, não entendi o que queres! Qual é a dúvida?

Sérgio Oliveira disse...

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

Anónimo disse...

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

Frankelin Silva disse...

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 ?

Mensagens Recentes



Microsoft Office Especialist

Membro da Comunidade
Experts-Exchange


Administ. da Comunidade
Portugal-a-Programar



Twitter

Artigos no CodeProject

Artigos no CodeProject

Subscrever Novidades

Endereço de Email:

Delivered by FeedBurner

Seguidores

Histórico