做一个网上的升级程序,若版本比较新,则到服务器上下载.EXE文件覆盖正在执行的可执行文件的,请问大虾帮帮忙,急!急!急!
解决方案 »
- 枚举问题
- 当textbox被输入文本并按buttton后文本内容被送到预设好的excel里面的特定位置(去参加计算)求代码!
- 一个女人被强*后的精彩对白(转)
- 是VB中连接ACCESS的查询相同条件的下一条记录怎么写啊?跪求!
- 在线求救急等
- 询问关于VB书中文件一章中的二个小疑问,谢谢!
- 哪里有注册版的vsflexgrid pro(急到期了)
- 请教高手解决技术性问题(lib,ocx,ole,activex,com,dll,类,函数)
- 各位千万帮忙,在线等!!!!
- “Label3 = rst”有错误,提示“type mismatch”,请问如何解决?
- 宣布 ******为不受欢迎的人(在我的帖子里)
- DAO中删除数据
给自己开发的软件增加一个网上升级,既可以让用户随时得到最新版本的软件,又让你的软件显得新潮。那么,这些是怎么实现的呢?本文就以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
一:比较版本是否最新,可以使用生成版本文件如:VER.TXT等来存放当前版本信息。
二:关闭正在运行的待升级程序
三:下载新文件覆盖老的
四:升级程序退出运行,并打开新的版本程序。(可有可无)
Const timeout As Long = 60Dim file() As Byte, Destination As StringDim LastSizeCheck As Long, LastSize As LongPrivate Sub BtnStartDL_Click()
Inet1.RequestTimeout = timeout
ProgressBar1.Max = 1024
Destination = App.Path & "\a.exe"
Label1.Caption = "establishing connection...."
Inet1.Execute "http://127.0.0.1/a.exe", "get"
End Sub
Private Function SafeUBoundFile() As Long
On Error GoTo erro
SafeUBoundFile = UBound(file)
Exit Function
erro:
SafeUBoundFile = -1
End FunctionPrivate Sub Command1_Click()
End
End SubPrivate Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Inet1.Cancel
End SubPrivate Sub Inet1_StateChanged(ByVal State As Integer)
Static inproc As Boolean
If Not inproc Then
inproc = TrueSelect Case State
Case icResponseReceived
Dim vtdata() As Byte
Label1.Caption = "downloading" & Inet1.URL & "....."
Do While Inet1.StillExecuting
DoEventsLoop
Do
DoEvents
vtdata = Inet1.GetChunk(256, 1)
If UBound(vtdata) = -1 Then Exit Do
ReDim Preserve file(SafeUBoundFile + UBound(vtdata) + 1)
CopyMemory file(UBound(file) - UBound(vtdata)), vtdata(0), UBound(vtdata) + 1
If UBound(vtdata) <> 255 Then Exit Do
Dim tmp As Long
tmp = UBound(file) / 1024
If tmp > ProgressBar1.Max Then tmp = ProgressBar1.Max
ProgressBar1.Value = tmpLoop
Label1.Caption = "download complete"
MsgBox "download complete"
Inet1.Cancel
Open Destination For Binary As #1
Put #1, , file
Close #1
Erase file
End Select
inproc = False
End If
End SubPrivate Sub Timer1_Timer()
Label2.Caption = Format(SafeUBoundFile / 1024, "#,##0.00KB") & "@" & Format((SafeUBoundFile - LastSize) / 1024 / (Timer - LastSizeCheck / 1000), "#.##0.00KB/s")
LastSizeCheck = Timer * 1000
LastSize = SafeUBoundFileEnd Sub