`

C#在应用程序中实现自动升级(转)

阅读更多

这是本人第一次写比较复杂的文章,表达不清之处,请各位见谅。好,闲话少说,入正题。

最近单位开发一个项目,其中需要用到自动升级功能。因为自动升级是一个比较常用的功能,可能会在很多程序中用到,于是,我就想写一个自动升级的组件,在应用程序中,只需要引用这个自动升级组件,并添加少量代码,即可实现自动升级功能。因为我们的程序中可能包含多个exe或者dll文件,所以要支持多文件的更新。

首先,要确定程序应该去哪里下载需要升级的文件。我选择了到指定的网站上去下载,这样比较简单,也通用一些。在这个网站上,需要放置一个当前描述最新文件列表的文件,我们估且叫它服务器配置文件。这个文件保存了当前最新文件的版本号(lastver),大小(size),下载地址(url),本地文件的保存路径(path),还有当更新了这个文件后,程序是否需要重新启动(needRestart)。这个文件大致如下:
updateservice.xml

<?xml version="1.0" encoding="utf-8"?>
<updateFiles>
  <file path="AutoUpdater.dll"  url="http://update.iyond.com/CompanyClientApplication/AutoUpdater.zip" lastver="1.0.0.0" size="28672" needRestart="true" />
  <file path="CompanyClient.exe"  url="http://update.iyond.com/CompanyClientApplication/CompanyClient.zip" lastver="1.1.0.0" size="888832 " needRestart="true" />
  <file path="HappyFenClient.dll"  url="http://update.iyond.com/CompanyClientApplication/HappyFenClient.zip" lastver="1.0.0.0" size="24576" needRestart="true" />
  <file path="NetworkProvider.dll"  url="http://update.iyond.com/CompanyClientApplication/NetworkProvider.zip" lastver="1.0.0.0" size="32768" needRestart="true" />
  <file path="Utility.dll"  url="http://update.iyond.com/CompanyClientApplication/Utility.zip" lastver="1.0.0.0" size="20480" needRestart="true" />
  <file path="Wizard.dll"  url="http://update.iyond.com/CompanyClientApplication/Wizard.zip" lastver="1.0.0.0" size="24576"  needRestart="true" />
</updateFiles>

 

同时,客户端也保存了一个需要升级的本地文件的列表,形式和服务器配置文件差不多,我们叫它本地配置文件。其中,<Enable>节点表示是否启用自动升级功能,<ServerUrl>表示服务器配置文件的地址。
update.config

<?xml version="1.0" encoding="utf-8"?>
<Config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Enabled>true</Enabled>
  <ServerUrl>http://update.iyond.com/updateservice.xml</ServerUrl>
  <UpdateFileList>
      <LocalFile path="AutoUpdater.dll" lastver="1.0.0.0" size="28672" />
      <LocalFile path="CompanyClient.exe" lastver="1.1.0.0" size="888832 " />
      <LocalFile path="HappyFenClient.dll" lastver="1.0.0.0" size="24576" />
      <LocalFile path="NetworkProvider.dll" lastver="1.0.0.0" size="32768" />
      <LocalFile path="Utility.dll" lastver="1.0.0.0" size="20480" />
      <LocalFile path="Wizard.dll" lastver="1.0.0.0" size="24576"  />
  </UpdateFileList>  
</Config>

 

使用自动各级组件的程序在启动时,会去检查这个配置文件。如果发现有配置文件中的文件版本和本地配置文件中描述的文件版本不一致,则提示用户下载。同时,如果本地配置文件中某些文件在服务器配置文件的文件列表中不存在,则说明这个文件已经不需要了,需要删除。最后,当升级完成后,会更新本地配置文件。

我们先来看一下如何使用这个组件。
在程序的Program.cs的Main函数中:

[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    AutoUpdater au = new AutoUpdater();
    try
    {
        au.Update();
    }
    catch (WebException exp)
    {
        MessageBox.Show(String.Format("无法找到指定资源\n\n{0}", exp.Message), "自动升级", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    catch (XmlException exp)
    {
        MessageBox.Show(String.Format("下载的升级文件有错误\n\n{0}", exp.Message), "自动升级", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    catch (NotSupportedException exp)
    {
        MessageBox.Show(String.Format("升级地址配置错误\n\n{0}", exp.Message), "自动升级", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    catch (ArgumentException exp)
    {
        MessageBox.Show(String.Format("下载的升级文件有错误\n\n{0}", exp.Message), "自动升级", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    catch (Exception exp)
    {
        MessageBox.Show(String.Format("升级过程中发生错误\n\n{0}", exp.Message), "自动升级", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }

    Application.Run(new MainUI());
}

 

如上所示,只需要简单的几行代码,就可以实现自动升级功能了。

软件运行截图:






下面,我们来详细说一下这个自动升级组件的实现。
先看一下类图:

AutoUpdater:自动升级的管理类,负责整体的自动升级功能的实现。
Config:配置类,负责管理本地配置文件。
DownloadConfirm:一个对话框,向用户显示需要升级的文件的列表,并允许用户选择是否马上升级。
DownloadFileInfo:要下载的文件的信息
DownloadProgress:一个对话框,显示下载进度。
DownloadProgress.ExitCallBack,
DownloadProgress.SetProcessBarCallBack,
DownloadProgress.ShowCurrentDownloadFileNameCallBack:由于.NET2.0不允许在一个线程中访问另一个线程的对象,所以需要通过委托来实现。
LocalFile:表示本地配置文件中的一个文件
RemoteFile:表示服务器配置文件中的一个文件。
UpdateFileList:一个集合,从List<LocalFile>继承

我们先整体看一下AutoUpdater.cs:

public class AutoUpdater
{
    const string FILENAME = "update.config";
    private Config config = null;
    private bool bNeedRestart = false;

    public AutoUpdater()
    {
        config = Config.LoadConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, FILENAME));
    }
    /**//// <summary>
    /// 检查新版本
    /// </summary>
    /// <exception cref="System.Net.WebException">无法找到指定资源</exception>
    /// <exception cref="System.NotSupportException">升级地址配置错误</exception>
    /// <exception cref="System.Xml.XmlException">下载的升级文件有错误</exception>
    /// <exception cref="System.ArgumentException">下载的升级文件有错误</exception>
    /// <exception cref="System.Excpetion">未知错误</exception>
    /// <returns></returns>
    public void Update()
    {
        if (!config.Enabled)
            return;
        /**//*
         * 请求Web服务器,得到当前最新版本的文件列表,格式同本地的FileList.xml。
         * 与本地的FileList.xml比较,找到不同版本的文件
         * 生成一个更新文件列表,开始DownloadProgress
         * <UpdateFile>
         *  <File path="" url="" lastver="" size=""></File>
         * </UpdateFile>
         * path为相对于应用程序根目录的相对目录位置,包括文件名
         */
        WebClient client = new WebClient();
        string strXml = client.DownloadString(config.ServerUrl);

        Dictionary<string, RemoteFile> listRemotFile = ParseRemoteXml(strXml);

        List<DownloadFileInfo> downloadList = new List<DownloadFileInfo>();

        //某些文件不再需要了,删除
        List<LocalFile> preDeleteFile = new List<LocalFile>();

        foreach (LocalFile file in config.UpdateFileList)
        {
            if (listRemotFile.ContainsKey(file.Path))
            {
                RemoteFile rf = listRemotFile[file.Path];
                if (rf.LastVer != file.LastVer)
                {
                    downloadList.Add(new DownloadFileInfo(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 (RemoteFile file in listRemotFile.Values)
        {
            downloadList.Add(new DownloadFileInfo(file.Url, file.Path, file.LastVer, file.Size));
            config.UpdateFileList.Add(new LocalFile(file.Path, file.LastVer, file.Size));

            if (file.NeedRestart)
                bNeedRestart = true;
        }

        if (downloadList.Count > 0)
        {
            DownloadConfirm dc = new DownloadConfirm(downloadList);

            if (this.OnShow != null)
                this.OnShow();

            if (DialogResult.OK == dc.ShowDialog())
            {
                foreach (LocalFile file in preDeleteFile)
                {
                    string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, file.Path);
                    if (File.Exists(filePath))
                        File.Delete(filePath);

                    config.UpdateFileList.Remove(file);
                }

                StartDownload(downloadList);
            }
        }
    }

    private void StartDownload(List<DownloadFileInfo> downloadList)
    {
        DownloadProgress dp = new DownloadProgress(downloadList);
        if (dp.ShowDialog() == DialogResult.OK)
        {
            //更新成功
            config.SaveConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, FILENAME));

            if (bNeedRestart)
            {
                MessageBox.Show("程序需要重新启动才能应用更新,请点击确定重新启动程序。", "自动更新", MessageBoxButtons.OK, MessageBoxIcon.Information);
                Process.Start(Application.ExecutablePath);
                Environment.Exit(0);
            }
        }
    }

    private Dictionary<string, RemoteFile> ParseRemoteXml(string xml)
    {
        XmlDocument document = new XmlDocument();
        document.LoadXml(xml);

        Dictionary<string, RemoteFile> list = new Dictionary<string, RemoteFile>();
        foreach (XmlNode node in document.DocumentElement.ChildNodes)
        {
            list.Add(node.Attributes["path"].Value, new RemoteFile(node));
        }

        return list;
    }
    public event ShowHandler OnShow;
}

 

在构造函数中,我们先要加载配置文件:

public AutoUpdater()
{
    config = Config.LoadConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, FILENAME));
}

 

最主要的就是Update()这个函数了。当程序调用au.Update时,首先检查当前是否开户了自动更新:

if (!config.Enabled)
    return;

 

如果启用了自动更新,就需要去下载服务器配置文件了:

WebClient client = new WebClient();
string strXml = client.DownloadString(config.ServerUrl);

 

然后,解析服务器配置文件到一个Dictionary中:

Dictionary<string, RemoteFile> listRemotFile = ParseRemoteXml(strXml);

 

接下来比较服务器配置文件和本地配置文件,找出需要下载的文件和本地需要删除的文件:

        List<DownloadFileInfo> downloadList = new List<DownloadFileInfo>();
        //某些文件不再需要了,删除
        List<LocalFile> preDeleteFile = new List<LocalFile>();

        foreach (LocalFile file in config.UpdateFileList)
        {
            if (listRemotFile.ContainsKey(file.Path))
            {
                RemoteFile rf = listRemotFile[file.Path];
                if (rf.LastVer != file.LastVer)
                {
                    downloadList.Add(new DownloadFileInfo(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 (RemoteFile file in listRemotFile.Values)
        {
            downloadList.Add(new DownloadFileInfo(file.Url, file.Path, file.LastVer, file.Size));
            config.UpdateFileList.Add(new LocalFile(file.Path, file.LastVer, file.Size));

            if (file.NeedRestart)
                bNeedRestart = true;
        }

 如果发现有需要下载的文件,则向用户显示这些文件,并提示其是否马上更新。如果用户选择了马上更新,则先删除本地不再需要的文件,然后开始下载更新文件。

        if (downloadList.Count > 0)
        {
            DownloadConfirm dc = new DownloadConfirm(downloadList);

            if (this.OnShow != null)
                this.OnShow();

            if (DialogResult.OK == dc.ShowDialog())
            {
                foreach (LocalFile file in preDeleteFile)
                {
                    string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, file.Path);
                    if (File.Exists(filePath))
                        File.Delete(filePath);

                    config.UpdateFileList.Remove(file);
                }

                StartDownload(downloadList);
            }
        }

 我们再来看一下StartDownload函数

    private void StartDownload(List<DownloadFileInfo> downloadList)
    {
        DownloadProgress dp = new DownloadProgress(downloadList);
        if (dp.ShowDialog() == DialogResult.OK)
        {
            //更新成功
            config.SaveConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, FILENAME));

            if (bNeedRestart)
            {
                MessageBox.Show("程序需要重新启动才能应用更新,请点击确定重新启动程序。", "自动更新", MessageBoxButtons.OK, MessageBoxIcon.Information);
                Process.Start(Application.ExecutablePath);
                Environment.Exit(0);
            }
        }
    }

 

在这个函数中,先调用DownloadProgress下载所有需要下载的文件,然后更新本地配置文件,最后,如果发现某些更新文件需要重新启动应用程序的话,会提示用户重新启动程序。

至此,AutoUpdater这个类的使命就完成了,其实,整个的升级过程也就完成了。(废话)。

最后,我们来看一下这个组件是如何下载更新文件的

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Net;
using System.IO;
using System.Diagnostics;

namespace Iyond.Utility
{
    public partial class DownloadProgress : Form
    {
        private bool isFinished = false;
        private List<DownloadFileInfo> downloadFileList = null;
        private ManualResetEvent evtDownload = null;
        private ManualResetEvent evtPerDonwload = null;
        private WebClient clientDownload = null;

        public DownloadProgress(List<DownloadFileInfo> downloadFileList)
        {
            InitializeComponent();

            this.downloadFileList = downloadFileList;
        }

        private void OnFormClosing(object sender, FormClosingEventArgs e)
        {
            if (!isFinished && DialogResult.No == MessageBox.Show("当前正在更新,是否取消?", "自动升级", MessageBoxButtons.YesNo, MessageBoxIcon.Question))
            {
                e.Cancel = true;
                return;
            }
            else
            {
                if (clientDownload != null)
                    clientDownload.CancelAsync();

                evtDownload.Set();
                evtPerDonwload.Set();
            }
        }

        private void OnFormLoad(object sender, EventArgs e)
        {
            evtDownload = new ManualResetEvent(true);
            evtDownload.Reset();
            Thread t = new Thread(new ThreadStart(ProcDownload));
            t.Name = "download";
            t.Start();
        }

        long total = 0;
        long nDownloadedTotal = 0;

        private void ProcDownload()
        {
            evtPerDonwload = new ManualResetEvent(false);

            foreach (DownloadFileInfo file in this.downloadFileList)
            {
                total += file.Size;
            }

            while (!evtDownload.WaitOne(0, false))
            {
                if (this.downloadFileList.Count == 0)
                    break;

                DownloadFileInfo file = this.downloadFileList[0];


                //Debug.WriteLine(String.Format("Start Download:{0}", file.FileName));

                this.ShowCurrentDownloadFileName(file.FileName);

                //下载
                clientDownload = new WebClient();

                clientDownload.DownloadProgressChanged += new DownloadProgressChangedEventHandler(OnDownloadProgressChanged);
                clientDownload.DownloadFileCompleted += new AsyncCompletedEventHandler(OnDownloadFileCompleted);

                evtPerDonwload.Reset();

                clientDownload.DownloadFileAsync(new Uri(file.DownloadUrl), Path.Combine(AppDomain.CurrentDomain.BaseDirectory, file.FileFullName + ".tmp"), file);
                
                //等待下载完成
                evtPerDonwload.WaitOne();

                clientDownload.Dispose();
                clientDownload = null;

                //移除已下载的文件
                this.downloadFileList.Remove(file);
            }

            //Debug.WriteLine("All Downloaded");

            if (this.downloadFileList.Count == 0)
                Exit(true);
            else
                Exit(false);

            evtDownload.Set();
        }

        void OnDownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            DownloadFileInfo file = e.UserState as DownloadFileInfo;
            nDownloadedTotal += file.Size;
            this.SetProcessBar(0, (int)(nDownloadedTotal * 100 / total));
            //Debug.WriteLine(String.Format("Finish Download:{0}", file.FileName));
            //替换现有文件
            string filePath = 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);
            //继续下载其它文件
            evtPerDonwload.Set();
        }

        void OnDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            this.SetProcessBar(e.ProgressPercentage, (int)((nDownloadedTotal + e.BytesReceived) * 100 / total));
        }

        delegate void ShowCurrentDownloadFileNameCallBack(string name);
        private void ShowCurrentDownloadFileName(string name)
        {
            if (this.labelCurrentItem.InvokeRequired)
            {
                ShowCurrentDownloadFileNameCallBack cb = new ShowCurrentDownloadFileNameCallBack(ShowCurrentDownloadFileName);
                this.Invoke(cb, new object[] { name });
            }
            else
            {
                this.labelCurrentItem.Text = name;
            }
        }

        delegate void SetProcessBarCallBack(int current, int total);
        private void SetProcessBar(int current, int total)
        {
            if (this.progressBarCurrent.InvokeRequired)
            {
                SetProcessBarCallBack cb = new SetProcessBarCallBack(SetProcessBar);
                this.Invoke(cb, new object[] { current, total });
            }
            else
            {
                this.progressBarCurrent.Value = current;
                this.progressBarTotal.Value = total;
            }
        }

        delegate void ExitCallBack(bool success);
        private void Exit(bool success)
        {
            if (this.InvokeRequired)
            {
                ExitCallBack cb = new ExitCallBack(Exit);
                this.Invoke(cb, new object[] { success });
            }
            else
            {
                this.isFinished = success;
                this.DialogResult = success ? DialogResult.OK : DialogResult.Cancel;
                this.Close();
            }
        }

        private void OnCancel(object sender, EventArgs e)
        {
            evtDownload.Set();
            evtPerDonwload.Set();
        }
    }
}

 

在构造函数中,将要下载的文件列表传进来

        public DownloadProgress(List<DownloadFileInfo> downloadFileList)
        {
            InitializeComponent();

            this.downloadFileList = downloadFileList;
        }

 

在Form的Load事件中,启动下载线程,开始下载。

        private void OnFormLoad(object sender, EventArgs e)
        {
            evtDownload = new ManualResetEvent(true);
            evtDownload.Reset();
            Thread t = new Thread(new ThreadStart(ProcDownload));
            t.Name = "download";
            t.Start();
        }

 

下载线程没什么特殊的,使用了WebClient的异步下载文件函数DownloadFileAsync,并且注册了两个事件,分别负责下载进度显示和下载完成后的处理:

clientDownload.DownloadProgressChanged += new DownloadProgressChangedEventHandler(OnDownloadProgressChanged);
clientDownload.DownloadFileCompleted += new AsyncCompletedEventHandler(OnDownloadFileCompleted);

 

大家看一下就明白了。

        private void ProcDownload()
        {
            evtPerDonwload = new ManualResetEvent(false);

            foreach (DownloadFileInfo file in this.downloadFileList)
            {
                total += file.Size;
            }

            while (!evtDownload.WaitOne(0, false))
            {
                if (this.downloadFileList.Count == 0)
                    break;

                DownloadFileInfo file = this.downloadFileList[0];


                //Debug.WriteLine(String.Format("Start Download:{0}", file.FileName));

                this.ShowCurrentDownloadFileName(file.FileName);

                //下载
                clientDownload = new WebClient();

                clientDownload.DownloadProgressChanged += new DownloadProgressChangedEventHandler(OnDownloadProgressChanged);
                clientDownload.DownloadFileCompleted += new AsyncCompletedEventHandler(OnDownloadFileCompleted);

                evtPerDonwload.Reset();

                clientDownload.DownloadFileAsync(new Uri(file.DownloadUrl), Path.Combine(AppDomain.CurrentDomain.BaseDirectory, file.FileFullName + ".tmp"), file);
                
                //等待下载完成
                evtPerDonwload.WaitOne();

                clientDownload.Dispose();
                clientDownload = null;

                //移除已下载的文件
                this.downloadFileList.Remove(file);
            }

            //Debug.WriteLine("All Downloaded");

            if (this.downloadFileList.Count == 0)
                Exit(true);
            else
                Exit(false);

            evtDownload.Set();
        }

 

最后,在OnDownloadFileCompleted函数中进行最后的处理。包括备份原文件,替换现有文件等。

        void OnDownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            DownloadFileInfo file = e.UserState as DownloadFileInfo;
            nDownloadedTotal += file.Size;
            this.SetProcessBar(0, (int)(nDownloadedTotal * 100 / total));
            //Debug.WriteLine(String.Format("Finish Download:{0}", file.FileName));
            //替换现有文件
            string filePath = 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);
            //继续下载其它文件
            evtPerDonwload.Set();
        }

 

其它的函数只是一些显示进度条和下载信息的,这里就不再详细介绍了。大家可以下载源码看一下。

最后说一下,由于个人能力和时间的问题,这个组件还有一些不完善的地方,比如配置文件比较复杂等,如果您对这个组件有什么改进的话,请务必发给我一份,我的邮件是:iyondkoo@gmail.com.谢谢。


再做个广告:VS2005专业教程站是小弟最近做的一个网站,主要是提供VS2005、ASP.NET相关教程,希望大家有什么问题可以去看一下,同时给我提些建议。谢谢大家啦。

源码下载
原文地址http://www.cnblogs.com/iyond/archive/2007/06/14/783301.html

分享到:
评论

相关推荐

    C#在WinForm应用程序中实现自动升级

    C#在WinForm应用程序中实现自动升级

    C#实现自动升级程序(含客户端和服务端)

    程序分成UpdateServer(Web服务...UpdateServer提供应用程序的最新版本,应用程序存放在UpdateServer下的AppCenter目录中。Client程序运行时,先从UpdateServer下载最新的版本,然后创建新的应用程序域加载程序执行。

    C#应用程序在线自动升级程序源码

    1、c#应用程序在线升级程序,通用各种WinForm系统升级程序 2、此源码简单易懂,界面简洁漂亮 3、有操作手册可供初学者学习,如果你是老鸟,估计不用看都会操作,呵呵,废话不多说,没做过升级程序的童鞋可以看看

    C#WinForm自动升级程序源代码

    本人写的针对WinForm程序自动升级程序,适用于所有WinForm客户端程序,非常方便,分享给大家共同学习。

    c#应用webService实现自动升级源代码

    c#应用webService实现自动升级 1、模块化设计,独立于用户应用程序 2、支持下载进度 3、支持用户程序的版本检测,并决定是否可升级 4、提供自动产生用户程序版本工具

    c#WinForm程序自动升级组件

    C# Winform自动升级程序组件,内含使用说明,使用简单方便,功能强大

    C#软件升级方案-C#编写的自动升级系统

    然而当一个应用 必须要使用C/S结构才能很好的实现其功能的时候,我们该如何解决客户端的部署与自动升级问题?部署很简单,只要点击安装程序即可,难的在于每当有新版本 发布时,能够实现自动升级[3]。现在好了,我们...

    c#WinForm程序自动升级源码

    实现C#winForm程序的自动升级功能,内含使用说明,使用方便简单,功能强大

    c#自动升级之星(版本更新控制)源码

    本程序采用CS架构,实现应用程序(文件)的自动升级(版本控制),支持文件与文件夹属性同步(满足特殊文件操作需求)。使用本程序可以实现对客户端文件的版本控制以及自动升级控制。 本程序采用纯C#编写,升级文件...

    C#的CS模式自动在线升级

    本文针对目前C/S模式下编写的应用程序可维护性差的特点,提出了一套自动在线升级的解决方案,分析了在线升级的困难及实现原理,并给出了实现升级的部分代码,具有实际参考价值和现实意义。本文程序代码均在.Net ...

    c# c\s应用程序自动更新模块源码

    c\s应用程序自动更新模块源码,可以直接编译 主要通过本地程序与服务端程序文件的版本号来升级与更新本地程序文件。 UpdateList.xml文件内容如下: &lt;description&gt;Application autoUpdate &lt;Url&gt;...

    办公自动化管理系统c#语句

    完整的办公自动化代码,运用的是sql2005,visual studio 2008软件实现。运用的是C#语句。导入即可使用。

    C#微软培训资料

    C#语言在.NET 框架中的作用及其特性 1.1 Microsoft.NET 一场新的革命 1.1.1 什么是.NET 2000 年 6 月 22 日 不论对 Microsoft 还是对整个 IT 业界都将成为值得纪念的一天 这一天 微软公司正式推出...

    C#自动更新程序及源码

    以上为自动更新的配置文件update.xml, 通过...使用了应用程序域。要了解请下载源码,感谢您能提供宝贵意见,如要进行修改,请注明来源。 由于时间关系,只完成了基本功能。有时间,会继续更新,希望您能提出宝贵意见。

    C/S模式程序自动升级功能,嵌入自己的程序就可以使用。

    C/S模式程序自动升级功能,嵌入自己的程序就可以使用。 将两个文件嵌入自己的程序项目中,写个简单的判断条件调用升级程序即可: if (UpdateState == "True" && string.Compare(Version, GetVersion, false) &gt; 0) { ...

    采用C#实现软件自动更新的方法

    然而当一个应用必须要使用C/S 结构才能很好的实现其功能的时候,我们该如何解决客户端的部署与自动升级问题?部署很简单,只要点击安装程序即可,难的在于每当有新版本发布时,能够实现 自动升级。现在好了,我们的...

    SimpAutoUpdater c#自动升级模块源码

    SimpAutoUpdater c#自动升级 模块源码 可以集成到自己程序: 首先在VS中为当前的主程序项目添加引用,引用“客户端”中的“SimpleUpdater.exe”。 在VS中,点开“解决方案管理器”中相应项目的“属性”节点,打开...

    asp.net(c#)程序版本升级更新的实现代码

    我们做了程序,不免会有版本升级,这就需要程序有自动版本升级的功能。那么看看我是如何实现程序自动更新的。

    自动升级程序代码

    一款不可多得的C# Winform自动升级开发项目,稍加修改就可应用在自已的项目中

Global site tag (gtag.js) - Google Analytics