Click here to Skip to main content
15,889,335 members
Articles / Programming Languages / XML
Article

Custom Application Auto Update

Rate me:
Please Sign up or sign in to vote.
3.64/5 (10 votes)
22 Jun 2007CPOL2 min read 167.1K   3.5K   115   51
Auto update features for windows application

Introduction

Fixing bugs and adding new features is a part of developing software applications. From my experience, sending application updates to users is also a critical part of developing applications, especially when the user has no advanced knowledge of computers. In the Internet era today, the software developer must make application deployment and updating easier and often makes automatic application updates to do this.

Background

I already searched through the internet on this topic, but not much seems suited to my needs. So, I tried to create one myself. Before starting development, I tried Updater Application Block (UAB) from Microsoft through Brendan Tompkins, Application Auto Update in VB.NET by Eduardo Oliveira and Microsoft Application Blocks - Application Updater, Using the Manifest Utility by Les Smith. My thanks go out to all of them. There are certain features of an Auto Update Application that I need:

  • User must login and specify the URL of the Update Server
  • Application automatic re-run after checking update
  • Update process transparent to the user
  • Easy for developer to upload the update files

How it works

After the user logs in and specifies the Server URL, we must call AutoUpdate.exe with the ProcessStartInfo class and set ProcessStartInfo.Arguments with the required command line string. After ProcessStartInfo starts, we must exit the main application. AutoUpdate.exe will delay several seconds before running, waiting for the main application to close. After that, AutoUpdate.exe will check updates and copy update files from the server to the client computer using the WebClient class based on the Manifest file that we created. At the end of update process, AutoUpdate.exe will re-run the main application.

Using the code

The Auto Update program

The Auto Update program consists of only a form and a module. Form is used for the user interface when Auto Update downloads the update files. Module is filling with sub Main and sub ProcessUpdate.

VB
Imports System.Net
Imports System.xml
Imports System.IO

