65.9K
CodeProject 正在变化。 阅读更多。
Home

UpdaterApp - 一个易于更新的库

starIconstarIconstarIconstarIconstarIcon

5.00/5 (7投票s)

2019 年 9 月 27 日

CPOL

4分钟阅读

viewsIcon

10337

downloadIcon

355

本文解释了一种下载和更新 WinForms 应用程序的简单方法。

引言

在开发软件时,我们需要自动更新。这使得开发者可以通过一个完全用 VB.NET 开发的开源库来利用自动资源,该库也可以用于 C# 和其他语言。
因此,在本文中,我将介绍一个库(.dll),它基于 AntSoft Systems On Demand (ASUpdater) 库(我获准分发此代码,因为我是其作者和公司的 CEO)。

要求

  • .NET Framework 4.5 或更高版本
  • System.Windows.Forms
  • System.Reflection
  • System.Xml
  • System.Security.Cryptography
  • System.ComponentModel
  • System.Drawing

库代码

模块

该模块具有基本和常用的库功能,以及应用程序信息,例如 PathTitleVersions

在此模块中,我们有将接收应用程序数据的变量以及 UrlExistGotInternetCreateHashPureGetMd5Hash sub MainLib 函数。

  • Public Function UrlExist (ByVal sUrl As String):检查 URL 是否存在并返回一个布尔值。您还必须输入要下载的文件的路径。
  • GotInternet():检查计算机是否已连接到网络。该函数返回一个布尔值。
  • CreateHashPure(ByVal sString As String, Optional iSize As Integer = 32):创建 MD5 哈希。
    • sString。输入您要用 MD5 加密的变量。
    • iSize:输入您希望返回的 MD5 加密大小,最大大小为 32。

    该函数返回一个 String 响应。

  • GetMd5Hash(ByVal md5Hash As MD5, ByVal input As String):该函数返回一个 String 响应。
  • MainLib()。在启动时加载应用程序信息。

在模块 mMain 中,我们有以下代码

