现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

vb.net 2005 软件升级程序 在线升级软件 原理、思路

2012-11-09 21:55 工业·编程 ⁄ 共 14366字 ⁄ 字号 暂无评论

自己做了软件,加了注册功能,现在想加个在线升级功能 一子被这个功能卡住几天,晚上搜索了两天没获得什么结果。好的教程不多的!郁闷的看了半天娱乐视频,玩了一会游戏!今天终于突破瓶颈,现在把我自己的成就工作余下,这个系统是在vb.net 2005上完成的,不过我觉得基本原理一样:

很多都说vb.net以后自带的clickonce简单好用,说实话,我觉得clickonce就是给那些玩家程序员弄的,根本不实际。要么是微软技术部成熟,要么就是我学得不深,反正我觉得还是自己写一个实在,做成了就是万能的。

第一步先讲解简单思路:

1、首先我们要有自己的ftp服务器,把要升级的读写挂在服务器上,本人本身是做网站的,所以已经有ftp服务器,不建议用自己电脑搭服务器测试,浪费时间。最好去买一个100m网站空间,便宜一年才89元 最好,本人就是用这家服务器2007年开始用,稳定反应快,出问题维修快。

2、启动主程序读取程序版本号,例如:1.0.0.0 。我们在自己网站上挂上最新版本html文本,里面只写个最新号版本,例如:1.0.0.9,判断版本不一样就启动 在线升级程序

update.exe,然后关闭自己的进程

3、update.exe是用vs另外创建项目做的软件,在我们主程序打包的时候,一起打包进去。

4、update.exe的工作原理。首先我们创建一个config.xml,挂在ftp上。里面包含升级的文件内容,格式如下:(我们也可以把要升级的文件放在sql里面)

<?xml version="1.0" encoding="utf-8"?>  
<DoubleBall>
    <dbversion id="1.0.0.0">
    <filedb path="data">这个不能删除用于版本检测</filedb>
    </dbversion>
    <dbversion id="1.0.0.1">
    <filedb path="data">bank.png</filedb>
    <filedb path="data">bookmark.png</filedb>
    </dbversion>
    <dbversion id="1.0.0.2">
    <filedb path="data">busy.png</filedb>
    <filedb path="data">check.png</filedb>
    </dbversion>
    <otherfile>
    <filedb path="">DoubleBall.exe</filedb>
    <filedb path="">ssq.dll</filedb>
    </otherfile>
</DoubleBall>

因为软件经常升级,所以我们把每个版本对应要升级的文件名保存在xml里面,我这边简单举例三个版本1.0.0.0-1.0.0.2,其中1.0.0.0版本没内容用于首次升级检测。otherfile下的文件是每个版本共有的文件。

update.exe启动后通过先获取主程序版本。然后 Imports System.Net.FtpWebRequest 后连接ftp下载config.xml到目录下。获取xml内容

xml原理:我们获取所有dbversion节点,用for循环检测,发现id跟我们版本一样,则开始下载版本后面的内容。而otherfile下的文件是升级必须下载的,不需要检测

假如我们现在主程序是1.0.0.1版本,那么它只更新 图片busy.png,check.png 和主程序 DoubleBall.exe 主动态库 ssq.dll。更新都是通过Imports System.Net.FtpWebRequest连接ftp下载到本地。我们下载升级程序的时候现在本地,主程序目录下创建临时文件update,文件下载都放在update下。等全部下载好,再把下载的内容复制覆盖到程序下面,以免下载一般出错什么的。覆盖完后,删除下载的临时夹update。

5 启动主程序,关闭update.exe进程

下面我贴出主要函数:

 

