c#自动更新+安装程序的制作 (转)  http://blog.csdn.net/myhuli120/article/details/6927588

一、自动更新的实现

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

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

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",完成添加.

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

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

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

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

  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. ActionBarSherlock

    https://github.com/JakeWharton/ActionBarSherlock https://github.com/ddewaele/GoogleMapsV2WithActionB ...

  2. Linux下Join命令

    Linux下Join命令 最近新上线算法,打算分析起点书籍点击率的波动,原来已经有流程每天每本书籍的点击率数据(文件).之前这种情况都是写代码对不同天的进行合并,后来发现linux下直接就有join命 ...

  3. Could not initialize class org.apache.log4j.LogManager 报错

    部署项目的时候,在windows下一切正常,但是在centos下就发生如下错误 Caused by: java.lang.ExceptionInInitializerError at com.dsid ...

  4. HDU - 1693 Eat the Trees(多回路插头DP)

    题目大意:要求你将全部非障碍格子都走一遍,形成回路(能够多回路),问有多少种方法 解题思路: 參考基于连通性状态压缩的动态规划问题 - 陈丹琦 下面为代码 #include<cstdio> ...

  5. 敏捷软件工程(agile software development) VS传统软件工程(traditional software development)

    敏捷软件工程(agile software development) VS传统软件工程(traditional software development)      Agile principle  ...

  6. Java常见异常总结

    算术异常类:ArithmeticExecption 空指针异常类:NullPointerException 类型强制转换异常:ClassCastException 数组负下标异常:NegativeAr ...

  7. JMS—事务管理

    Spring提供了一个JmsTransactionManager用于对JMS ConnectionFactory做事务管理.这将允许JMS应用利用Spring的事务管理特性.JmsTransactio ...

  8. react 编写组件 五

    看以下示例了解如何定义一个组件 // 定义一个组件LikeButton var LikeButton = React.createClass({ // 给state定义初始值 getInitialSt ...

  9. asp.net Ajax Post 请求一般处理程序

    其实很早就开通博客园了,一直想写些有价值的东西,供自己以后查阅的同时,也可以帮助别人遇到此类问题时能有一个好的解决方法.但是由于各种原因, 就没有实施我的想法.今天突然很想写下一篇文章,不知道我的第一 ...

  10. 当使用VS CODE 时,如果窗口中打开的文件无法识别HTML的话,可以使用以下方法添加要识别的文件类型

    找到该文件并修改\Microsoft VS Code\resources\app\extensions\html\package.json{ "name": "html& ...