一、自动更新的实现

让客户端实现自动更新,通常做法是在客户端部署一个单独的自动更新程序。主程序启动后,访问服务端,检查配置文件是
否有更新版本,有更新版本就启动更新程序,由更新负责下载更新版本,并更新客户端程序,流程如下:

当流程进行到红色部分的是后就调用更新程序进行更新。

1)版本判断:

客户端和服务端都部署同一个版本文件,客户端登陆时发送验证给服务端判断版本是否一致。

Version.xml代码

  1. <iq xmlns="http://www.dynastech.com/xmtp" from="*@domcool.local/updater" to="*@domcool.local/updater" type="get"
  1. id="508f3e88-4bb0-4585-a5c6-cc41ef57fef3">
  2. <query xmlns="http://www.dynastech.com/xmtp/disco#update" version="20090922" lastUpdateTime="2009-09-22"
  1. fileUrl="http://172.0.0.1/UCCompanion/UCCompanionSetup(0922).zip <">
  2. x xmlns="http://www.dynastech.com/xmtp/item">
  3. </x>
  4. </query>
  5. </iq>
  1. 版本文件主要比较服务端Version.xml文件和客户端Version.xml文件中Version(版本号)是否一致,如果服务端Version属性
  1. 大于客户端的Version属性,则通过服务端的fileUrl属性获取新版本的下载地址。供更新程序使用。
  1. 2)删除原有更新包
  1. 所有客户端更新文件均下载到C:\Documents and Settings\当前用户名\Local Settings\Temp 文件夹内,当客户端运行后首先判
  1. 断是否有新更新包需要下载,如果没有则判断该临时文件夹内是否有旧有安装文件,如果存在,则删除旧有安装文件。
  1. private void RemoveOldSetupFile()
  2. {
  3. try
  4. {
  5. string temp = System.Environment.GetEnvironmentVariable("TEMP");
  6. string folder = new DirectoryInfo(temp).FullName;
  7. if (File.Exists(folder + @"\" + setupName + ".exe"))
  8. {
  9. File.Delete(folder + @"\" + setupName + ".exe");
  10. }
  11. if (File.Exists(folder + @"\" + setupName + ".msi"))
  12. {
  13. File.Delete(folder + @"\" + setupName + ".msi");
  14. }
  15. }
  16. catch { }
  17.  
  18. }

备注:关于获取系统特殊文件夹的方法见博客http://www.cnblogs.com/thornfield_he/archive/2009/09/22/1571719.html

3)启动下载程序

下载程序和客户端程序是相互独立的,可以通过客户端开启新线程启动下载程序。下载程序在文件下载结束后可以关掉客户端程序,
并开启新线程启动安装程序进行安装。

  1. private void Update()
  2. {
  3. if (ShouldUpdate(query.Version, this.version))
  4. {
  5. MessageBox.Show("请更新客户端文件到版本[" + query.Version + "]", "更新提示", MessageBoxButtons.OK,
  1. MessageBoxIcon.Asterisk);
  2. System.Diagnostics.Process.Start(Application.StartupPath + @"\AutoUpdater.exe", query.FileUrl);
  3. }
  4. else { RemoveOldSetupFile(); }
  5. }
  6.  
  7. private bool ShouldUpdate(string serverVersion, string localVersion)
  8. {
  9. if (!string.IsNullOrEmpty(serverVersion) && !string.IsNullOrEmpty(localVersion))
  10. {
  11. return serverVersion.CompareTo(localVersion) > 0;
  12. }
  13. return true;
  14. }
  1. 调用AutoUpdater.exe文件时需要传入文件下载地址。
  1. System.Diagnostics.Process.Start(Application.StartupPath + @"\AutoUpdater.exe", query.FileUrl);
  1. 4)下载程序代码
  1. 下载程序界面
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Text;
  7. using System.Windows.Forms;
  8. using System.Net;
  9. using System.IO;
  10. using System.Threading;
  11. using System.Diagnostics;
  12.  
  13. namespace AutoUpdater
  14. {
  15. public partial class MainForm : Form
  16. {
  17. private WebClient client;
  18. private string URl;
  19. private string fileName;
  20. private string path;
  21. private const string applicationFile = "Setup";
  22.  
  23. public MainForm(string url)
  24. {
  25. InitializeComponent();
  26.  
  27. this.URl = url;
  28. client = new WebClient();
  29. client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
  30. client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
  31. client.Proxy = WebRequest.DefaultWebProxy;
  32. client.Proxy.Credentials = new NetworkCredential();
  33.  
  34. this.Hide();
  35. //Thread thread = new Thread(UpdateFile);
  36. //Thread.Sleep(15000);
  37. //thread.Start();
  38. UpdateFile();
  39. }
  40.  
  41. public MainForm()
  42. {
  43. InitializeComponent();
  44. }
  45.  
  46. /// <summary>
  47. /// 下载完成调用
  48. /// </summary>
  49. /// <param name="sender"></param>
  50. /// <param name="e"></param>
  51. void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
  52. {
  53. label1.Text = "文件接收完成";
  54. UnZip();
  55. RunUpdate();
  56. }
  57.  
  58. /// <summary>
  59. /// 下载进度条
  60. /// </summary>
  61. /// <param name="sender"></param>
  62. /// <param name="e"></param>
  63. void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
  64. {
  65. this.progressBar1.Value = e.ProgressPercentage;
  66. }
  67.  
  68. /// <summary>
  69. /// 开始下载
  70. /// </summary>
  71. private void StartDownload()
  72. {
  73. fileName = URl.Substring(URl.LastIndexOf("/") + 1, URl.Length - URl.LastIndexOf("/") - 1);
  74. path = GetTempFolder();
  75.  
  76. try
  77. {
  78. WebRequest myre = WebRequest.Create(URl);
  79. }
  80. catch (Exception ex)
  81. {
  82. MessageBox.Show(ex.Message, "Error");
  83. }
  84.  
  85. try
  86. {
  87. label1.Text = "开始下载文件...";
  88. client.DownloadFileAsync(new Uri(URl), path + @"\" + fileName);
  89.  
  90. }
  91. catch (WebException exp)
  92. {
  93. label1.Text = exp.Message;
  94. }
  95. }
  96.  
  97. /// <summary>
  98. /// 解压压缩包,格式必须是*.zip,否则不能解压
  99. /// 因为是调用Windows内部api进行解压,只能够识别zip压缩包
  100. /// 必须添加C:\WINDOWS\system32\shell32.dll的引用
  101. /// </summary>
  102. private void UnZip()
  103. {
  104. try
  105. {
  106. Shell32.ShellClass sc = new Shell32.ShellClass();
  107. Shell32.Folder SrcFolder = sc.NameSpace(this.path + @"\" + this.fileName);
  108. Shell32.Folder DestFolder = sc.NameSpace(this.path);
  109. Shell32.FolderItems items = SrcFolder.Items();
  110. DestFolder.CopyHere(items, 20);
  111. }
  112. catch (Exception ex)
  113. {
  114. MessageBox.Show(ex.Message);
  115. }
  116. }
  117.  
  118. /// <summary>
  119. /// 获取下载文件夹地址及解压文件存放地址
  120. /// 此地址默认为C:\Documents and Settings\当前用户名\Local Settings\Temp 文件夹
  121. /// </summary>
  122. /// <returns></returns>
  123. private string GetTempFolder()
  124. {
  125. string folder = System.Environment.GetEnvironmentVariable("TEMP");
  126. return new DirectoryInfo(folder).FullName;
  127. }
  128.  
  129. /// <summary>
  130. /// 开始下载文件
  131. /// </summary>
  132. private void UpdateFile()
  133. {
  134. this.Hide();
  135. //如果临时文件夹存在setup安装文件,就直接调用安装文件
  136. if (File.Exists(GetTempFolder() + @"\" + applicationFile + ".exe") && File.Exists(GetTempFolder() +
  1. @"\" + applicationFile + ".msi"))
  2. {
  3. label1.Text = "开始下载文件...";
  4. this.progressBar1.Value = this.progressBar1.Maximum;
  5. label1.Text = "文件接收完成";
  6. RunUpdate();
  7. }
  8. //如果临时文件夹不存在setup安装文件,就从网络下载
  9. else
  10. {
  11. RemoveSetupFile();
  12. StartDownload();
  13. }
  14. }
  15.  
  16. /// <summary>
  17. /// 清除旧有已下载的安装文件
  18. /// </summary>
  19. private static void RemoveSetupFile()
  20. {
  21. try
  22. {
  23. string temp = System.Environment.GetEnvironmentVariable("TEMP");
  24. string folder = new DirectoryInfo(temp).FullName;
  25. if (File.Exists(folder + @"\" + applicationFile + ".exe"))
  26. {
  27. File.Delete(folder + @"\" + applicationFile + ".exe");
  28. }
  29. if (File.Exists(folder + @"\" + applicationFile + ".msi"))
  30. {
  31. File.Delete(folder + @"\" + applicationFile + ".msi");
  32. }
  33. }
  34. catch { }
  35. }
  36.  
  37. /// <summary>
  38. /// 下载完毕,开始执行更新程序
  39. /// </summary>
  40. private void RunUpdate()
  41. {
  42. try
  43. {
  44. foreach (Process p in Process.GetProcesses())
  45. {
  46. if (p.ProcessName.ToLower().StartsWith("uccompanion"))
  47. {
  48. if (MessageBox.Show("UCCompanion正在运行,是否关闭当前程序安装更新?", "安装UCCompanion",
  1. MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
  2. {
  3. p.Kill();
  4. Process.Start(GetTempFolder() + @"\" + applicationFile + ".exe");
  5. }
  6. else
  7. {
  8. MessageBox.Show("UCCompanion下载完成,将在下次启动时提醒更新!");
  9. }
  10. }
  11. }
  12.  
  13. }
  14. catch (Exception ex)
  15. {
  16. MessageBox.Show(ex.Message);
  17. }
  18. finally
  19. {
  20. this.Close();
  21. }
  22. }
  23.  
  24. /// <summary>
  25. /// 重载WindProc判断点击关闭按钮(X)时,隐藏程序界面
  26. /// </summary>
  27. /// <param name="msg"></param>
  28. protected override void WndProc(ref Message msg)
  29. {
  30. const int WM_SYSCOMMAND = 0x0112;
  31. const int SC_CLOSE = 0xF060;
  32.  
  33. if (msg.Msg == WM_SYSCOMMAND && ((int)msg.WParam == SC_CLOSE))
  34. {
  35. this.Hide();
  36. return;
  37. }
  38. base.WndProc(ref msg);
  39. }
  40.  
  41. /// <summary>
  42. /// 双击图标弹出界面
  43. /// </summary>
  44. /// <param name="sender"></param>
  45. /// <param name="e"></param>
  46. private void icon_notify_MouseDoubleClick(object sender, MouseEventArgs e)
  47. {
  48. this.Show();
  49. this.WindowState = FormWindowState.Normal;
  50. }
  51.  
  52. /// <summary>
  53. ///
  54. /// </summary>
  55. /// <param name="sender"></param>
  56. /// <param name="e"></param>
  57. private void MainForm_SizeChanged(object sender, EventArgs e)
  58. {
  59. if (this.WindowState == FormWindowState.Minimized)
  60. {
  61. this.Hide();
  62. }
  63. }
  64.  
  65. private void MainForm_Load(object sender, EventArgs e)
  66. {
  67. this.Hide();
  68. }
  69.  
  70. }
  71.  
  72. static class Program
  73. {
  74. /// <summary>
  75. /// 启动,接收传入网址作为参数
  76. /// </summary>
  77. /// <param name="agr"></param>
  78. [STAThread]
  79. static void Main(string[] agr)
  80. {
  81. if (agr.Length == 1 && agr[0].StartsWith(@"http://"))
  82. {
  83. MainForm form = new MainForm(agr[0]);
  84. Application.Run(form);
  85. }
  86. }
  87. }
  88. }

程序代码

将AutoUpdater项目生成的文件添加到客户端文件中,在客户端的Update()方法里调用updater,实现更新文件的下载。

  1. 以上就已经实现了自动更新功能,下面将讨论文件安装包的制作。

二、安装包的制作

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类的添加.

修改代码为:

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.ComponentModel;
  5. using System.Configuration.Install;
  6. using System.Reflection;
  7. using System.IO;
  8.  
  9. namespace InstallCompenent
  10. {
  11. [RunInstaller(true)]
  12. public partial class UccompanionInstaller : Installer
  13. {
  14. private const string zipPacket = "UCCompanionSetup(0918).zip";
  15. /// <summary>
  16. /// 应用程序入口
  17. /// </summary>
  18. public static void Main()
  19. {
  20. }
  21. /// <summary>
  22. /// 构造函数
  23. /// </summary>
  24. public UccompanionInstaller()
  25. {
  26. InitializeComponent();
  27. }
  28. /// <summary>
  29. /// 重写安装完成后函数
  30. /// 实现安装完成后自动启动已安装的程序
  31. /// </summary>
  32. /// <param name="savedState"></param>
  33. protected override void OnAfterInstall(IDictionary savedState)
  34. {
  35. base.OnAfterInstall(savedState);
  36. Assembly asm = Assembly.GetExecutingAssembly();
  37. string path = asm.Location.Remove(asm.Location.LastIndexOf("\\")) + "\\";
  38. System.Diagnostics.Process.Start(path + "\\UCCompanion.exe");
  39. }
  40. /// <summary>
  41. /// 重写安装过程方法
  42. /// </summary>
  43. /// <param name="stateSaver"></param>
  44. public override void Install(IDictionary stateSaver)
  45. {
  46. base.Install(stateSaver);
  47. }
  48. /// <summary>
  49. /// 重写安装之前方法
  50. /// </summary>
  51. /// <param name="savedState"></param>
  52. protected override void OnBeforeInstall(IDictionary savedState)
  53. {
  54. base.OnBeforeInstall(savedState);
  55. }
  56. /// <summary>
  57. /// 重写卸载方法
  58. /// 卸载程序后也删除程序的安装包
  59. /// </summary>
  60. /// <param name="savedState"></param>
  61. public override void Uninstall(IDictionary savedState)
  62. {
  63. string temp = System.Environment.GetEnvironmentVariable("TEMP");
  64. string folder = new DirectoryInfo(temp).FullName;
  65. if (File.Exists(folder + @"\setup.exe"))
  66. {
  67. File.Delete(folder + @"\setup.exe");
  68. }
  69. if (File.Exists(folder + @"\setup.msi"))
  70. {
  71. File.Delete(folder + @"\setup.msi");
  72. }
  73. if (File.Exists(folder + @"\"+zipPacket))
  74. {
  75. File.Delete(folder + @"\"+zipPacket);
  76. }
  77. base.Uninstall(savedState);
  78. }
  79. /// <summary>
  80. /// 重写回滚方法
  81. /// </summary>
  82. /// <param name="savedState"></param>
  83. public override void Rollback(IDictionary savedState)
  84. {
  85. base.Rollback(savedState);
  86. }
  87. }
  88. }

c.在安装项目中右键->添加项目输出->选择"项目"->InstallCompenent.完成主输出项目的添加.

d.打开自定义操作编辑器,在安装->右键->添加自定义操作->选择"应用程序文件夹"->选择"主输出来自InstallCompenent",完成添加.

好了,点击“生成解决方案”,即可以生成带有卸载功能的安装程序了。

转自:http://blog.csdn.net/myhuli120/article/details/6927588

c#自动更新+安装程序的制作的更多相关文章

  1. c#自动更新+安装程序的制作 (转)

    c#自动更新+安装程序的制作 (转)  http://blog.csdn.net/myhuli120/article/details/6927588 一.自动更新的实现 让客户端实现自动更新,通常做法 ...

  2. 怎样用VB自动更新应用程序

    具体程序实现如下:在应用程序工程MyApp中的部分代码如下:Option Explicit'编译后的应用程序名称,注意没有后缀 .EXE,本例为MYAPPPrivate Const App_Name ...

  3. linux小白成长之路4————centos7配置自动更新安装安全补丁

    [内容指引] 安装yum-cron; 修改配置:nano: 手工启动服务: 将服务设置为开机自动启动. 为保证linux系统的安全性以及稳定性,可以使用yum-cron服务自动更新: 1.安装yum- ...

  4. C#自动更新本地程序

    关于系统的自动更新.近日有一情况是需要将java端后台最新版本的系统文件覆盖本地客户端,简称自动更新了. 本地会获取当前系统的版本号去请求后台java的接口数据.返回给我的是后台压缩包转的base64 ...

  5. Android自动更新安装后显示‘完成’‘打开’按钮

    /** * 安装apk * * @param url */ private void installApk() { File apkfile = new File(apkFilePath); if ( ...

  6. VS2010制作网站自定义安装程序 转

    最近在把一个网站打包成安装程序,这方面的文章网上有很多,也看了不少,但因为开发环境的不同,遇到了一些问题,便写下这篇文章记下整个流程(有很多资源都来自互联网,由于条目颇多,所以无法说明其来处,敬请谅解 ...

  7. WinForm应用程序中实现自动更新功能

    WinForm应用程序中实现自动更新功能 编写人:左丘文 2015-4-20 近来在给一客户实施ECM系统,但他们使用功能并不是我们ECM制造版提供的标准功能,他们要求对系统作一些定制功能,为了避免因 ...

  8. 制作Java安装程序

    这个工具利用 ANT 来制作在 Windows, MacOS X, Unix 平台上可执行的文件,比如 exe,zip,jar.ROXES ANT Tasks 基于 GPL 发布. http://ww ...

  9. acm对拍程序 以及sublime text3的文件自动更新插件auto refresh

    acm等算法比赛常用---对拍 以及sublime text3的文件自动更新插件auto refresh 对拍 对拍即程序自动对比正确程序的运行结果和错误程序的运行结果之间的差异 废话少说, 直接上操 ...

随机推荐

  1. a标签的href="javascript:void(0)"和href="#"的区别

    修正一个说法上的bug吧.对于IE6来说,点击后gif暂停bug仅仅发生在“javascript:伪协议未加分号”的情形下. 我再来提供一个视角吧. 给<a>标签增加href属性,就意味着 ...

  2. FFT —— 快速傅里叶变换

    问题: 已知A[], B[], 求C[],使: 定义C是A,B的卷积,例如多项式乘法等. 朴素做法是按照定义枚举i和j,但这样时间复杂度是O(n2). 能不能使时间复杂度降下来呢? 点值表示法: 我们 ...

  3. 九度OJ 1437 To Fill or Not to Fill -- 贪心算法

    题目地址:http://ac.jobdu.com/problem.php?pid=1437 题目描述: With highways available, driving a car from Hang ...

  4. 每天一条linux命令——shutdown

    shutdown命令用来系统关机命令.shutdown指令可以关闭所有程序,并依用户的需要,进行重新开机或关机的动作. 语法: shutdown(选项)(参数) 选项: -c:当执行“shutdown ...

  5. Debian vim没有颜色的解决办法

    最近在研究Linux kali 3.12-kali1-amd64  Debian 3.12.6-2kali1  x86_64 GNU/Linux Debian的内核 发现vim竟然没有颜色,root或 ...

  6. CSS定位机制

    CSS中,存在3种定位机制:标准文档流(Normal flow) * 特点:从上到下,从左导游,输出文档内容 * 由块级元素和行级元素组成 浮动(Floats) * 能够实现横向多列布局 * 设置了浮 ...

  7. 构建 struts2 spring3 mybatis 的maven项目 构建 pom.xml

    学习maven项目时 搭建个ssm项目 算是给自己留个备份吧 环境说明: MyEclipse10 Maven   3.2.3 框架: struts2    2.3.24.1 spring3    3. ...

  8. php版网易视频云api

    最近在做在线教育课程,使用网易云视频作为在线视频直播. 网易官方只有java示例,我们使用php,就自己写个api. 当然实现也是很简单的. 演示:http://www.deitui.com/inde ...

  9. 【python】for循环一列

    a="哈哈哈哈,笑死我了"for i in a: print (i, end=' ') 结果 哈 哈 哈 哈 , 笑 死 我 了

  10. bzoj3667: Rabin-Miller算法

    Description   Input 第一行:CAS,代表数据组数(不大于350),以下CAS行,每行一个数字,保证在64位长整形范围内,并且没有负数.你需要对于每个数字:第一,检验是否是质数,是质 ...