技术文章 > 应用程序的网上升级-VB

应用程序的网上升级-VB

2018-11-15 10:06

文档管理软件,文档管理系统,知识管理系统,档案管理系统的技术资料:
给自己开发的软件增加一个网上升级,既可以让用户随时得到最新版本的软件,又让你的软件显得新潮。那么,这些是怎么实现的呢?本文就以VB为例来说明这一技术的实现原理。
在Windows系统下,一个EXE文件在运行的时候是被系统锁定的,在其运行期间是不能对其修改的(至少用普通的方法办不到),也不能被覆盖。因此,直接从网上下载一个新版本文件覆盖旧版本文件是行不通的,需要另辟蹊径。
既然不能在运行的时候覆盖自身,那就只有先停止在覆盖了,但是覆盖工作由谁来做呢,这很简单,由别的程序来做。举例来说,程序A需要升级到新版的A“,但在A运行的时候A“不能覆盖A,这时A必须停止,而由B来从网上下载A“,从而覆盖A。将这个过程联起来就是:1)A启动B,2)A停止运行,3)B下载A“,4)B启动A“,5)B停止运行。这样就运行了A“,即新版的A。这里,可以将A看成主程序,而将B看成辅助升级程序。
上面这个步骤只是实现了主程序A的升级,而辅助升级程序B没有能够升级,要实现B的升级,步骤要多一步:1)A下载B“,2)A启动B“,3)A停止运行,4)B“下载A“,5)B“启动A“,6)B“停止运行。这样,主程序A和辅助升级程序B就都得到了升级。
至此,网上升级的第一个技术要点就讲完了,下面讲一下从网上下载文件的技术要点。咋一看,好像有些困难,以为要Winsock、WinInet等等知识,但实际上,VB本身提供了大量优秀的控件,使用这些控件使得编程变得简单又可靠。例如,从网上下载文件,我们可以使用MS Internet Transfer Control,即MSINET.OCX。这个控件使得从网上下载文件简单到只要写一两句程序即可实现。
OpenUrl方法:使用这个方法可以下载网上的资源,它有两个参数,一个是URL,这个参数不用多说;另一个是datatype,它指定资源的类型,VB给出了两种类型的资源,字符串型和二进制型,分别对应的参数是icString和icByteArray。注意,这个参数的缺省值是icString,即字符串型,这对我们下载程序是不利的,因此我们要显示的指定它为icByteArray。这种情况下,函数的返回值是一个二进制的数组,将这个数组保存为文件即可实现网上文件的下载。示例如下(来自MSDN)
Dim b() As Byte
Dim strURL As String
“ Set the strURL to a valid address.
strURL = "FTP://ftp.GreatSite.com/China.exe"
b() = Inet1.OpenURL(strURL, icByteArray)
Open "C:\Temp\China.exe" For Binary Access Write As #1
Put #1, , b()
Close #1
这个例子是FTP的资源,当然,也可以是我们需要的HTTP资源。
使用OpenUrl方法下载文件非常简单,但其不足之处是很明显的,在下载过程中,程序无法给出任何信息,直到下载结束,这样往往给用户一种死机的假相。为了实现下载进度的显示,就不能使用这个方法了,而要用一些稍微复杂点的东西了。
Execute方法:使用这个方法可以向远程服务器发送一个请求,它有四个参数,一个URL,一个请求命令字,一个附加数据,一个附加信息(后两个我也不知道应该叫什么,暂且这么叫吧)。我们要从HTTP服务器上下载文件,需要发送的请求是"GET",附加数据和附加信息都是不需要的。最后的使用方法就是Inet1.Execute strURL, "GET",发送一个"GET"请求到服务器,然后等待回应。
StateChanged事件:这个事件有一个State来说明事件发生的原因。刚才说到等待回应,没错,当应用程序接收完服务器的回应时就会触发这个事件,而且State是icResponseReceived,这时,我们可以用GetHeader方法来得到文件的大小,Inet1.GetHeader("Content-Length")得到的就是文件的大小。注意:并不是所有的HTTP服务器都支持Content-Length,如果服务器不支持的话,那么就没有办法了,不过绝大多数服务器都是支持的。
同样在StateChanged事件里,如果State是icResponseCompleted,说明所有的数据都已经接收,可以用GetChunk方法把数据从缓冲区里读出来了。GetChunk方法读数据和OpenUrl不同,它可以指定每次读取数据的数据量大小。这样,不断的用GetChunk读取数据就可以得到已读取的数据量,在上一步已经得到了文件的大小,即总数据量,根据这些就可以算出文件已经下载的百分比。
GetChunk方法:与OpenUrl有些类似,但多一个参数指定读取数据的字节数。它的返回值也是一个二进制数组(参数datatype指定为icByteArray时)
结合以上几点,我们就可以写出一个带有进度显示的文件下载来。下面是参考设计。
“该变量用于存储Web页面文件大小
Private m_lngDocSize As Long
Private Const strURL = "http://vip.6to23.com/NowCan1/project/HumanManage.exe"
Private Const FileName = "HumanManage.exe"
Private Sub Command1_Click()
“文件大小值复位
m_lngDocSize = 0
“复位进度条控件
ProgressBar1.Value = 0.001
“显示进度的标签内容设为空
lblProgressInfo.Caption = ""
“定义ITC控件使用的协议为HTTP协议
Inet1.Protocol = icHTTP
“调用Execute方法向Web服务器发送HTTP请求
Inet1.Execute Trim$(strURL), "GET"
lblProgressInfo.Caption = "请等待..."

