在WinForm應(yīng)用程序中實現(xiàn)自動升級_第1頁
在WinForm應(yīng)用程序中實現(xiàn)自動升級_第2頁
在WinForm應(yīng)用程序中實現(xiàn)自動升級_第3頁
在WinForm應(yīng)用程序中實現(xiàn)自動升級_第4頁
在WinForm應(yīng)用程序中實現(xiàn)自動升級_第5頁
已閱讀5頁,還剩9頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

最近單位開發(fā)一個項目,其中需要用到自動升級功能。因為自動升級是一個比較常用的功能,可能會在很多程序中用到,于是,我就想寫一個自動升級的組件,在應(yīng)用程序中,只需要引用這個自動升級組件,并添加少量代碼,即可實現(xiàn)自動升級功能。因為我們的程序中可能包含多個exe或者dll文件,所以要支持多文件的更新。首先,要確定程序應(yīng)該去哪里下載需要升級的文件。我選擇了到指定的網(wǎng)站上去下載,這樣比較簡單,也通用一些。在這個網(wǎng)站上,需要放置一個當(dāng)前描述最新文件列表的文件,我們估且叫它服務(wù)器配置文件。這個文件保存了當(dāng)前最新文件的版本號(lastver),大小(size),下載地址(url),本地文件的保存路徑(path),還有當(dāng)更新了這個文件后,程序是否需要重新啟動(needRestart)。這個文件大致如下:updateservice.xml<?xmlversion="1.0"encoding="utf-8"?><updateFiles><filepath="AutoUpdater.dll"url="/CompanyClientApplication/AutoUpdater.zip"lastver=""size="28672"needRestart="true"/><filepath="CompanyClient.exe"url="/CompanyClientApplication/CompanyClient.zip"lastver=""size="888832"needRestart="true"/><filepath="HappyFenClient.dll"url="/CompanyClientApplication/HappyFenClient.zip"lastver=""size="24576"needRestart="true"/><filepath="NetworkProvider.dll"url="/CompanyClientApplication/NetworkProvider.zip"lastver=""size="32768"needRestart="true"/><filepath="Utility.dll"url="/CompanyClientApplication/Utility.zip"lastver=""size="20480"needRestart="true"/><filepath="Wizard.dll"url="/CompanyClientApplication/Wizard.zip"lastver=""size="24576"needRestart="true"/></updateFiles>同時,客戶端也保存了一個需要升級的本地文件的列表,形式和服務(wù)器配置文件差不多,我們叫它本地配置文件。其中,<Enable>節(jié)點表示是否啟用自動升級功能,<ServerUrl>表示服務(wù)器配置文件的地址。update.config<?xmlversion="1.0"encoding="utf-8"?><Configxmlns:xsi="/2001/XMLSchema-instance"xmlns:xsd="/2001/XMLSchema"><Enabled>true</Enabled><ServerUrl>/updateservice.xml</ServerUrl><UpdateFileList><LocalFilepath="AutoUpdater.dll"lastver=""size="28672"/><LocalFilepath="CompanyClient.exe"lastver=""size="888832"/><LocalFilepath="HappyFenClient.dll"lastver=""size="24576"/><LocaIFilepath="NetworkProvider.dll"lastver=""size="32768"/><LocalFilepath="Utility.dll"lastver=""size="20480"/><LocalFilepath="Wizard.dll"lastver=""size="24576"/></UpdateFileList></Config>使用自動各級組件的程序在啟動時,會去檢查這個配置文件。如果發(fā)現(xiàn)有配置文件中的文件版本和本地配置文件中描述的文件版本不一致,則提示用戶下載。同時,如果本地配置文件中某些文件在服務(wù)器配置文件的文件列表中不存在,則說明這個文件已經(jīng)不需要了,需要刪除。最后,當(dāng)升級完成后,會更新本地配置文件。我們先來看一下如何使用這個組件。在程序的Program.cs的Main函數(shù)中:[STAThread]staticvoidMain()(Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);AutoUpdaterau=newAutoUpdater();try(au.Update();)catch(WebExceptionexp)(MessageBox.Show(String.Format("無法找到指定資源\n\n{0}",exp.Message),"自動升級",MessageBoxButtons.OK,MessageBoxIcon.Error);}catch(XmlExceptionexp){MessageBox.Show(String.Format("下載的升級文件有錯誤\n\n{0}",exp.Message),"自動升級",MessageBoxButtons.OK,MessageBoxIcon.Error);}catch(NotSupportedExceptionexp){MessageBox.Show(String.Format("升級地址配置錯誤\n\n{0}",exp.Message),"自動升級",MessageBoxButtons.OK,MessageBoxIcon.Error);

)catch(ArgumentExceptionexp)(MessageBox.Show(String.Format("下載的升級文件有錯誤\n\n{0}",exp.Message),"自動升級",MessageBoxButtons.OK,MessageBoxIcon.Error);}catch(Exceptionexp){MessageBox.Show(String.Format("升級過程中發(fā)生錯誤\n\n{0}",exp.Message),"自動升級",MessageBoxButtons.OK,MessageBoxIcon.Error);Application.Run(newMainUI());如上所示,只需要簡單的幾行代碼,就可以實現(xiàn)自動升級功能了。軟件運行截圖:以下交件需要更新:交件名800032最新版本交件名800032CompanyClient.exe以后再說下面,我們來詳細(xì)說一下這個自動升級組件的實現(xiàn)。先看一下類圖:-立圉^utoUpdater+_|ProjectReferences-lyond.Utility+“拓弓AutoUpdater+?詼Config+“&寸弓DownloadConNrm+”"弓DownloadFilelnfo+“&寸弓DownloadProgress+,盤DownloadProgress.ExitCallBack+,盤DownloadProgress.5etProcessBarCal舊弓匚k+乏盤DownloadProgress.5howCurrentDownloadFileNameCal舊mck.+?&七LocalFile+?詼RemoteFile+■&;|5howHandler+?曾衫UpdateFileListAutoUpdater:自動升級的管理類,負(fù)責(zé)整體的自動升級功能的實現(xiàn)。Config:配置類,負(fù)責(zé)管理本地配置文件。DownloadConfirm:一個對話框,向用戶顯示需要升級的文件的列表,并允許用戶選擇是否馬上升級。DownloadFileInfo:要下載的文件的信息DownloadProgress:一個對話框,顯示下載進(jìn)度。DownloadProgress.ExitCallBack,DownloadProgress.SetProcessBarCallBack,DownloadProgress.ShowCurrentDownloadFileNameCallBack:由于.NET2.0不允許在一個線程中訪問另一個線程的對象,所以需要通過委托來實現(xiàn)。LocalFile:表示本地配置文件中的一個文件RemoteFile:表示服務(wù)器配置文件中的一個文件。UpdateFileList:一個集合,從List<LocalFile>繼承我們先整體看一下AutoUpdater.cs:isconststringFILENAME="update.config";privateConfigconfig=null;privateboolbNeedRestart=false;publicAutoUpdater()(config=Config.LoadConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,FILENAME));)/**////<summary>///檢查新版本///</summary>///<exceptioncref="System.Net.WebException">無法找到指定資源</exception>///<exceptioncref="System.NotSupportException">升級地址配置錯誤</exception>///<exceptioncref="System.Xml.XmlException">下載的升級文件有錯誤</exception>///<exceptioncref="System.ArgumentException">下載的升級文件有錯誤</exception>///<exceptioncref="System.Excpetion">未知錯誤</exception>///<returns></returns>publicvoidUpdate()(if(!config.Enabled)return;/**//**請求Web服務(wù)器,得到當(dāng)前最新版本的文件列表,格式同本地的FileList.xml。*與本地的FileList.xml比較,找到不同版本的文件*生成一個更新文件列表,開始DownloadProgress<UpdateFile><Filepath=""url=""lastver=""size=""></File></UpdateFile>path為相對于應(yīng)用程序根目錄的相對目錄位置,包括文件名*/WebClientclient=newWebClient();stringstrXml=client.DownloadString(config.ServerUrl);Dictionary<string,RemoteFile>listRemotFile=ParseRemoteXml(strXml);List<DownloadFileInfo>downloadList=newList<DownloadFileInfo>();〃某些文件不再需要了,刪除List<LocalFile>preDeleteFile=newList<LocalFile>();foreach(LocalFilefileinconfig.UpdateFileList)(if(listRemotFile.ContainsKey(file.Path))(RemoteFilerf=listRemotFile[file.Path];if(rf.LastVer!=file.LastVer)(downloadList.Add(newDownloadFileInfo(rf.Url,file.Path,rf.LastVer,rf.Size));file.LastVer=rf.LastVer;file.Size=rf.Size;if(rf.NeedRestart)bNeedRestart=true;)listRemotFile.Remove(file.Path);)else(preDeleteFile.Add(file);))foreach(RemoteFilefileinlistRemotFile.Values)(downloadList.Add(newDownloadFileInfo(file.Url,file.Path,file.LastVer,file.Size));config.UpdateFileList.Add(newLocalFile(file.Path,file.LastVer,file.Size));if(file.NeedRestart)bNeedRestart=true;)if(downloadList.Count>0)(DownloadConfirmdc=newDownloadConfirm(downloadList);if(this.OnShow!=null)this.OnShow();if(DialogResult.OK==dc.ShowDialog())(foreach(LocalFilefileinpreDeleteFile)(stringfilePath=Path.Combine(AppDomain.CurrentDomain.BaseDirectory,file.Path);if(File.Exists(filePath))File.Delete(filePath);config.UpdateFileList.Remove(file);)StartDownload(downloadList);)))privatevoidStartDownload(List<DownloadFileInfo>downloadList)(DownloadProgressdp=newDownloadProgress(downloadList);if(dp.ShowDialog()==DialogResult.OK)(〃更新成功config.SaveConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,FILENAME));if(bNeedRestart)(MessageBox.Show("程序需要重新啟動才能應(yīng)用更新,請點擊確定重新啟動程序。","自動更新",MessageBoxButtons.OK,MessageBoxIcon.Information);Process.Start(Application.ExecutablePath);Environment.Exit(0);)))privateDictionary<string,RemoteFile>ParseRemoteXml(stringxml)(XmlDocumentdocument=newXmlDocument();document.LoadXml(xml);Dictionary<string,RemoteFile>list=newDictionary<string,RemoteFile>();foreach(XmlNodenodeindocument.DocumentElement.ChildNodes)(list.Add(node.Attributes["path"].Value,newRemoteFile(node));)returnlist;)publiceventShowHandlerOnShow;)在構(gòu)造函數(shù)中,我們先要加載配置文件:publicAutoUpdater()(config=Config.LoadConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,FILENAME));)最主要的就是Update()這個函數(shù)了。當(dāng)程序調(diào)用au.Update時,首先檢查當(dāng)前是否開戶了自動更新:if(!config.Enabled)return;如果啟用了自動更新,就需要去下載服務(wù)器配置文件了:WebClientclient=newWebClient();stringstrXml=client.DownloadString(config.ServerUrl);然后,解析服務(wù)器配置文件到一個Dictionary中:Dictionary<string,RemoteFile>listRemotFile=ParseRemoteXml(strXml);接下來比較服務(wù)器配置文件和本地配置文件,找出需要下載的文件和本地需要刪除的文件:List<DownloadFileInfo>downloadList=newList<DownloadFileInfo>();〃某些文件不再需要了,刪除List<LocalFile>preDeleteFile=newList<LocalFile>();foreach(LocalFilefileinconfig.UpdateFileList)(if(listRemotFile.ContainsKey(file.Path))(RemoteFilerf=listRemotFile[file.Path];if(rf.LastVer!=file.LastVer)(downloadList.Add(newDownloadFileInfo(rf.Url,file.Path,rf.LastVer,rf.Size));file.LastVer=rf.LastVer;file.Size=rf.Size;if(rf.NeedRestart)bNeedRestart=true;)listRemotFile.Remove(file.Path);)else(preDeleteFile.Add(file);)foreach(RemoteFilefileinlistRemotFile.Values)(downloadList.Add(newDownloadFileInfo(file.Url,file.Path,file.LastVer,file.Size));config.UpdateFileList.Add(newLocalFile(file.Path,file.LastVer,file.Size));if(file.NeedRestart)bNeedRestart=true;)如果發(fā)現(xiàn)有需要下載的文件,則向用戶顯示這些文件,并提示其是否馬上更新。如果用戶選擇了馬上更新,則先刪除本地不再需要的文件,然后開始下載更新文件。if(downloadList.Count>0)DownloadConfirmdc=newDownloadConfirm(downloadList);if(this.OnShow!=null)this.OnShow();if(DialogResult.OK==dc.ShowDialog())foreach(LocalFilefileinpreDeleteFile)Lath=Pat5……eD…);if(File.Exists(filePath))File.Delete(filePath);config.UpdateFileList.Remove(file);一我們再來看一下StartDownload函數(shù)privatevoidStartDownload(List<DownloadFileInfo>downloadList)(DownloadProgressdp=newDownloadProgress(downloadList);if(dp.ShowDialog()==DialogResult.OK)(〃更新成功config.SaveConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,FILENAME));if(bNeedRestart)(MessageBox.Show("程序需要重新啟動才能應(yīng)用更新,請點擊確定重新啟動程序。","自動更新",MessageBoxButtons.OK,MessageBoxIcon.Information);Process.Start(Application.ExecutablePath);Environment.Exit(0);)))在這個函數(shù)中,先調(diào)用DownloadProgress下載所有需要下載的文件,然后更新本地配置文件,最后,如果發(fā)現(xiàn)某些更新文件需要重新啟動應(yīng)用程序的話,會提示用戶重新啟動程序。至此,AutoUpdater這個類的使命就完成了,其實,整個的升級過程也就完成了。(廢話)。最后,我們來看一下這個組件是如何下載更新文件的usingSystem;usingSystem.Collections.Generic;usingSystem.ComponentModel;usingSystem.Data;usingSystem.Drawing;usingSystem.Text;usingSystem.Windows.Forms;usingSystem.Threading;usingSystem.Net;usingSystem.IO;usingSystem.Diagnostics;namespacelyond.Utility(publicpartialclassDownloadProgress:Form(privateboolisFinished=false;privateList<DownloadFileInfo>downloadFileList=null;privateManualResetEventevtDownload=null;privateManualResetEventevtPerDonwload=null;privateWebClientclientDownload=null;publicDownloadProgress(List<DownloadFileInfo>downloadFileList)(InitializeComponent();this.downloadFileList=downloadFileList;)privatevoidOnFormClosing(objectsender,FormClosingEventArgse)(if(!isFinished&&DialogResult.No==MessageBox.Show("當(dāng)前正在更新,是否取消?","自動升級",MessageBoxButtons.YesNo,MessageBoxIcon.Question))(e.Cancel=true;return;)else(if(clientDownload!=null)clientDownload.CancelAsync();evtDownload.Set();evtPerDonwload.Set();))privatevoidOnFormLoad(objectsender,EventArgse){i=new_t(true);evtDownload.Reset();Threadt=newThread(newThreadStart(ProcDownload));t.Name="download";t.Start();longtotal=0;longnDownloadedTotal=0;…dP—evtPerDonwload=newManualResetEvent(false);5(Dow_st)total+=file.Size;_)if(this.downloadFileList.Count==0)break;DownloadFileInfofile=this.downloadFileList[0];//Debug.WriteLine(String.Format("StartDownload:{0}",file.FileName));this.ShowCurrentDownloadFileName(file.FileName);〃下載clientDownload=newWebClient();clientDownload.DownloadProgressChanged+=newDownloadProgressChangedEventHandler(OnDownloadProgressChanged);clientDownload.DownloadFileCompleted+=newAsyncCompletedEventHandler(OnDownloadFileCompleted);evtPerDonwload.Reset();clientDownload.DownloadFileAsync(newUri(file.DownloadUrl),Path.Combine(AppDomain.CurrentDomain.BaseDirectory,file.FileFullName+".tmp"),file);〃等待下載完成evtPerDonwload.WaitOne();clientDownload.Dispose();clientDownload=null;〃移除已下載的文件this.downloadFileList.Remove(file);)//Debug.WriteLine("AllDownloaded");if(this.downloadFileList.Count==0)Exit(true);elseExit(false);evtDownload.Set();)voidOnDownloadFileCompleted(objectsender,AsyncCompletedEventArgse)(DownloadFileInfofile=e.UserStateasDownloadFileInfo;nDownloadedTotal+=file.Size;this.SetProcessBar(0,(int)(nDownloadedTotal*100/total));//Debug.WriteLine(String.Format("FinishDownload*。}",file.FileName));〃替換現(xiàn)有文件stringfilePath=Path.Combine(AppDomain.CurrentDomain.BaseDirectory,file.FileFullName);if(File.Exists(filePath))(if(File.Exists(filePath+".old"))File.Delete(filePath+".old");File.Move(filePath,filePath+".old");)File.Move(filePath+".tmp",filePath);〃繼續(xù)下載其它文件evtPerDonwload.Set();)voidOnDownloadProgressChanged(objectsender,DownloadProgressChangedEventArgse)(this.SetProcessBar(e.ProgressPercentage,(int)((nDownloadedTotal+e.BytesReceived)*100/total));)delegatevoidShowCurrentDownloadFileNameCallBack(stringname);privatevoidShowCurrentDownloadFileName(stringname)(if(this.labelCurrentItem.InvokeRequired)(ShowCurrentDownloadFileNameCallBackcb=newShowCurrentDownloadFileNameCallBack(ShowCurrentDownloadFileName);this.Invoke(cb,newobject[](name});)else(this.labelCurrentItem.Text=name;}}delegatevoidSetProcessBarCallBack(intcurrent,inttotal);privatevoidSetProcessBar(intcurrent,inttotal)g_{廣…,5_);elseI5「,_delegatevoidExitCallBack(boolsuccess);……)—d)ExitCallBackcb=newExitCallBack(Exit);this.Invoke(cb,newobject[]{success});elsethis.isFinished=success;this.DialogResult=success?DialogResult.OK:DialogResult.Cancel;this.Close();——)'_,,…在構(gòu)造函數(shù)中,將要下載的文件列表傳進(jìn)來publicDownloadProgress(List<DownloadFileInfo>downloadFileList){_.._在Form的Load事件中,啟動下載線程,開始下載。privatevoidOnFormLoad(objectsender,EventArgse)(evtDownload=newManualResetEvent(true);evtDownload.Reset();Threadt=newThread(newThreadStart(ProcDownload));t.Name="download";t.Start();)下載線程沒什么特殊的,使用了WebClient的異步下載文件函數(shù)DownloadFileAsync,并且注冊了兩個事件,分別負(fù)責(zé)下載進(jìn)度顯示和下載完成后的處理:clientDownload.DownloadProgressChanged+=newDownloadProgressChangedEventHandler(OnDownloadProgressChanged);clientDownload.DownloadFileCompleted+=newAsyncCompletedEventHandler(OnDownloadFileCompleted);大家看一下就明白了。privatevoidProcDownload()(evtPerDonwload=newManualResetEvent(false);foreach(DownloadFileInfofileinthis.downloadFileList)(total+=file.Size;)while(!evtDownload.WaitOne(0,false))(if(this.downloadFileList.Count==0)break;DownloadFileInfofile=this.downl

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論