Imports System.Windows.Forms
Imports System.Net
Imports System.Xml
Imports System.Text
Imports System.Text.RegularExpressions
Imports System.Security.Cryptography
Imports System.ComponentModel
Imports System.Drawing
Module mMain
    Public sPath As String 'Application Path 
    Public sTitle As String 'Application Title
    Public sVerActual As String 'Actual Application Major Version with format 1
    Public sVerActualSimp As String 'Actual Application Version with simple format 1.0
    'Sets the Update Version to the Application version, 
    'but in the future, the version will receive information from the configuration file, 
    'which is on the server hosting the new version installation file.
    Public sVerUpdate As FileVersionInfo = _
           FileVersionInfo.GetVersionInfo(Application.ExecutablePath)
    Public sVersion As String
    Public PicUpdateImg As System.Drawing.Image
    Public PicAboutImg As System.Drawing.Image
    Public LibUpdate As New Updater

    Public Sub MainLib()
        'Check if Application path is Root Drive e has or not
        If Application.StartupPath.EndsWith("\") Then
            sPath = Application.StartupPath
        Else
            sPath = Application.StartupPath & "\"
        End If
        'Load to PicUpdateImg (Image Object) the resource image file
        PicUpdateImg = My.Resources.ASSUpdater
        'Load to PicAboutImg (Image Object) the resource image file
        PicAboutImg = My.Resources.ASSUpdaterAbout
        'Load the necessary info to run this application
        With My.Application.Info
            sTitle = .ProductName.ToString & " v" & .Version.Major & "." & .Version.Minor
            sVerActual = .Version.Major.ToString
            sVerActualSimp = String.Format("{0}.{1}", _
                             .Version.Major.ToString, .Version.Minor.ToString)
            sVersion = String.Format("Versão {0}", My.Application.Info.Version.ToString)
        End With
    End Sub
    ''' <summary>
    ''' Check if URL exists and return a boolean 
    ''' </summary>
    ''' <param name="sUrl">Enter the URL you want to check for. 
    ''' The URL must be complete, including the name of the file to download.</param>
    ''' <returns>A boolean response</returns>
    ''' <remarks></remarks>
    Public Function UrlExist(ByVal sUrl As String) As Boolean
        Dim fileUrl As Uri = New Uri(sUrl)
        Dim req As System.Net.WebRequest
        req = System.Net.WebRequest.Create(sUrl)
        Dim resp As System.Net.WebResponse
        Try
            resp = req.GetResponse()
            resp.Close()
            req = Nothing
            Return (True)
        Catch ex As Exception
            req = Nothing
            Return False
        End Try
    End Function
    ''' <summary>
    ''' Checks if computer is connected to network
    ''' </summary>
    ''' <returns>Boolean Response</returns>
    ''' <remarks></remarks>
    Public Function GotInternet() As Boolean
        Try
            Return My.Computer.Network.IsAvailable
        Catch weberrt As WebException
            Return False
        Catch except As Exception
            Return False
        End Try
    End Function
    ''' <summary>
    ''' Create MD5 Hash
    ''' </summary>
    ''' <param name="sString">Enter the variable you want to encrypt in MD5</param>
    ''' <param name="iSize">Enter the size you want to return encryption in MD5, 
    ''' maximum size is 32</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function CreateHashPure(ByVal sString As String, _
                    Optional iSize As Integer = 32) As String
        Using md5Hash As MD5 = MD5.Create()
            Dim hash As String = GetMd5Hash(md5Hash, sString)
            hash = Left(hash, iSize)
            Return LCase(hash)
        End Using
    End Function
    ''' <summary>
    ''' Function to Create MD5 Hash, with base the set information
    ''' </summary>
    ''' <param name="md5Hash">A MD5 Hash created</param>
    ''' <param name="input">Input string</param>
    ''' <returns>Return string response</returns>
    ''' <remarks></remarks>
    Public Function GetMd5Hash(ByVal md5Hash As MD5, ByVal input As String) As String

        ' Convert the input string to a byte array and compute the hash.
        Dim data As Byte() = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input))

        ' Create a new Stringbuilder to collect the bytes
        ' and create a string.
        Dim sBuilder As New StringBuilder()

        ' Loop through each byte of the hashed data 
        ' and format each one as a hexadecimal string.
        Dim i As Integer
        For i = 0 To data.Length - 1
            sBuilder.Append(data(i).ToString("x2"))
        Next i

        ' Return the hexadecimal string.
        Return sBuilder.ToString()

    End Function 'GetMd5Hash

End Module

该库有一个名为 Updater.vb 的类。在此模块类中实现了许多函数。这是库的核心,包含函数、子程序和属性。最重要的函数,或许是 CheckNewVersion(),它检查是否有新版本可供下载并返回一个布尔值。基于此响应,就可以知道应用程序是否需要更新。

其他函数和属性,以及子程序,也很重要,因为它们是库的一部分,但它们补充了其他函数甚至子程序。下面是该类的注释完整代码,以便开发者更好地理解。

Imports System.Windows.Forms
Imports System.Reflection
Imports System.Xml
Imports System.IO

Public Class Updater
    'Define the variables that received values to use by Application
    Private _versionapp As String
    Private _codeapp As String
    Private _nameapp As String
    Private _urlconfig As String
    Private sNewVersion As String, sDescUpdate As String, sDateUpdate As String
    'Create a Check Update Response for decision making
    Public Enum CheckResponse
        res_empty = 0
        res_noupdate = 1
        res_update = 2
        res_erro = 3
    End Enum

    Public Sub New()
        MainLib()
    End Sub
    ''' <summary>
    ''' After check if has a new version to download, the Library showing a message
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub AppUpdate()
        Dim frm As New frmUpdateDesc 'create a new instance of frmUpdateDesc
        'Show the information about 
        frm.wbDescription.DocumentText = My.Resources.HTMLStart & _
            "<h4>A new version is available for download.</h4>" &
            "<p>Version: " & sNewVersion & "<br/>" &
            "Date: " & sDateUpdate & "</p>" &
            "<div>Description: " & sDescUpdate & "</div>" &
            "<p>You want to get the new version now?<br/>" &
            "To start the download, click the Download button.!</p>" & My.Resources.HTMLEnd
        frm.ShowDialog()
    End Sub
    ''' <summary>
    ''' Displays information obtained in the CheckNewVersion function.
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub CheckUpdate()
        'check new update
        Dim CheckUpdataRes As CheckResponse = CheckNewVersion()
        If CheckUpdataRes = CheckResponse.res_update Then 'check new update
            AppUpdate() 'show update form
        ElseIf CheckUpdataRes = CheckResponse.res_noupdate Then
            MessageBox.Show("Your software has the latest version and is up to date!", _
            sTitle, MessageBoxButtons.OK, MessageBoxIcon.Information)
        ElseIf CheckUpdataRes = CheckResponse.res_empty Then 'check new update
            Exit Sub
        ElseIf CheckUpdataRes = CheckResponse.res_erro Then 'check new update
            MessageBox.Show("Could not check for update!", sTitle, _
                             MessageBoxButtons.OK, MessageBoxIcon.Error)
        Else
            MessageBox.Show("Error!", sTitle, MessageBoxButtons.OK, MessageBoxIcon.Error)
        End If
    End Sub
    ''' <summary>
    ''' Check Online Version
    ''' </summary>
    ''' <returns>Return A Enum a CheckResponse Value</returns>
    ''' <remarks></remarks>
    Public Function CheckNewVersion() As CheckResponse
        Dim PathTemp As String
        PathTemp = System.IO.Path.GetTempPath()
        Try
            'Allows you to verify that all required Properties have been set 
            'so that the library can check for a new update version.
            'Check ULRConfig
            If String.IsNullOrWhiteSpace(URLConfig) Then
                MessageBox.Show("You must specify the configuration file path to check _
                for update!", sTitle, MessageBoxButtons.OK, MessageBoxIcon.Information)
                Return CheckResponse.res_empty
            End If
            'Check VersionApp
            If String.IsNullOrWhiteSpace(VersionApp) Then
                MessageBox.Show("Application version must be specified to check _
                for update!", sTitle, MessageBoxButtons.OK, MessageBoxIcon.Information)
                Return CheckResponse.res_empty
            End If
            'Check NameApp
            If String.IsNullOrWhiteSpace(NameApp) Then
                MessageBox.Show("You must specify the application name to check _
                for updates.!", sTitle, MessageBoxButtons.OK, MessageBoxIcon.Information)
                Return CheckResponse.res_empty
            End If
            'Check if computer is connected a Network
            If GotInternet() = False Then
                MessageBox.Show("Unable to check software update. _
                                 No Internet connection verified!", sTitle, _
                                 MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
                Return False
            End If
            'Allows you to check if the given URL is true or if the given file exists 
            'on the server
            If UrlExist(URLConfig) = True Then
                'Checks if Config file exists
                If File.Exists(PathTemp & My.Application.Info.AssemblyName & ".xml") _
                   Then File.Delete(PathTemp & My.Application.Info.AssemblyName & ".xml")
                'Starts configuration file download by saving to computer Temp folder
                My.Computer.Network.DownloadFile(URLConfig, PathTemp & _
                              My.Application.Info.AssemblyName & ".xml")
                'Start reading configuration information
                GoTo InitialDld
            Else

                Return CheckResponse.res_erro
            End If
InitialDld:
            Clipboard.SetText(PathTemp & My.Application.Info.AssemblyName & ".xml")
            'Checks if the configuration file was successfully obtained
            If System.IO.File.Exists(PathTemp & My.Application.Info.AssemblyName & ".xml") Then
                Dim dom As New XmlDocument()
                'Read information from the configuration file to pass to variables, 
                'allowing the library to tell if there is a need to update
                dom.Load(PathTemp & My.Application.Info.AssemblyName & ".xml")
                'Load Version Info
                Dim sVer As String = dom.SelectSingleNode("//Info/Version").InnerText
                'Load Date Info
                Dim sDate As String = dom.SelectSingleNode("//Info/Date").InnerText
                'Load File download (Install file) Info
                Dim sFileDld As String = dom.SelectSingleNode("//Info/Filename").InnerText
                'Load Description Info
                Dim sDescription As String = _
                        dom.SelectSingleNode("//Info//Description").InnerText
                'Compares the current version of the application 
                'to the obtained version through the configuration file. 
                'If the server version is larger then upgrade is enabled, 
                'if false reports no need for upgrade
                If sVerUpdate.FileVersion.ToString < sVer Then
                    sNewVersion = sVer
                    sDescUpdate = sDescription
                    sDateUpdate = sDate
                    LibUpdate.NameApp = NameApp
                    LibUpdate.VersionApp = VersionApp
                    LibUpdate.URLConfig = URLConfig
                    Return CheckResponse.res_update
                Else
                    Return CheckResponse.res_noupdate
                End If
            Else
                Return CheckResponse.res_erro
            End If
        Catch ex As Exception
            MessageBox.Show("Error: " & ex.Message & vbNewLine & vbNewLine & _
                            "StackTrace: " & ex.StackTrace, sTitle, MessageBoxButtons.OK, _
                             MessageBoxIcon.Stop)

            Return CheckResponse.res_erro
        Finally

        End Try
    End Function
    ''' <summary>
    ''' Get Library Assembly Version
    ''' </summary>
    ''' <returns>Return String Value</returns>
    ''' <remarks></remarks>
    Public Function LibVersion() As String
        Dim assy As System.Reflection.Assembly = GetType(Updater).Assembly
        Dim assyName As String = assy.GetName().Name
        'AssemblyTitle
        Dim attr As Attribute = Attribute.GetCustomAttribute( _
              assy, GetType(AssemblyTitleAttribute))
        Dim adAttr As AssemblyTitleAttribute = _
                    CType(attr, AssemblyTitleAttribute)
        Return String.Format("{0}", GetType(Updater).Assembly.GetName().Version)
    End Function
    ''' <summary>
    ''' Get Library Assembly Name (Title) and Version
    ''' </summary>
    ''' <returns>Return String Value</returns>
    ''' <remarks></remarks>
    Public Function LibNameVersion() As String
        Dim assy As System.Reflection.Assembly = GetType(Updater).Assembly
        Dim assyName As String = assy.GetName().Name
        'AssemblyTitle And AssemblyVersion
        Dim attr As Attribute = Attribute.GetCustomAttribute( _
              assy, GetType(AssemblyTitleAttribute))
        Dim adAttr As AssemblyTitleAttribute = _
                    CType(attr, AssemblyTitleAttribute)
        Return String.Format("{0} v{1}", adAttr.Title, _
               GetType(Updater).Assembly.GetName().Version)
    End Function
    ''' <summary>
    ''' Get Library Assembly Description
    ''' </summary>
    ''' <returns>Return String Value</returns>
    ''' <remarks></remarks>
    Public Function LibDescription() As String
        Dim assy As System.Reflection.Assembly = GetType(Updater).Assembly
        Dim assyName As String = assy.GetName().Name
        'AssemblyDescriptionAttribute
        Dim attr As Attribute = Attribute.GetCustomAttribute( _
              assy, GetType(AssemblyDescriptionAttribute))
        Dim adAttr As AssemblyDescriptionAttribute = _
                    CType(attr, AssemblyDescriptionAttribute)
        Return String.Format("{0}", adAttr.Description)
    End Function
    ''' <summary>
    ''' Get Library Assembly Name (Title)
    ''' </summary>
    ''' <returns>Return String Value</returns>
    ''' <remarks></remarks>
    Public Function LibName() As String
        Dim assy As System.Reflection.Assembly = GetType(Updater).Assembly
        Dim assyName As String = assy.GetName().Name
        'AssemblyTitleAttribute
        Dim attr As Attribute = Attribute.GetCustomAttribute( _
              assy, GetType(AssemblyTitleAttribute))
        Dim adAttr As AssemblyTitleAttribute = _
                    CType(attr, AssemblyTitleAttribute)
        Return String.Format("{0}", adAttr.Title)
    End Function
    ''' <summary>
    ''' Get Library Assembly Copyright
    ''' </summary>
    ''' <returns>Return String Value</returns>
    ''' <remarks></remarks>
    Public Function LibCopyright() As String
        Dim assy As System.Reflection.Assembly = GetType(Updater).Assembly
        Dim assyName As String = assy.GetName().Name
        'AssemblyCopyrightAttribute
        Dim attr As Attribute = Attribute.GetCustomAttribute( _
              assy, GetType(AssemblyCopyrightAttribute))
        Dim adAttr As AssemblyCopyrightAttribute = _
                    CType(attr, AssemblyCopyrightAttribute)
        Return String.Format("{0}", adAttr.Copyright)
    End Function
    ''' <summary>
    ''' Set and Get Application Version
    ''' </summary>
    ''' <returns>Return string Value</returns>
    Public Property VersionApp() As String
        Get
            Return _versionapp
        End Get
        Set(value As String)
            _versionapp = value
        End Set
    End Property
    ''' <summary>
    ''' Set and Get Application Name
    ''' </summary>
    ''' <returns>Return string Value</returns>
    Public Property NameApp() As String
        Get
            Return _nameapp
        End Get
        Set(value As String)
            _nameapp = value
        End Set
    End Property
    ''' <summary>
    ''' Set and Get URL of the XML File configuration and information
    ''' </summary>
    ''' <returns>Return string Value</returns>
    Public Property URLConfig() As String
        Get
            Return _urlconfig
        End Get
        Set(value As String)
            _urlconfig = value
        End Set
    End Property
End Class

配置 XML 文件结构

XML 文件的结构很重要,这样库及其 CheckNewVersion() 函数才能正确读取信息,然后传递给库变量,库变量将处理信息并决定是否更新软件。

下面我们提供 XML 的结构,该结构可以由开发者任意命名,但建议与 AssemblyName 相同,以便在使用此库的多个项目中更方便地管理更新。

<?xml version="1.0" encoding="utf-8"?>
<!--Arquivo de Atualização do Software Appsetup v1.0-->
<!--Date in US Format or in Your Region Format-->
<Application>
<Info>
  <Version>1.1.1.0321</Version>
  <Date>27/09/2019</Date>
  <Filename>http://antsoft.com.br/appsetup.exe</Filename>
  <Description>
    System Update Tool Improvement.
  </Description>
  <copyright>Copyright © 2019, AntSoft Systems On Demand</copyright>
</Info>
</Application>

表单

库项目中的三个窗体都在可下载的代码中,并且不会在本文中讨论,因为它们易于理解,因为所有代码都已注释。只需注意,在窗体中有一个名为 UpdateService() 的子程序,这是该窗体的核心,因为这个子程序在检查更新需求后,库将下载 XML 配置文件的安装文件,而安装文件最好是 exemsi 扩展名。

以下是两个库窗体的图像。第一张图像是更新描述窗体,第二张图像是更新窗体,将在此窗体中获取安装文件,然后运行安装新版本。在此示例中,找不到更新文件,因为这是一个演示。

frmUpdater Form 中,UpdateService() 子程序有一个重要的解释点,因为它可以让开发者更好地理解

 Public Sub UpdateService()
        'Clear All items on Listview
        lvwUpdate.Items.Clear()
        'Add new item on ListView
        lvwUpdate.Items.Add("Starting the upgrade", 3)
        Try
            'Allows you to add two new Handles to allow you to generate file 
            'download progress and completion
            AddHandler wc.DownloadProgressChanged, AddressOf OnDownloadProgressChanged
            AddHandler wc.DownloadFileCompleted, AddressOf OnFileDownloadCompleted
            'Add new item on ListView
            AddTextlvw("Checking for new version online...")
            'Checks if Config file exists
            If File.Exists(PathTemp & My.Application.Info.AssemblyName & ".xml") _
               Then File.Delete(PathTemp & My.Application.Info.AssemblyName & ".xml")
            'Get Config File
            My.Computer.Network.DownloadFile(UpdaterApp.LibUpdate.URLConfig, _
                PathTemp & My.Application.Info.AssemblyName & ".xml")

            If File.Exists(PathTemp & My.Application.Info.AssemblyName & ".xml") Then
                'Add new item on ListView
                AddTextlvw("Valid update found ...", 2)
            Else
                'Add new item on ListView
                AddTextlvw("Update not verified or process failed!", 1)
                'Add new item on ListView
                AddTextlvw("Try again!", 1)
                Exit Sub
                pBar.Visible = False
            End If
            'Add new item on ListView
            AddTextlvw("Starting version checking ...")
            Dim dom As New XmlDocument()
            'Read information from the configuration file to pass to variables, 
            'allowing the library to tell if there is a need to update
            dom.Load(PathTemp & My.Application.Info.AssemblyName & ".xml")

            'Load Version Info
            sNewVersion = dom.SelectSingleNode("//Info/Version").InnerText
            'Load Date Info
            Dim sDate As String = dom.SelectSingleNode("//Info/Date").InnerText
            'Load File download (Install file) Info
            Dim sFileDld As String = dom.SelectSingleNode("//Info/Filename").InnerText
            'Get only filename of the URL Path
            Dim sFileTmp As String = System.IO.Path.GetFileName(sFileDld)
            sFileExec = System.IO.Path.GetFileName(sFileDld)
            'Add new item on ListView
            AddTextlvw("Current version: " & sVerUpdate.FileVersion, 5)
            'Add new item on ListView
            AddTextlvw("Downloadable Version: " & sNewVersion, 5)
            If sVerUpdate.FileVersion.ToString < sNewVersion Then
                'Add new item on ListView
                AddTextlvw("Starting the update file download.", 3)
                'Checks if Install File exists, if true Delete
                If System.IO.File.Exists(PathTemp & "\" & sFileTmp) Then _
                    Kill(PathTemp & "\" & sFileTmp)
                If UrlExist(sFileDld) = True Then
                    'Add new item on ListView
                    AddTextlvw("Downloading the installation file...")
                    'Start download of the Install file setup
                    wc.DownloadFileAsync(New Uri(sFileDld), PathTemp & "\" & sFileTmp)
                Else
                    'Add new item on ListView
                    AddTextlvw("Setup file not found!", 1)
                    pBar.Visible = False
                    Exit Sub
                End If
            Else
                'Add new item on ListView
                AddTextlvw("No need to update.", 4)
                pBar.Visible = False
                btnAbout.Enabled = True

            End If
        Catch ex As Exception
            'Add new item on ListView
            MessageBox.Show("Unable to update software. Error: " & vbNewLine & _
                            ex.Message, sTitle, _
                            MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
            AddTextlvw("Error trying to verify update.", 1)
            pBar.Visible = False

        End Try
    End Sub

调用 UpdateApp 库

要调用新版本,请检查函数,然后在新版本可用时开始下载。这非常简单,只需几行命令即可完成。您必须在项目引用中引用 UpdateApp 库。

在窗体中,您需要输入以下命令:

Public Class Form1
    Dim LibUpdater As New UpdaterApp.Updater
    Private Sub Button1_Click(sender As Object, e As EventArgs) _
            Handles Button1.Click, LinkLabel1.Click
        With LibUpdater
            'Change this URL to the path where your configuration file is hosted in XML format.
            .URLConfig = "http://www.antsoft.com.br/CPTests/UpdateApp/" & _
              My.Application.Info.AssemblyName & ".xml"
            'Application Name
            .NameApp = My.Application.Info.ProductName
            'Application Version in String Format
            .VersionApp = My.Application.Info.Version.ToString
            'Call the CheckUpdate Function
            .CheckUpdate()
        End With
    End Sub
End Class

关注点

有了上述代码,就可以以一种简单而有效的方式检查应用程序的新更新,这可以方便所有客户获取新功能,并方便维护您的软件,从而优化时间,让您有更多时间专注于开发新版本。

历史

此代码是发布版本。

© . All rights reserved.