在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),請進行舉報或認領(lǐng)

文檔簡介

最近單位開發(fā)一個項目,其中需要用到自動升級功能。因為自動升級是一個比較常用的功能,可能會在很多程序中用到,于是,我就想寫一個自動升級的組件,在應(yīng)用程序中,只需要引用這個自動升級組件,并添加少量代碼,即可實現(xiàn)自動升級功能。因為我們的程序中可能包含多個exe或者dll文件,所以要支持多文件的更新。首先,要確定程序應(yīng)該去哪里下載需要升級的文件。我選擇了到指定的網(wǎng)站上去下載,這樣比較簡單,也通用一些。在這個網(wǎng)站上,需要放置一個當前描述最新文件列表的文件,我們估且叫它服務(wù)器配置文件。這個文件保存了當前最新文件的版本號(lastver),大小(size),下載地址(url),本地文件的保存路徑(path),還有當更新了這個文件后,程序是否需要重新啟動(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)不需要了,需要刪除。最后,當升級完成后,會更新本地配置文件。我們先來看一下如何使用這個組件。在程序的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以后再說下面,我們來詳細說一下這個自動升級組件的實現(xiàn)。先看一下類圖:-立圉^utoUpdater+_|ProjectReferences-lyond.Utility+“拓弓AutoUpdater+?詼Config+“&寸弓DownloadConNrm+”"弓DownloadFilelnfo+“&寸弓DownloadProgress+,盤DownloadProgress.ExitCallBack+,盤DownloadProgress.5etProcessBarCal舊弓匚k+乏盤DownloadProgress.5howCurrentDownloadFileNameCal舊mck.+?&七LocalFile+?詼RemoteFile+■&;|5howHandler+?曾衫UpdateFileListAutoUpdater:自動升級的管理類,負責整體的自動升級功能的實現(xiàn)。Config:配置類,負責管理本地配置文件。DownloadConfirm:一個對話框,向用戶顯示需要升級的文件的列表,并允許用戶選擇是否馬上升級。DownloadFileInfo:要下載的文件的信息DownloadProgress:一個對話框,顯示下載進度。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ù)器,得到當前最新版本的文件列表,格式同本地的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ù)了。當程序調(diào)用au.Update時,首先檢查當前是否開戶了自動更新: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("當前正在更新,是否取消?","自動升級",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ù)中,將要下載的文件列表傳進來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,并且注冊了兩個事件,分別負責下載進度顯示和下載完成后的處理: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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論