Module Module1
    Friend myForm As Form1    ' the form interface of update process
    Friend ExeFile As String  ' the main program that called the auto update
    Dim RemoteUri As String   ' the url location of the files
    Dim Key As String         ' the key used by the program when called back 
    ' to know that the program was launched by the 
    ' Auto Update program
    Dim ManifestFile As String  ' the manifest file name
    Dim UserID As String        ' the User ID
    Dim CommandLine As String   ' the command line passed to the original 

    Sub Main()
        Try
            ' Get the parameters sent by the 
            ' application should be separated by "|"
            Dim param() As String = 
                Split(Microsoft.VisualBasic.Command(), "|")
            ExeFile = param(0)
            RemoteUri = param(1)
            ManifestFile = param(2)
            UserID = param(3)
            CommandLine = Microsoft.VisualBasic.Command()
            ' if Parameter omitted then application exit
            If ExeFile = "" Or RemoteUri = "" Or 
                ManifestFile = "" Then Environment.Exit(1)

            myForm = New Form1
            myForm.Label1.Text = 
                "Checking for application update, please wait!..."
            Application.DoEvents()
            Application.Run(myForm)
        Catch ex As Exception
            MsgBox(ex.ToString)
            Application.Exit()
        End Try
    End Sub

    Sub ProcessUpdate()
        Dim myWebClient As New WebClient
        ' Download manifest file
        Try
            ' get the update file content in manifest file
            myForm.Label2.Text = "download manifest..."
            Application.DoEvents()
            myWebClient.DownloadFile(RemoteUri & ManifestFile, ManifestFile)
            myForm.Label2.Text = "download manifest done"
            Application.DoEvents()
        Catch ex As Exception
            MessageBox.Show(ex.ToString)
            Exit Sub
        End Try

        Try
            Dim m_xmld As XmlDocument
            Dim m_nodelist As XmlNodeList
            Dim m_node As XmlNode
            'Create the XML Document
            m_xmld = New XmlDocument
            'Load the Xml file
            m_xmld.Load(Application.StartupPath & "\" & ManifestFile)
            'Get the list of name nodes 
            m_nodelist = m_xmld.SelectNodes("/update/name")

            'Init progressbar
            InitProgress(m_nodelist.Count)

            'Loop through the nodes
            For Each m_node In m_nodelist
                'Get the file Attribute Value
                Dim fileAttribute = 
                    m_node.Attributes.GetNamedItem("file").Value
                'Get the fileName Element Value
                Dim fileNameValue = m_node.ChildNodes.Item(0).InnerText
                'Get the fileVersion Element Value
                Dim fileVersionValue = m_node.ChildNodes.Item(1).InnerText
                'Get the fileLastModified Value
                Dim fileLastModiValue = m_node.ChildNodes.Item(2).InnerText

                'Temp file name
                Dim TempFileName As String = 
                    Application.StartupPath & "\" & 
                    Now.TimeOfDay.TotalMilliseconds
                Dim isToUpgrade As Boolean = False
                Dim RealFileName As String = 
                    Application.StartupPath & "\" & fileNameValue
                Dim LastModified As Date = CDate(fileLastModiValue)

                Dim FileExists As Boolean = File.Exists(RealFileName)
                'If file not exist then download file
                If Not FileExists Then
                    isToUpgrade = True
                ElseIf fileVersionValue <> "" Then
                    'verify the file version
                    Dim fv As FileVersionInfo = 
                        FileVersionInfo.GetVersionInfo(RealFileName)
                    isToUpgrade = 
                        (GetVersion(fileVersionValue) > 
                        GetVersion(fv.FileMajorPart & 
                        "." & fv.FileMinorPart & "." & fv.FileBuildPart & 
                        "." & fv.FilePrivatePart))
                    'check if version not upgrade then check last modified
                    If Not isToUpgrade Then
                        isToUpgrade = 
                            (LastModified > 
                            File.GetLastWriteTimeUtc(RealFileName))
                    End If
                Else
                    'check last modified file
                    isToUpgrade = 
                        (LastModified > 
                        File.GetLastWriteTimeUtc(RealFileName))
                End If

                'Download upgrade file
                If isToUpgrade Then
                    myForm.Label2.Text = 
                        "Update file " & fileNameValue & "..."
                    Application.DoEvents()
                    ' Download file and name it with temporary name
                    myWebClient.DownloadFile(RemoteUri & fileNameValue, 
                        TempFileName)
                    ' Rename temporary file to real file name
                    File.Copy(TempFileName, RealFileName, True)
                    ' Set Last modified 
                    File.SetLastWriteTimeUtc(RealFileName, LastModified)
                    ' Delete temporary file
                    File.Delete(TempFileName)
                End If

                IncrementProgress()
            Next
            'Delete server manifest file
            File.Delete(Application.StartupPath & "\" & ManifestFile)

            myForm.Label1.Text = "Application update complete!"
            Application.DoEvents()

            Dim startInfo As New ProcessStartInfo(Application.StartupPath & 
                "\" & ExeFile)
            startInfo.Arguments = CommandLine
            Process.Start(startInfo)

        Catch ex As Exception
            MessageBox.Show(ex.ToString)
        End Try
    End Sub

Main application

In the main application, we must check if this is first run or a re-run of the application from the Auto Update program. We check this by retrieving the parameter length.

VB
Module Module1
    Public g_login As String
    Public isUpdate As Boolean = False

    Sub Main()
        ' Get the parameters sent by the application
        Dim param() As String = Split(Microsoft.VisualBasic.Command(), "|")
        If param.Length > 1 Then isUpdate = True

        Dim frmLogin As New Form1
        frmLogin.ShowDialog()
    End Sub
End Module

In the login form, when the user clicks the OK button, we must add this code:

VB
Private Sub btnLogin_Click(ByVal sender As System.Object, 
    ByVal e As System.EventArgs) Handles btnLogin.Click
    Dim MainForm As New Form2
    If txtUSER_ID.Text.Trim = "" Then
        MsgBox("Please enter your User ID!", MsgBoxStyle.Information)
        txtUSER_ID.Focus()
        Exit Sub
    ElseIf txtPASS.Text.Trim = "" Then
        MsgBox("Please enter your Password!", MsgBoxStyle.Information)
        txtPASS.Focus()
        Exit Sub
    ElseIf txtSERVER_URL.Text.Trim = "" Then
        MsgBox("Please enter Server URL!", MsgBoxStyle.Information)
        txtSERVER_URL.Focus()
        Exit Sub
    End If

    'Check is valid login
    If txtUSER_ID.Text.Trim = "User" And txtPASS.Text.Trim = "123" Then
        Me.Hide()
        'Check if first run then call auto update
        If Not isUpdate Then
            Dim startInfo As New ProcessStartInfo(Application.StartupPath & 
                "\" & "AutoUpdate.exe")
            Dim cmdLine As String
            cmdLine = "MainApp.exe|" & txtSERVER_URL.Text.Trim & 
                "|ServerManifest.xml|" & txtUSER_ID.Text.Trim
            startInfo.Arguments = cmdLine
            Process.Start(startInfo)
            Environment.Exit(1)
        Else
            MainForm.ShowDialog()
        End If
    Else
        MsgBox("Invalid Password!", MsgBoxStyle.Information)
        txtPASS.Focus()
        Exit Sub
    End If
End Sub

Manifest files utility

This program will create a manifest file that fills with the list of update files in the selected folder we must choose. The manifest file is formatted in XML.

VB
Private Sub Button2_Click(ByVal sender As System.Object, 
    ByVal e As System.EventArgs) Handles Button2.Click
    If txtPath.Text = "" Then
        Exit Sub
    End If

    Try
        xmlDoc.RemoveAll() 'Clears the xmlDoc for multiple process, 
                           ' because xmlDoc is a class level object
        lblStatus.Text = "Readind directory structure..."
        Application.DoEvents()

        xmlDoc.AppendChild(xmlDoc.CreateProcessingInstruction("xml", 
            "version='1.0' encoding='UTF-8'")) 'First Chid: Header
        createRootNode()

        With SaveFileDialog1
            .AddExtension = True
            .FileName = "ServerManifest.xml"
            .DefaultExt = ".xml"
            .Filter = "xml files (*.xml)|*.xml"
            .FilterIndex = 1
            .RestoreDirectory = True

            If .ShowDialog = 
                Forms.DialogResult.OK Then xmlDoc.Save(.FileName)
        End With
        '            xmlDoc.Save("ServerManifest.xml")

        lblStatus.Text = "The XML document of manifest was created."

    Catch ex As Exception
        MessageBox.Show(ex.ToString)
    End Try
End Sub

Private Sub createRootNode()
    Try
        oElmntRoot = xmlDoc.CreateElement("update") 'Second Child: update
        xmlDoc.AppendChild(oElmntRoot) 'Add the element to the xml document

        loopNodes(oElmntRoot, txtPath.Text)

    Catch ex As Exception
        MsgBox(ex.ToString)
    End Try
End Sub

Private Sub loopNodes(ByVal oElmntParent As XmlElement, 
    ByVal strPath As String)
    Dim ofs As New DirectoryInfo(strPath & "\")

    'Files Loop ------------------------------------------------------
    Dim oFile As FileInfo
    For Each oFile In ofs.GetFiles
        lblStatus.Text = "Reading file " & oFile.Name
        Application.DoEvents()

        If oFile.Name <> "ServerManifest.xml" And _
            Not oFile.Name.EndsWith(".pdb") And _
            Not oFile.Name.EndsWith(".config") Then
            Dim oElmntLeaf1 As XmlElement    'Manipulates the files nodes
            Dim oElmntFileName As XmlElement
            Dim oElmntFileVersion As XmlElement
            Dim oElmntFileModified As XmlElement

            oElmntLeaf1 = xmlDoc.CreateElement("name")
            oElmntLeaf1.SetAttribute("file", oFile.Name)
            oElmntParent.AppendChild(oElmntLeaf1)

            oElmntFileName = xmlDoc.CreateElement("filename")
            oElmntFileName.InnerText = oFile.Name
            oElmntLeaf1.AppendChild(oElmntFileName)

            Dim fv As FileVersionInfo = 
                FileVersionInfo.GetVersionInfo(oFile.FullName)
            oElmntFileVersion = xmlDoc.CreateElement("fileversion")
            oElmntFileVersion.InnerText = fv.FileVersion
            oElmntLeaf1.AppendChild(oElmntFileVersion)

            oElmntFileModified = xmlDoc.CreateElement("filelastmodified")
            oElmntFileModified.InnerText = oFile.LastWriteTimeUtc
            oElmntLeaf1.AppendChild(oElmntFileModified)
        End If
    Next
End Sub

History

  • 22 June, 2007 -- Original version posted

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Indonesia Indonesia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionSystem.IndexOutofRangeException [modified] Pin
Troglomite28-Jun-07 7:25
Troglomite28-Jun-07 7:25 
AnswerRe: System.IndexOutofRangeException Pin
GoodID28-Jun-07 17:08
GoodID28-Jun-07 17:08 
AnswerRe: System.IndexOutofRangeException [modified] Pin
Troglomite29-Jun-07 3:13
Troglomite29-Jun-07 3:13 
GeneralRe: System.IndexOutofRangeException Pin
GoodID1-Jul-07 19:28
GoodID1-Jul-07 19:28 
AnswerRe: System.IndexOutofRangeException [modified] Pin
Troglomite2-Jul-07 2:11
Troglomite2-Jul-07 2:11 
GeneralRe: System.IndexOutofRangeException Pin
sowa424-Apr-11 6:45
sowa424-Apr-11 6:45 
GeneralRe: System.IndexOutofRangeException Pin
GoodID4-Apr-11 16:54
GoodID4-Apr-11 16:54 
GeneralClickOnce ! Phooey. This looks much more flexible Pin
robvon27-Jun-07 0:07
robvon27-Jun-07 0:07 
Great work. I've put aside some serious time to play with it. I read the whole book on clickonce and liked very little due to its prescriptive nature.
GeneralGoodOne! Pin
Mahesh Sapre22-Jun-07 19:21
Mahesh Sapre22-Jun-07 19:21 
GeneralClickOnce API Pin
Not Active22-Jun-07 9:11
mentorNot Active22-Jun-07 9:11 
GeneralRe: ClickOnce API Pin
Mahesh Sapre22-Jun-07 19:17
Mahesh Sapre22-Jun-07 19:17 
GeneralRe: ClickOnce API Pin
GoodID24-Jun-07 16:41
GoodID24-Jun-07 16:41 
GeneralRe: ClickOnce API Pin
Boban Stojanovski25-Jun-07 21:45
Boban Stojanovski25-Jun-07 21:45 
GeneralRe: ClickOnce API Pin
Not Active26-Jun-07 1:52
mentorNot Active26-Jun-07 1:52 
GeneralRe: ClickOnce API Pin
bearfx26-Jun-07 6:21
bearfx26-Jun-07 6:21 
GeneralRe: ClickOnce API Pin
Not Active26-Jun-07 7:02
mentorNot Active26-Jun-07 7:02 
GeneralRe: ClickOnce API Pin
scalpa9829-Jun-07 22:48
scalpa9829-Jun-07 22:48 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.