话说这几天我闲着无聊,没事就写了个游戏更新程序,一开始自己写了个服务端,通过和客户端的链接,然后将数据传给客户端。这样经过我的测试,发现当网速正常且客户端链接数量小得情况下是没问题的,一旦网速不好或者客户端连接数量太大,就会出现数据丢失,导致更新后的游戏相关文件出现异常,这样对于游戏更新程序来说是一个致命的错误,会造成游戏客户端的损坏。所以我换了种方法:使用WindowsAPI来实现文件下载,就像迅雷一样的,最后经过我的努力终于实现。作为危险漫步博客的忠实读者,这点共享精神还是有的。为了不让读者们走我走过的弯路,我就把我遇到的问题全都写上来。好了,废话不多说,下面转入正题。
一,最初的程序
既然上面说了,需要一个API来下载文件,我就看MSDN,看到了这么一个API:URIDownloadToFile。在VB中的声明方式如下:
Private Declare Function URLDownloadToFile Lib”urlmon”Alias”URLDownloadToFileA(ByVal pCallerAs Long, ByVal szURL As String, ByVal szFileName As Stning, ByVal dwReserved As Long, ByVal lpfnCB AsLong) As Long
笫—个参数:pCaller,控件的接口,如果不是控件则为0。
第二个参数:szURL,要下载的uil地址,不能为空。
第三个参数:szFiLeName,下载后保存的文件名。
第四个参数:dwReserved,保留字段,必需为o。
第五个参数:lpfnCB,下载进度状态回调。到这为止是介绍API知识,我接着讲。于是我根据提示。
可是我输入进去下载链接和储存的文件路径和文件名,点击下载按钮的时候,程序假死了!直到文件下载完毕程序才恢复正常,这可让人头疼了,又没有下载进度,程序还假死。要是让用户用这样的游戏更新程序,用户会流失一大半的,所以我决定解决这个问题。于是我去看百度,终于找到了一些资料,说是这个API的最后一个参数指向了一个IBmdStatusCallback接口的指针,用来返回进度等。于是乎我继续寻找关于IBindStatusCallback的资料,最后终于得知接口IBindStatusCallback存在于库olelib中,据说该库功能很强大,与windows许乡接口想通,读者们有兴趣可以去百度一下,我就不多说了。
二,完善的程序
根据IBindStatusCallback的资料,笔者着实实践了一番,最后终得正果。那么我就把代码发上来,给读者们讲解。
到这里是声明变量”HjUrlDownFile”可调用类模块”URLDownFile”中的事件。第二句是W/ndowsAPI”DeleteUrlCacheEtry”,这个APl主要用于清空缓存,防止下一次下载相同的文件是从缓存中下载的。主要用法如下:
按钮中的代码第一句是用Set语句将新对象 (URLDownFile)引用赋给变量HjUrlDownFile。第二句是将Timerl的状态设置为可用,激活Timerl中的过程代码,以便计算测速。第三句代码是将下载按钮的状态设置为禁用,防止重复点击。第四句就是调用新对象的DownloadFile事件,该事件中的两个参数分别是下载地址和储存路径。这是类模块中的代码,读者们只要会调用就行,类模块中的代码基本上是固定的,要是想实现断点续传功能读者们可自行修改:
新对象的OnProgress事件,第一句代码是将进度条的最大值设置为下载的文件字大小。第二句的意思是将已下载的大小赋值给迸度条的进度。第三句代码是将已下载的进度赋值给dKB_Tmp,以便计算网速使用。第四句代码的意思是将标签的内容该为当前下载的百分比。其中Round(D?rogress/lMax,;100”中,Round()函数的作用是保留小数点位数用的。第一个参数是将已下载的大小和总大小做比值得到的一串小数,第二个参数是要保留的位数,这里写2,就表示是保留两位。再乘以100就能得到一个两位数,然后用CStr0函数转换成字符串,再加上一个百分号,这样子进度就能显示出来了。第五句的意思是,如果总大小等于已下载大小,那么就执行下面的代码。第六句是将”dKB_Tmp”变量中的值清空,相当于初始化。第七句代码是将标签3的内容改为“下载完毕”。第八句用来清空缓存。第九句用来恢复下载按钮的状态。然后第10句到第12句用了一个For循环,用来清空dKB数组中的数据,也相当于初始化。第13句代码是将Timerl的状态设置为禁用,t表示不再计算网速。最后一句DoEvents将控制权限交给系统,防止假死:
Timerl的过程,第一句代码”dKB_Tmp/1024”首次获得这一秒的进度,也就是已经下载了多少。将已下载的大小除以1024,得到数赋值给数组”dKB”中的元素”dKB(l)”中,第二句代码是将即时大小减去上一秒的大小,赋值给标签3的内容。第三句代码是,保存这一秒的下载进度。这样,当Tiemr中的代码循环执行的时候就能得到网速了。
好了,到这里实现下载功能是没问题了。那么要做就要做的好一点,实现监视剪切板直接读取下载地址,然后分离出地址中的文件名,弹出下载窗口,点击按钮下载文件。想到了就马上动手做,笔者已经将代码写好了,下面给读者们详细解释一下:
Private WithEvents DownForm As Form这句代码足将变量DownForm定义为窗口,可调用窗口中的事件。下面代码的详细解释因为太多,我就写在注释中了:
Private Sub Timeil_Timer()
Dim tClipboard As String, tString As String声明变量
Dim Lng As Long
tCLipboard= Clipboard.GetText 取得剪切板中的内容,保存到变量”tClipboard'’中。
If Mid(tClipboard,1,4)=’’http" And
InStr(tClipboard,”.”)0 And InStr(Mid(tClipboard,
InStrRev(tClipboard,”Then,如果在tClipboard”中找到了前四个字是”http”,并且找到了,和00000000的话,那么就确定是下载地址,然后执行下面的代码:
这里有两个函数Instr()和Mid()。Instr用来查找字符,有三个参数Instr(Start,Stringl,String2),第一个参数代表从什么地方开始查找,也就是查找的起始位置,第二个参数是父文本,也就是从什么内容中
查找,第三个参数是被查找的内容,In str函数如果找到了要找的内容,会返回要找的内容的位置,如果没找到会返回0。Mid函数可以用来截取文本,有三个参数Mid(String, Start,Num)第一个参数的意思是要截取的文本内容,第二个参数的意思是从什么地方开始截取,第三个参数的意思是要截取多少个长度。结合着上面的代码,读者们都会看懂的。
好了,到这里一个小下载器就完成了,有什么写的不好的地方还请多多包涵,也可自行修改。其实编程这东西,就是多看多找资料,自然就能弄会了。