<p>Imports System.Net 'FtpWebRequest 
Imports System.IO '输入输出流 
Imports System.XML 'xml 
Imports System.Text.RegularExpressions '正则</p><p>'常见错误:如果发现没有检测到文件,是xml出错,原因缺少对比版本1.0.0.0</p><p>Public Class Form1 
    Dim ftppath As String = "<a href="ftp://www.qiusheng.net/web/DoubleBall/">ftp://www.qiusheng.net/web/DoubleBall/</a>" 'ftp升级文件的,www.qiusheng.net也可以换做ip 
    Dim listupdate As String = ftppath & "config_db.xml" '配置文件ftp路径 
    Dim userID As String = "qi***g" 'ftp账户 
    Dim ftppw As String = "31C******b4a1" 'ftp密码 
    Dim softname As String = "DoubleBall.exe" '主程序 
    Dim startpath As String = Application.StartupPath '主程序启动的目录 
    Dim updatepath As String = startpath & "\update" 
    Dim listxml As String = startpath & "\config_db.xml" 
    Dim reqftp As FtpWebRequest 
    Dim oldversion As String 
    Private Delegate Sub myDelegate(ByVal myString As String) '自定义一个委托 
    Dim MyThread As System.Threading.Thread '定义一个线程</p><p>    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 
        Timer1.Start() 
    End Sub</p><p>    '中转函数 
    Private Sub sum() 
        Me.BeginInvoke(New myDelegate(AddressOf softUpdate), "") '在启动的函数内,用新委托调用 签名函数 
    End Sub</p><p>    Private Sub softUpdate(ByVal myString As String) 
        If Directory.Exists(updatepath) Then 
            DeleteDir(updatepath) 
        End If</p><p>        TextBox1.AppendText("创建临时更新文件夹:update" & vbCrLf) 
        Directory.CreateDirectory(updatepath) '创建文件夹 
        '下载配置文件 参数:远程路径 本地路径 现在的进度条 
        downfile(listupdate, listxml, ProgressBar1, "config_db.xml") '下载配置文件到本地</p><p>        oldversion = "1.0.0.0" 'Getcurversion(startpath & "\" & softname) 
        TextBox1.AppendText(softname & "获取当前版本号:" & oldversion & vbCrLf) 
        Label1.Text = softname & "当前版本:" & oldversion 
        updateXMl(listxml) '从ftp批量下早软件</p><p>        TextBox1.AppendText("覆盖原文件..." & vbCrLf) 
        CopyDir(updatepath, startpath)</p><p>        TextBox1.AppendText("删除临时更新目录..." & vbCrLf) 
        DeleteDir(updatepath)</p><p>        TextBox1.AppendText("升级完毕!" & vbCrLf)</p><p>        '启动DoubleBall.exe主程序 
        Process.Start(startpath & "\" & softname)</p><p>        '结束DoubleBallUpdate进程 
        Dim proc() As Process = Process.GetProcessesByName("DoubleBallUpdate") 
        Dim pro As Process 
        For Each pro In proc 
            pro.Kill() 
        Next 
    End Sub</p><p>    '下载 参数:远程路径 本地路径 现在的进度条 
    Private Sub downfile(ByVal filepath As String, ByVal savepath As String, ByVal Prog As ProgressBar, ByVal downname As String) 
        TextBox1.AppendText("开始下载:" & downname) 
        Try 
            reqftp = FtpWebRequest.Create(New Uri(filepath)) 
            reqftp.Method = WebRequestMethods.Ftp.DownloadFile  '下载 '上传UploadFile 
            reqftp.UseBinary = True 
            reqftp.Credentials = New NetworkCredential(userID, ftppw)</p><p>            Dim response As FtpWebResponse = reqftp.GetResponse 
            Dim totalBytes As Long = getFileSize(filepath) 
            Prog.Maximum = totalBytes 
            Dim totalDownloadedByte As Long = 0 '当前下载的长度</p><p>            Dim outputStream As FileStream = New FileStream(savepath, FileMode.Create) '输出流 
            Dim ftpStream As Stream = response.GetResponseStream 
            Dim bufferSize As Integer = 1024 
            Dim buffer(bufferSize) As Byte 
            Dim readCount As Integer '读取的数量</p><p>            readCount = ftpStream.Read(buffer, 0, bufferSize) '读取 
            Do While readCount > 0 
                totalDownloadedByte = readCount + totalDownloadedByte 
                Prog.Value = totalDownloadedByte '设置进度条</p><p>                outputStream.Write(buffer, 0, readCount) '写入流 
                readCount = ftpStream.Read(buffer, 0, bufferSize) '读取 
            Loop 
            ftpStream.Close() 
            outputStream.Close() 
            response.Close() 
            TextBox1.AppendText(" OK!" & vbCrLf) 
        Catch ex As Exception 
            TextBox1.AppendText(" OK!" & vbCrLf) 
        End Try 
    End Sub</p><p>    '获取文件大小 
    Private Function getFileSize(ByVal filepath As String) As Long 
        Try 
            reqftp = FtpWebRequest.Create(New Uri(filepath)) 
            reqftp.Method = WebRequestMethods.Ftp.GetFileSize 
            reqftp.UseBinary = True 
            reqftp.Credentials = New NetworkCredential(userID, ftppw) 
            Dim response As FtpWebResponse = reqftp.GetResponse 
            getFileSize = response.ContentLength '获取文件大小 
        Catch ex As Exception 
            getFileSize = 0 
        End Try 
    End Function</p><p>    '获取版本号 
    Private Function Getcurversion(ByVal filepath As String) As String 
        Dim Curversion As String 
        Try 
            Curversion = FileVersionInfo.GetVersionInfo(filepath).FileVersion.ToString 
            Return Curversion 
        Catch ex As Exception 
            Return Nothing 
        End Try 
    End Function</p><p> 
    '复制文件 
    Public Shared Sub CopyDir(ByVal srcPath As String, ByVal aimPath As String) 
        Try 
            ' 检查目标目录是否以目录分割字符\结束,如果不是则添加之  
            If aimPath(aimPath.Length - 1) <> Path.DirectorySeparatorChar Then 
                aimPath += Path.DirectorySeparatorChar 
            End If 
            '判断源目录是否存在,不存在则退出.  
            If (Not Directory.Exists(srcPath)) Then Exit Sub 
            ' 判断目标目录是否存在如果不存在则新建之  
            If (Not Directory.Exists(aimPath)) Then Directory.CreateDirectory(aimPath) 
            ' 得到源目录的文件列表,该里面是包含文件以及目录路径的一个数组  
            ' 如果你指向copy目标文件下面的文件而不包含目录请使用下面的方法  
            ' string[] fileList = Directory.GetFiles(srcPath);  
            Dim fileList() As String = Directory.GetFileSystemEntries(srcPath) 
            ' 遍历所有的文件和目录  
            For Each FileName As String In fileList 
                ' 先当作目录处理如果存在这个目录就递归Copy该目录下面的文件  
                If Directory.Exists(FileName) Then 
                    CopyDir(FileName, aimPath + Path.GetFileName(FileName)) 
                    ' 否则直接Copy文件  
                Else 
                    File.Copy(FileName, aimPath + Path.GetFileName(FileName), True) 
                End If 
            Next 
        Catch ex As Exception 
            MessageBox.Show(ex.ToString()) 
        End Try 
    End Sub</p><p>    ' ======================================================  
    ' 实现一个静态方法将指定文件夹下面的所有内容Detele  
    ' 测试的时候要小心*作,删除之后无法恢复。  
    ' ======================================================  
    Public Shared Sub DeleteDir(ByVal aimPath As String) 
        Try 
            ' 检查目标目录是否以目录分割字符结束如果不是则添加之  
            If (aimPath(aimPath.Length - 1) <> Path.DirectorySeparatorChar) Then 
                aimPath += Path.DirectorySeparatorChar 
            End If 
            '判断待删除的目录是否存在,不存在则退出.  
            If (Not Directory.Exists(aimPath)) Then Exit Sub 
            ' 得到源目录的文件列表,该里面是包含文件以及目录路径的一个数组  
            ' 如果你指向Delete目标文件下面的文件而不包含目录请使用下面的方法  
            ' string[] fileList = Directory.GetFiles(aimPath);  
            Dim fileList() As String = Directory.GetFileSystemEntries(aimPath) 
            ' 遍历所有的文件和目录  
            For Each FileName As String In fileList 
                If (Directory.Exists(FileName)) Then 
                    ' 先当作目录处理如果存在这个目录就递归Delete该目录下面的文件  
                    DeleteDir(aimPath + Path.GetFileName(FileName)) 
                Else 
                    ' 否则直接Delete文件  
                    File.Delete(aimPath + Path.GetFileName(FileName)) 
                End If 
            Next 
            '删除文件夹  
            System.IO.Directory.Delete(aimPath, True) 
        Catch ex As Exception 
            MessageBox.Show(ex.ToString()) 
        End Try 
    End Sub</p><p>    Sub editone(ByVal allpaths As String, ByVal rootNames As String, ByVal paraname As String, ByVal paravalue As String) 
        Dim lsen() As String = {paraname} '要修改的名称,多个用逗号分开 
        Dim lsit() As String = {paravalue} '要修改对应的值,,多个用逗号分开 
        modifXML(allpaths, rootNames, lsen, lsit) 
    End Sub</p><p>    '修改XML要修改的XML文件名,XML文件中的根元素名称,要修改的元素数组,对应于要修改的元素数组的修改文本数组</p><p>    Sub modifXML(ByVal allpath As String, ByVal rootName As String, ByVal elementNameArry() As String, ByVal innerTextArry() As String) 
        If My.Computer.FileSystem.FileExists(allpath) Then 
            Dim doc As New XmlDocument 
            doc.Load(allpath) 
            Dim list As XmlNodeList = doc.SelectSingleNode(rootName).ChildNodes 
            For Each xn As XmlNode In list 
                Dim xe As XmlElement 
                xe = xn 
                Dim nls As XmlNodeList = xe.ChildNodes 
                For Each xn1 As XmlNode In nls 
                    Dim xe2 As XmlElement 
                    xe2 = xn1 
                    For i As Integer = 0 To elementNameArry.Length - 1 
                        If xe2.Name = elementNameArry(i) Then 
                            xe2.InnerText = innerTextArry(i) 
                        End If 
                    Next 
                Next 
            Next 
            doc.Save(allpath) 
        End If 
    End Sub</p><p> 
    '读取所有XML文件 要读取的XML文件名 
    Sub updateXMl(ByVal allpath As String) 
        Dim doc As New XmlDocument 
        Dim xn As XmlNode 
        Dim IsDown As Boolean = False 
        Dim IsOpen As Boolean = True '是否需要继续判断版本 
        doc.Load(allpath) 
        Dim list As XmlNodeList = doc.SelectNodes("/DoubleBall/dbversion") 
        Dim lsftppath As String 
        Dim lslocalfolder As String '本地文件夹 
        Dim lslocalfile As String '本地文件 
        For Each xn In list 
            '判断下载是否开启 
            If IsDown Then 
                TextBox1.AppendText("更新版本:" & CType(xn, XmlElement).GetAttribute("id") & vbCrLf) 
                Dim nls As XmlNodeList = CType(xn, XmlElement).ChildNodes 
                For Each xn1 As XmlNode In nls</p><p>                    lslocalfolder = CType(xn1, XmlElement).GetAttribute("path") '临时本地文件夹名称 
                    If lslocalfolder <> "" Then 
                        '判断是否存在,如果不存在就创建 
                        If Not Directory.Exists(updatepath & "\" & lslocalfolder) Then 
                            Directory.CreateDirectory(updatepath & "\" & lslocalfolder) '本地创建文件夹 
                        End If 
                        lsftppath = ftppath & lslocalfolder & "/" & CType(xn1, XmlElement).InnerText '临时远程路径 
                        lslocalfile = updatepath & "\" & lslocalfolder & "\" & CType(xn1, XmlElement).InnerText 
                    Else 
                        lsftppath = ftppath & CType(xn1, XmlElement).InnerText '临时远程路径 
                        lslocalfile = updatepath & "\" & CType(xn1, XmlElement).InnerText 
                    End If 
                    downfile(lsftppath, lslocalfile, ProgressBar1, CType(xn1, XmlElement).InnerText) 
                Next 
            End If</p><p>            If IsOpen Then 
                If CType(xn, XmlElement).GetAttribute("id") = oldversion Then 
                    IsDown = True 
                    IsOpen = False '不要再判断版本 
                End If 
            End If 
        Next</p><p>        '下载其它 
        TextBox1.AppendText("下载其它" & vbCrLf) 
        Dim xn2 As XmlNode 
        Dim list2 As XmlNodeList = doc.SelectNodes("/DoubleBall/otherfile") 
        For Each xn2 In list2 
            Dim nls2 As XmlNodeList = CType(xn2, XmlElement).ChildNodes 
            For Each xn3 As XmlNode In nls2</p><p> 
                lslocalfolder = CType(xn3, XmlElement).GetAttribute("path") '临时本地文件夹名称 
                If lslocalfolder <> "" Then 
                    '判断是否存在,如果不存在就创建 
                    If Not Directory.Exists(updatepath & "\" & lslocalfolder) Then 
                        Directory.CreateDirectory(updatepath & "\" & lslocalfolder) '本地创建文件夹 
                    End If 
                    lsftppath = ftppath & lslocalfolder & "/" & CType(xn3, XmlElement).InnerText '临时远程路径 
                    lslocalfile = updatepath & "\" & lslocalfolder & "\" & CType(xn3, XmlElement).InnerText 
                Else 
                    lsftppath = ftppath & CType(xn3, XmlElement).InnerText '临时远程路径 
                    lslocalfile = updatepath & "\" & CType(xn3, XmlElement).InnerText 
                End If 
                downfile(lsftppath, lslocalfile, ProgressBar1, CType(xn3, XmlElement).InnerText) 
            Next 
        Next 
    End Sub</p><p>    '读取单个XML文件 
    Public Function GetreadonlyXMl(ByVal allpath As String, ByVal Elementnames As String) 
        Dim lsgg As String = Nothing 
        Try 
            If My.Computer.FileSystem.FileExists(allpath) Then 
                Dim doc As New XmlDocument 
                doc.Load(allpath) 
                Dim re As XmlNodeReader = New XmlNodeReader(doc) 
                Dim tmpStr As String = "" 
                Dim name As String = Nothing</p><p>                '如果还可以读取 
                While re.Read 
                    '获取读取节点的类型 
                    Select Case re.NodeType 
                        Case XmlNodeType.Element  '匹配次级元素 
                            name = re.Name</p><p>                        Case XmlNodeType.Text  '匹配子元素 
                            If name.Equals(Elementnames) Then 
                                lsgg = re.Value 
                                Exit Select 
                            End If 
                    End Select 
                End While 
            End If</p><p>        Catch ex As Exception 
            'MsgBox(ex.Message & vbCrLf & ex.StackTrace) 
            lsgg = "" 
        End Try 
        GetreadonlyXMl = lsgg 
    End Function</p><p>    Private Sub LinkLabel1_LinkClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) Handles LinkLabel1.LinkClicked 
        System.Diagnostics.Process.Start("<a href="http://www.sandns.net">http://www.sandns.net</a>") 
    End Sub</p><p>    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick 
        MyThread = New System.Threading.Thread(AddressOf sum) 
        MyThread.Start() 
        Timer1.Stop() 
    End Sub 
End Class 
</p> 

给我留言

留言无头像?