End Sub

Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Shell App.Path & "\" & FileName, vbNormalFocus
End Sub
Private Sub Inet1_StateChanged(ByVal State As Integer)
Dim binBuffer() As Byte
Dim sngProgerssValue As Single
Dim iBlock As Long
On Error Resume Next
iBlock = 0
Select Case State
Case icResponseCompleted
“打开文件供写入
Open App.Path & "\" & FileName For Binary Access Write As #1
Do “从缓冲区读取数据
DoEvents
binBuffer = Inet1.GetChunk(512, icByteArray)
“strText = strText & strBuffer
iBlock = iBlock + 1
If m_lngDocSize > 0 Then
“获得进度百分比值
sngProgerssValue = Int((iBlock * 512 / m_lngDocSize) * 100)
“更新进度标签显示内容
lblProgressInfo.Caption = "已下载 " & CStr(iBlock * 512) & " 字节 (" & CStr(sngProgerssValue) & "%)"
“用新值更新进度条控件
ProgressBar1.Value = sngProgerssValue
“写入文件
Put #1, , binBuffer()
End If
Loop Until iBlock * 512 >= m_lngDocSize
“关闭文件
Close #1
MsgBox "升级完成", vbOKOnly Or vbInformation, "在线升级"
Case icResponseReceived
If m_lngDocSize = 0 Then
“读取页面文件大小
If Len(Inet1.GetHeader("Content-Length")) > 0 Then
m_lngDocSize = CLng(Inet1.GetHeader("Content-Length"))
If (m_lngDocSize = 0) Then
MsgBox "读取远程数据出错", vbOKOnly Or vbExclamation, "在线升级"
End If
Else
MsgBox "ERROR!", vbOKOnly Or vbExclamation, "在线升级"
End If
End If
Case icError
MsgBox "与主机通信出错", vbOKOnly Or vbExclamation, "在线升级"
Case icResolvingHost
lblProgressInfo.Caption = "正在查找主机..."
Case icHostResolved
lblProgressInfo.Caption = "已经找到主机"
Case icConnecting
lblProgressInfo.Caption = "正在联系主机"
Case icConnected
lblProgressInfo.Caption = "已经连接到主机"
Case icRequesting
lblProgressInfo.Caption = "正在发送请求..."
Case icRequestSent
lblProgressInfo.Caption = "成功发送请求"
Case icReceivingResponse
lblProgressInfo.Caption = "正在接收回应..."
Case icDisconnecting
lblProgressInfo.Caption = "正在断开连接..."
Case icDisconnected
lblProgressInfo.Caption = "已经断开连接"
End Select
End Sub
以上简单的介绍了网上升级的实现方法,如有兴趣可以试试。