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

一、自动更新的实现

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

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

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

时间: 2024-10-14 14:17:34

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

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

c#自动更新+安装程序的制作 (转)  http://blog.csdn.net/myhuli120/article/details/6927588 一.自动更新的实现 让客户端实现自动更新,通常做法是在客户端部署一个单独的自动更新程序.主程序启动后,访问服务端,检查配置文件是 否有更新版本,有更新版本就启动更新程序,由更新负责下载更新版本,并更新客户端程序,流程如下: 当流程进行到红色部分的是后就调用更新程序进行更新. 1)版本判断: 客户端和服务端都部署同一个版本文件,客户端登陆时发送验证给

C#自动更新本地程序

关于系统的自动更新.近日有一情况是需要将java端后台最新版本的系统文件覆盖本地客户端,简称自动更新了. 本地会获取当前系统的版本号去请求后台java的接口数据.返回给我的是后台压缩包转的base64字节流. 客户端拿到新版本需要更新本地程序. if (UpdateSystem(Path.Combine(Application.StartupPath, "Version.txt"), Path.Combine(Application.StartupPath, "u.zip&q

Android 自动更新--安装新文件后没有&quot;完成,打开&quot;提示界面

下载了Android App安装文件后,在执行安装时不能显示"完成,打开"界面,这是因为没有为intent设置setFlags(Intent.FLAG_ACTIVITY_NEW_TASK). /** * 安装APK文件 */ private void installApk(String savePath, String fileName) { File apkfile = null; try { apkfile = new File(savePath, fileName); } cat

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

1 /** 2 * 安装apk 3 * 4 * @param url 5 */ 6 private void installApk() { 7 File apkfile = new File(apkFilePath); 8 if (!apkfile.exists()) { 9 return; 10 } 11 Intent i = new Intent(Intent.ACTION_VIEW); 12 i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 13 i.s

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

WinForm应用程序中实现自动更新功能 编写人:左丘文 2015-4-20 近来在给一客户实施ECM系统,但他们使用功能并不是我们ECM制造版提供的标准功能,他们要求对系统作一些定制功能,为了避免因程序的bug而带来频繁让用户更新程序的不良影响,就想给ECM增加一个winform自动更新功能,今天在这里,我想与大家一起分享代码,在此做个小结,以供参考.有兴趣的同学,可以一同探讨与学习一下,否则就略过吧.   1. 首先我们在这里先分析一下其它程序猿的一些基本情况: 相信有许多程序猿都喜欢用Wi

关于node-webkit安装程序制作的另一种办法

node-webkit是一个让我们很方便的利用node和webkit内核,前后团都用js,轻松方便的开发出c端应用程序的技术,多余的介绍不必多说,需要详细制动的请大家自行google, 我这里说一下安装程序的制作,由于node-webkit 以下简称nw 是作者编译好的nw.exe来启动的,所以应用程序文件是一大堆node结构的文件和文件夹,其实就是一堆固定目录结构的html结合js,css文件,nw.exe根据程序描述文件package.json来启动主页面加载到webkit内核中的.作者介绍

[转]一个完整的Installshield安装程序实例

Installshield安装程序实例—基本设置一 前言 Installshield可以说是最好的做安装程序的商业软件之一,不过因为功能的太过于强大,以至于上手和精通都不是容易的事情,之前都是用Installshield的Project Assistant对付过去的,这次做这个安装程序,为了实现一些功能,必须写代码,国内外现成的资料很少,而且很多都语焉不详,自己反复啃了多次,对比Installshiel自带的help,才明白资料所表达的意思.这个安装程序虽然比较简陋,在行家眼里可能是小菜一碟,但

一个完整的Installshield安装程序实例-转

一个完整的Installshield安装程序实例-艾泽拉斯之海洋女神出品(一)---基本设置一 前言 Installshield可以说是最好的做安装程序的商业软件之一,不过因为功能的太过于强大,以至于上手和精通都不是容易的事情,之前都是用Installshield的Project Assistant对付过去的,这次做这个安装程序,为了实现一些功能,必须写代码,国内外现成的资料很少,而且很多都语焉不详,自己反复啃了多次,对比Installshiel自带的help,才明白资料所表达的意思.这个安装程

大话Electron应用自动更新

一.Windows下更新特有的问题 软件更新在Linux和macOS还好说,但是在Windows上可能会遇到UAC问题,常用的方法是:Windows计划任务.Windows Service,本质上这两种方式还是提权,Windows Service 与 Windows计划任务相比最大的特点就是可以与应用交互,Windows的更新就是使用Windows Update服务,即使在macOS的Edge浏览器也是使用的Microsoft Update服务. 二.手动更新 手动更新是下载完整的安装包,用户手