標籤:des blog http io os 使用 ar strong for
一、自動更新的實現
讓用戶端實現自動更新,通常做法是在用戶端部署一個單獨的自動更新程式。主程式啟動後,訪問服務端,檢查設定檔是
否有更新版本,有更新版本就啟動更新程式,由更新負責下載更新版本,並更新用戶端程式,流程如下:
當流程進行到紅色部分的是後就調用更新程式進行更新。
1)版本判斷:
用戶端和服務端都部署同一個版本檔案,用戶端登陸時發送驗證給服務端判斷版本是否一致。
Version.xml代碼
<iq xmlns="http://www.dynastech.com/xmtp" from="*@domcool.local/updater" to="*@domcool.local/updater" type="get"
id="508f3e88-4bb0-4585-a5c6-cc41ef57fef3"> <query xmlns="http://www.dynastech.com/xmtp/disco#update" version="20090922" lastUpdateTime="2009-09-22"
fileUrl="http://172.0.0.1/UCCompanion/UCCompanionSetup(0922).zip <">x xmlns="http://www.dynastech.com/xmtp/item"> </x> </query></iq>
版本檔案主要比較服務端Version.xml檔案和用戶端Version.xml檔案中Version(版本號碼)是否一致,如果服務端Version屬性
大於用戶端的Version屬性,則通過服務端的fileUrl屬性擷取新版本的。供更新程式使用。
2)刪除原有更新包
所有用戶端更新檔案均下載到C:\Documents and Settings\目前使用者名\Local Settings\Temp 檔案夾內,當用戶端運行後首先判
斷是否有新更新包需要下載,如果沒有則判斷該臨時檔案夾內是否有舊有安裝檔案,如果存在,則刪除舊有安裝檔案。
private void RemoveOldSetupFile() { try { string temp = System.Environment.GetEnvironmentVariable("TEMP"); string folder = new DirectoryInfo(temp).FullName; if (File.Exists(folder + @"\" + setupName + ".exe")) { File.Delete(folder + @"\" + setupName + ".exe"); } if (File.Exists(folder + @"\" + setupName + ".msi")) { File.Delete(folder + @"\" + setupName + ".msi"); } } catch { } }
備忘:關於擷取系統特殊檔案夾的方法見部落格http://www.cnblogs.com/thornfield_he/archive/2009/09/22/1571719.html
3)啟動下載程式
下載程式和用戶端程式是相互獨立的,可以通過用戶端開啟新線程啟動下載程式。下載程式在檔案下載結束後可以關掉用戶端程式,
並開啟新線程啟動安裝程式進行安裝。
private void Update(){ if (ShouldUpdate(query.Version, this.version)) { MessageBox.Show("請更新用戶端檔案到版本[" + query.Version + "]", "更新提示", MessageBoxButtons.OK,
MessageBoxIcon.Asterisk); System.Diagnostics.Process.Start(Application.StartupPath + @"\AutoUpdater.exe", query.FileUrl); } else { RemoveOldSetupFile(); }}private bool ShouldUpdate(string serverVersion, string localVersion){ if (!string.IsNullOrEmpty(serverVersion) && !string.IsNullOrEmpty(localVersion)) { return serverVersion.CompareTo(localVersion) > 0; } return true;}
調用AutoUpdater.exe檔案時需要傳入檔案。
System.Diagnostics.Process.Start(Application.StartupPath + @"\AutoUpdater.exe", query.FileUrl);
4)下載程式代碼
下載程式介面
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Net;using System.IO;using System.Threading;using System.Diagnostics;namespace AutoUpdater{ public partial class MainForm : Form { private WebClient client; private string URl; private string fileName; private string path; private const string applicationFile = "Setup"; public MainForm(string url) { InitializeComponent(); this.URl = url; client = new WebClient(); client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged); client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted); client.Proxy = WebRequest.DefaultWebProxy; client.Proxy.Credentials = new NetworkCredential(); this.Hide(); //Thread thread = new Thread(UpdateFile); //Thread.Sleep(15000); //thread.Start(); UpdateFile(); } public MainForm() { InitializeComponent(); } /// <summary> /// 下載完成調用 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) { label1.Text = "檔案接收完成"; UnZip(); RunUpdate(); } /// <summary> /// 下載進度條 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) { this.progressBar1.Value = e.ProgressPercentage; } /// <summary> /// 開始下載 /// </summary> private void StartDownload() { fileName = URl.Substring(URl.LastIndexOf("/") + 1, URl.Length - URl.LastIndexOf("/") - 1); path = GetTempFolder(); try { WebRequest myre = WebRequest.Create(URl); } catch (Exception ex) { MessageBox.Show(ex.Message, "Error"); } try { label1.Text = "開始下載檔案..."; client.DownloadFileAsync(new Uri(URl), path + @"\" + fileName); } catch (WebException exp) { label1.Text = exp.Message; } } /// <summary> /// 解壓壓縮包,格式必須是*.zip,否則不能解壓 /// 因為是調用Windows內部api進行解壓,只能夠識別zip壓縮包 /// 必須添加C:\WINDOWS\system32\shell32.dll的引用 /// </summary> private void UnZip() { try { Shell32.ShellClass sc = new Shell32.ShellClass(); Shell32.Folder SrcFolder = sc.NameSpace(this.path + @"\" + this.fileName); Shell32.Folder DestFolder = sc.NameSpace(this.path); Shell32.FolderItems items = SrcFolder.Items(); DestFolder.CopyHere(items, 20); } catch (Exception ex) { MessageBox.Show(ex.Message); } } /// <summary> /// 擷取下載檔案夾地址及解壓檔案存放地址 /// 此地址預設為C:\Documents and Settings\目前使用者名\Local Settings\Temp 檔案夾 /// </summary> /// <returns></returns> private string GetTempFolder() { string folder = System.Environment.GetEnvironmentVariable("TEMP"); return new DirectoryInfo(folder).FullName; } /// <summary> /// 開始下載檔案 /// </summary> private void UpdateFile() { this.Hide(); //如果臨時檔案夾存在setup安裝檔案,就直接調用安裝檔案 if (File.Exists(GetTempFolder() + @"\" + applicationFile + ".exe") && File.Exists(GetTempFolder() +
@"\" + applicationFile + ".msi")) { label1.Text = "開始下載檔案..."; this.progressBar1.Value = this.progressBar1.Maximum; label1.Text = "檔案接收完成"; RunUpdate(); } //如果臨時檔案夾不存在setup安裝檔案,就從網路下載 else { RemoveSetupFile(); StartDownload(); } } /// <summary> /// 清除舊有已下載的安裝檔案 /// </summary> private static void RemoveSetupFile() { try { string temp = System.Environment.GetEnvironmentVariable("TEMP"); string folder = new DirectoryInfo(temp).FullName; if (File.Exists(folder + @"\" + applicationFile + ".exe")) { File.Delete(folder + @"\" + applicationFile + ".exe"); } if (File.Exists(folder + @"\" + applicationFile + ".msi")) { File.Delete(folder + @"\" + applicationFile + ".msi"); } } catch { } } /// <summary> /// 下載完畢,開始執行更新程式 /// </summary> private void RunUpdate() { try { foreach (Process p in Process.GetProcesses()) { if (p.ProcessName.ToLower().StartsWith("uccompanion")) { if (MessageBox.Show("UCCompanion正在運行,是否關閉當前程式安裝更新?", "安裝UCCompanion",
MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { p.Kill(); Process.Start(GetTempFolder() + @"\" + applicationFile + ".exe"); } else { MessageBox.Show("UCCompanion下載完成,將在下次啟動時提醒更新!"); } } } } catch (Exception ex) { MessageBox.Show(ex.Message); } finally { this.Close(); } } /// <summary> /// 重載WindProc判斷點擊關閉按鈕(X)時,隱藏程式介面 /// </summary> /// <param name="msg"></param> protected override void WndProc(ref Message msg) { const int WM_SYSCOMMAND = 0x0112; const int SC_CLOSE = 0xF060; if (msg.Msg == WM_SYSCOMMAND && ((int)msg.WParam == SC_CLOSE)) { this.Hide(); return; } base.WndProc(ref msg); } /// <summary> /// 雙擊表徵圖彈出介面 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void icon_notify_MouseDoubleClick(object sender, MouseEventArgs e) { this.Show(); this.WindowState = FormWindowState.Normal; } /// <summary> /// /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MainForm_SizeChanged(object sender, EventArgs e) { if (this.WindowState == FormWindowState.Minimized) { this.Hide(); } } private void MainForm_Load(object sender, EventArgs e) { this.Hide(); } } static class Program { /// <summary> /// 啟動,接收傳入網址作為參數 /// </summary> /// <param name="agr"></param> [STAThread] static void Main(string[] agr) { if (agr.Length == 1 && agr[0].StartsWith(@"http://")) { MainForm form = new MainForm(agr[0]); Application.Run(form); } } }}
程式碼
將AutoUpdater項目產生的檔案添加到用戶端檔案中,在用戶端的Update()方法裡調用updater,實現更新檔案的下載。
以上就已經實現了自動更新功能,下面將討論檔案安裝包的製作。
二、安裝包的製作
1)建立安裝項目
2)滑鼠右擊Setup項目選擇>視圖,可以看到製作安裝包常見的視圖有以下幾個
最常用的視圖有“檔案系統”,“使用者介面”和“啟動條件”。
3)指定安裝屬性
滑鼠左鍵單擊項目名稱,記住是左鍵單擊,然後點擊屬性標籤,注意:不是右擊的屬性
a.需要注意的是Version屬性,每次版本更新時Version值必須後面的版本大於前面的版本。每次更改Version值時Projectcode會更改一次。
其中你修改安裝項目的版本號碼時,比如從v1.00 到1.01,在你再次產生項目的時候,會提示你是否允許修改ProductCode,選擇"是",
程式會自動修改ProductCode,選擇否將保持相同的ProductCode,即不能自動卸載舊的版本.
b.在以後版本中要確認和以前的版本兩個版本有不同的ProductCode和相同的UpgradeCode
c.manufacturer屬性指定製造商名稱。
d.detectnewerinstalledversion屬性選擇為true,
e.removepreviousversions選擇為true
滑鼠左鍵單擊項目名稱,此次是按右鍵,然後點擊屬性,彈出屬性頁面,選擇“系統必備”。
在開啟的系統必備頁中,選中如下中的選擇項,這個很重要!!!!!1!!!!!選上以後,在產生的安裝檔案包中
包含.netframework組件.(這個選項預設是沒有選中的)。
4)檔案系統視圖
檔案系統視圖左側根目錄樹下有3個子節點。
a.應用程式檔案夾:將所有待打包的應用程式的可執行檔和相應的類庫和組件拖動到該目錄下。該目錄可以建立子
目錄,項目安裝完畢以後的檔案夾結構會和該目錄下結構一致。
然後右擊左邊的"應用程式檔案夾"開啟屬性對話方塊,修改檔案釋放路徑,[ProgramFilesFolder][Manufacturer]\[ProductName]。
安裝程式預設安裝目錄會是"c:\programm file\製造商名稱\安裝解決方案名稱";
b.使用者的“程式”菜單和使用者案頭:用於在開始菜單建立檔案捷徑
在應用程式檔案夾中將需要產生的捷徑的檔案添加捷徑並拖動到使用者的“程式”菜單和使用者案頭
c.添加檔案卸載功能
在添加你的應用程式項目的時候,多添加一個msiexec.exe進去,這個檔案在c:\windows\system32檔案夾下。
為其在程式菜單添加一個捷徑,把他的名字改成"Uninstall.exe",指定Icon捷徑顯示的表徵圖。然後下面我們
要的做的就是尋找這個部署項目的ProductCode了,滑鼠左鍵單擊項目名稱,記住是左鍵單擊,然後點擊屬性標籤,注意:
不是右擊的屬性,這個區別很大,這時你就可以看到ProductCode了
然後開啟你建立的那個卸載程式的捷徑的屬性對話方塊,在Aguements屬性中輸入"/x {ProductCode}"
5)使用者介面視圖
在“歡迎使用”後,“安裝資料夾”前添加“許可協議”對話方塊。
licensefile選擇協議,協議的格式為rtf。
6)啟動條件視圖
為啟動安裝程式制定最低framework要求。
7)實現安裝、卸載過程中的其他額外的操作。比如安裝結束後啟動程式,卸載程式後同時刪除網路下載打安裝包等功能。
a.建立一個空的項目InstallCompenent,步驟為:解決方案->右鍵添加->建立項目->選擇"空項目"->
輸入名稱"InstallCompenent"->確定,完成項目的添加.
b.在InstallCompenent項目中右鍵->添加->建立項->選擇安裝程式類->輸入名稱"Installer",完成installer類的添加.
修改代碼為:
using System;using System.Collections;using System.Collections.Generic;using System.ComponentModel;using System.Configuration.Install;using System.Reflection;using System.IO;namespace InstallCompenent{ [RunInstaller(true)] public partial class UccompanionInstaller : Installer { private const string zipPacket = "UCCompanionSetup(0918).zip"; /// <summary> /// 應用程式入口 /// </summary> public static void Main() { } /// <summary> /// 建構函式 /// </summary> public UccompanionInstaller() { InitializeComponent(); } /// <summary> /// 重寫安裝完成後函數 /// 實現安裝完成後自動啟動已安裝的程式 /// </summary> /// <param name="savedState"></param> protected override void OnAfterInstall(IDictionary savedState) { base.OnAfterInstall(savedState); Assembly asm = Assembly.GetExecutingAssembly(); string path = asm.Location.Remove(asm.Location.LastIndexOf("\\")) + "\\"; System.Diagnostics.Process.Start(path + "\\UCCompanion.exe"); } /// <summary> /// 重寫安裝過程方法 /// </summary> /// <param name="stateSaver"></param> public override void Install(IDictionary stateSaver) { base.Install(stateSaver); } /// <summary> /// 重寫安裝之前方法 /// </summary> /// <param name="savedState"></param> protected override void OnBeforeInstall(IDictionary savedState) { base.OnBeforeInstall(savedState); } /// <summary> /// 重寫卸載方法 /// 卸載程式後也刪除程式的安裝包 /// </summary> /// <param name="savedState"></param> public override void Uninstall(IDictionary savedState) { string temp = System.Environment.GetEnvironmentVariable("TEMP"); string folder = new DirectoryInfo(temp).FullName; if (File.Exists(folder + @"\setup.exe")) { File.Delete(folder + @"\setup.exe"); } if (File.Exists(folder + @"\setup.msi")) { File.Delete(folder + @"\setup.msi"); } if (File.Exists(folder + @"\"+zipPacket)) { File.Delete(folder + @"\"+zipPacket); } base.Uninstall(savedState); } /// <summary> /// 重寫復原方法 /// </summary> /// <param name="savedState"></param> public override void Rollback(IDictionary savedState) { base.Rollback(savedState); } }}
c.在安裝項目中右鍵->添加項目輸出->選擇"項目"->InstallCompenent.完成主輸出項目的添加.
d.開啟自訂動作編輯器,在安裝->右鍵->添加自訂動作->選擇"應用程式檔案夾"->選擇"主輸出來自InstallCompenent",完成添加.
好了,點擊“產生解決方案”,即可以產生帶有卸載功能的安裝程式了。
轉自:http://blog.csdn.net/myhuli120/article/details/6927588
c#自動更新+安裝程式的製作