winform更新程序代码

这是我的第一个随笔,写的不好的或者语法错误等,请大家不要见怪,首先预览下截图

 

自动更新一般分3部分:

1、发现更新

2、下载文件

3、复制文件

下面对以上3个过程做简单的介绍

发现更新

根据客户端的配置文件的manifestUri去读取服务器的xml文件,然后依次比较applicationId和version,如果applicationId一致且version不一致则可以更新,客户端配置文件不是app.config,而是一个自己定义的xml文件,至于为什么不用app.config文件的原因很简单,因为app.config在系统运行的时候是不能进行修改的,客户端配置文件内容大概如下:

<?xml version="1.0" encoding="utf-8"?>
<applicationUpdater applicationId="{4a1e1623-bd3c-4921-8d91-85d34a5fe518}"
                        manifestUri
="http://127.0.0.1/manifests.xml"
                        version
="1.04">
</applicationUpdater>
applicationId表示运用程序Id,这个要跟服务器上的xml的applicationId一致,否则程序不会更新;
manifestUri表示服务器xml的地址
version表示当前版本,版本跟服务器上的不一致就更新
 
服务器端配置文件内容大概如下:
<?xml version="1.0" encoding="utf-8" ?>
<manifest>
  
<!--版本号,无格式要求,更新时需要修改-->
  
<version>1.2</version>
  
<description>更新说明,更新时需要修改</description>
  
<!--applicationId运用程序ID,无格式要求,需要与客户端配置一样,否则不会进行更新-->
  
<application applicationId="{215E1AD7-9ABA-432f-A952-24BABA556850}">
    
<!--重新启动exe名称,parameters启动时传入的参数-->
    
<entryPoint file="Client.exe" parameters="client" />
    
<!--更新文件的目录,相对于更新系统,默认为同级目录-->
    
<location>.</location>
  
</application>
  
<!--base表示存放该文件的url-->
  
<files base="http://localhost/update/">
    
<!--文件名称,更新时需要修改-->
    
<file source="test.txt" />
    
<file source="Client.exe" />
  
</files>
</manifest>
XML对应的实体类
View Code
[XmlRoot("manifest")]
    
public class Manifest
    {
        [XmlElement(
"version")]
        
public string Version { getset; }

        [XmlElement(
"description")]
        
public string Description { getset; }

        [XmlElement(
"fileBytes")]
        
public long FileBytes { getset; }

        [XmlElement(
"application")]
        
public Application Application { getset; }

        [XmlElement(
"files")]
        
public ManifestFiles ManifestFiles { getset; }
    }

    
public class ManifestFiles
    {
        [XmlElement(
"file")]
        
public ManifestFile[] Files { getset; }

        [XmlAttribute(
"base")]
        
public string BaseUrl { getset; }
    }

    
public class ManifestFile
    {
        [XmlAttribute(
"source")]
        
public string Source
        {
            
get;
            
set;
        }

        [XmlAttribute(
"hash")]
        
public string Hash
        {
            
get;
            
set;
        }
    }

    
public class Application
    {
        [XmlAttribute(
"applicationId")]
        
public string ApplicationId { getset; }

        [XmlElement(
"location")]
        
public string Location { getset; }

        [XmlElement(
"entryPoint")]
        
public EntryPoint EntryPoint { getset; }
    }

    
public class EntryPoint
    {
        [XmlAttribute(
"file")]
        
public string File { getset; }

        [XmlAttribute(
"parameters")]
        
public string Parameters { getset; }
    }

    
public class UpdaterConfigurationView
    {
        
private static XmlDocument document = new XmlDocument();
        
private static readonly string xmlFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "updateconfiguration.config");

        
static UpdaterConfigurationView()
        {
            document.Load(xmlFileName);
        }

        
public string Version
        {
            
get
            {
                
return document.SelectSingleNode("applicationUpdater").Attributes["version"].Value;
            }
            
set
            {
                document.SelectSingleNode(
"applicationUpdater").Attributes["version"].Value = value;
                document.Save(xmlFileName);
            }
        }

        
public string ApplicationId
        {
            
get
            {
                
return document.SelectSingleNode("applicationUpdater").Attributes["applicationId"].Value;
            }
            
set
            {
                document.SelectSingleNode(
"applicationUpdater").Attributes["applicationId"].Value = value;
                document.Save(xmlFileName);
            }
        }

        
public string ManifestUri
        {
            
get
            {
                
return document.SelectSingleNode("applicationUpdater").Attributes["manifestUri"].Value;
            }
            
set
            {
                document.SelectSingleNode(
"applicationUpdater").Attributes["manifestUri"].Value = value;
                document.Save(xmlFileName);
            }
        }
    }
 
 
 
下载文件
 下载文件是根据服务器端的配置文件进行的,配置文件设置了下载的文件路径,下载地址的url,下载文件保存的位置,由location节点设置,好了,不多说了,看下载的源码,这里我是写了一个可以异步下载的组件,里面用的是Ms自带的WebClient类,异步下载有事件通知,详见源码:
事件类
View Code
public class DownloadErrorEventArgs : EventArgs
    {
        
public Exception Error { getset; }

        
public Manifest Manifest { getset; }
    }

    
public class DownloadProgressEventArgs : ProgressChangedEventArgs
    {
        
public DownloadProgressEventArgs(int progressPercentage, object userState)
            : 
base(progressPercentage,userState)
        { }

        
/// <summary>
        
/// 当前下载的文件名
        
/// </summary>
        public string FileName { getset; }

        
/// <summary>
        
/// 获取收到的字节数。
        
/// </summary>
        public long BytesReceived { getset; }
        
/// <summary>
        
/// 获取 System.Net.WebClient 数据下载操作中的字节总数。
        
/// </summary>
        public long TotalBytesToReceive { getset; }
    }

    
public class DownloadCompleteEventArgs : AsyncCompletedEventArgs
    {
        
public DownloadCompleteEventArgs(Exception error, bool cancelled, object userState)
            : 
base(error, cancelled, userState)
        { 
        }

        
public Manifest Manifest { getset; }
    }

 下载代码

View Code
public class DownloadClass : Component
    {
        
private WebClient webClient=new WebClient();
        
private Manifest manifest;
        
private int fileCount = 0;
        
private bool cancel = false;
        
private string tempPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "temp");

        
private HybridDictionary userStateToLifetime = new HybridDictionary();
        
private object defaultTaskId = new object();
        
private delegate void WorkerEventHandler(AsyncOperation asyncOp);
        
private System.ComponentModel.Container components = null;
        
private SendOrPostCallback onProgressReportDelegate;
        
private SendOrPostCallback onCompletedDelegate;
        
private AsyncOperation current;

        
/// <summary>
        
/// 下载进度
        
/// </summary>
        public event EventHandler<DownloadProgressEventArgs> DownloadProgressChanged;
        
/// <summary>
        
/// 下载完成事件
        
/// </summary>
        public event EventHandler<DownloadCompleteEventArgs> DownloadCompleted;
        
/// <summary>
        
/// 下载错误触发的事件
        
/// </summary>
        public event EventHandler<DownloadErrorEventArgs> DownloadError;

        
public DownloadClass(IContainer container)
        {
            container.Add(
this);
            InitializeComponent();
            InitializeDelegates();
        }

        
public DownloadClass()
        {
            InitializeComponent();
            InitializeDelegates();
        }

        
/// <summary>
        
/// 初始化代理
        
/// </summary>
        protected virtual void InitializeDelegates()
        {
            onProgressReportDelegate 
= new SendOrPostCallback(ReportProgress);
            onCompletedDelegate 
= new SendOrPostCallback(DoDownloadCompleted);
        }

        
/// <summary>
        
/// 触发下载进度事件
        
/// </summary>
        
/// <param name="e"></param>
        protected virtual void OnDownloadProgressChanged(DownloadProgressEventArgs e)
        {
            
if (DownloadProgressChanged != null)
            {
                DownloadProgressChanged(
this, e);
            }
        }

        
/// <summary>
        
/// 触发下载完成事件
        
/// </summary>
        
/// <param name="e"></param>
        protected virtual void OnDownloadCompleted(DownloadCompleteEventArgs e)
        {
            
if (DownloadCompleted != null)
            {
                DownloadCompleted(
this, e);
            }
        }

        
/// <summary>
        
/// 触发下载错误事件
        
/// </summary>
        
/// <param name="e"></param>
        protected virtual void OnDownloadError(DownloadErrorEventArgs e)
        {
            
if (DownloadError != null)
            {
                DownloadError(
this, e);
            }
        }

        
/// <summary>
        
/// 下载文字保存的临时目录
        
/// </summary>
        public string TempPath
        {
            
get
            {
                
return tempPath;
            }
            
set
            {
                tempPath 
= value;
            }
        }

        
/// <summary>
        
/// 同步下载
        
/// </summary>
        
/// <param name="manifest"></param>
        public void Download(Manifest manifest)
        {
            Init(manifest);
            
foreach (var file in manifest.ManifestFiles.Files)
            {
                
string serverFileName = Path.Combine(manifest.ManifestFiles.BaseUrl, file.Source);
                
string clientFileName = Path.Combine(tempPath, file.Source);
                Uri uri 
= new Uri(serverFileName);
                
if (!Directory.Exists(Path.GetDirectoryName(clientFileName)))
                {
                    Directory.CreateDirectory(Path.GetDirectoryName(clientFileName));
                }
                webClient.DownloadFile(uri, clientFileName);
            }
        }

        
/// <summary>
        
/// 异步下载
        
/// </summary>
        
/// <param name="manifest"></param>
        public void DownloadAsync(Manifest manifest)
        {
            Init(manifest);
            DownloadAsync(manifest,defaultTaskId);
        }

        
/// <summary>
        
/// 异步下载并指定任务Id
        
/// </summary>
        
/// <param name="manifest"></param>
        
/// <param name="taskId"></param>
        public void DownloadAsync(Manifest manifest,object taskId)
        {
            AsyncOperation asyncOp 
= AsyncOperationManager.CreateOperation(taskId);
            
lock (userStateToLifetime.SyncRoot)
            {
                
if (userStateToLifetime.Contains(taskId))
                {
                    
throw new ArgumentException("参数taskId必须是唯一的""taskId");
                }
                userStateToLifetime[taskId] 
= asyncOp;
            }
            WorkerEventHandler workerDelegate 
= new WorkerEventHandler(DownloadWorker);
            workerDelegate.BeginInvoke(asyncOp, 
nullnull);
        }

        
private void Init(Manifest manifest)
        {
            
this.manifest = manifest;
            webClient.BaseAddress 
= manifest.ManifestFiles.BaseUrl;
            webClient.Credentials 
= CredentialCache.DefaultCredentials;
            webClient.Encoding 
= Encoding.UTF8;
        }

        
/// <summary>
        
/// 异步下载方法
        
/// </summary>
        
/// <param name="asyncOp"></param>
        private void DownloadWorker(AsyncOperation asyncOp)
        {
            current 
= asyncOp;
            
if (!TaskCanceled(asyncOp.UserSuppliedState))
            {
                
try
                {
                    webClient.DownloadFileCompleted 
+= new AsyncCompletedEventHandler(webClient_DownloadFileCompleted);
                    webClient.DownloadProgressChanged 
+= new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged);
                    
foreach (var file in manifest.ManifestFiles.Files)
                    {
                        
string serverFileName = Path.Combine(manifest.ManifestFiles.BaseUrl, file.Source);
                        
string clientFileName = Path.Combine(tempPath, file.Source);
                        Uri uri 
= new Uri(serverFileName);
                        
if (!Directory.Exists(Path.GetDirectoryName(clientFileName)))
                        {
                            Directory.CreateDirectory(Path.GetDirectoryName(clientFileName));
                        }
                        
while (webClient.IsBusy)
                        {
                            
//阻塞异步下载
                        }
                        
if (!cancel)
                        {
                            webClient.DownloadFileAsync(uri, clientFileName, file.Source);
                        }
                    }
                }
                
catch (Exception ex)
                {
                    DownloadErrorEventArgs e 
= new DownloadErrorEventArgs();
                    e.Error 
= ex;
                    e.Manifest 
= manifest;
                    OnDownloadError(e);
                }
            }
        }

        
/// <summary>
        
/// 异步完成方法
        
/// </summary>
        
/// <param name="exception"></param>
        
/// <param name="canceled"></param>
        
/// <param name="asyncOp"></param>
        private void CompletionMethod(Exception exception, bool canceled, AsyncOperation asyncOp)
        {
            
if (!canceled)
            {
                
lock (userStateToLifetime.SyncRoot)
                {
                    userStateToLifetime.Remove(asyncOp.UserSuppliedState);
                }
            }
            DownloadCompleteEventArgs e 
= new DownloadCompleteEventArgs(exception, canceled, asyncOp.UserSuppliedState);
            e.Manifest 
= manifest;
            asyncOp.PostOperationCompleted(onCompletedDelegate, e);
            current 
= null;
        }

        
/// <summary>
        
/// 异步下载进度事件(仅对于单个文件)
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        void webClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            DownloadProgressEventArgs args 
= new DownloadProgressEventArgs(e.ProgressPercentage, e.UserState);
            args.BytesReceived 
= e.BytesReceived;
            args.FileName 
= e.UserState.ToString();
            args.TotalBytesToReceive 
= e.TotalBytesToReceive;
            
if (current != null)
            {
                current.Post(onProgressReportDelegate, args);
            }
        }

        
/// <summary>
        
/// 异步下载完成事件(仅对于单个文件)
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            fileCount
++;
            
if (fileCount == manifest.ManifestFiles.Files.Length)
            {
                
this.CompletionMethod(e.Error, TaskCanceled(current.UserSuppliedState), current);
            }
        }

        
/// <summary>
        
/// 取消异步下载
        
/// </summary>
        public void CancelAsync()
        {
            CancelAsync(defaultTaskId);
        }

        
/// <summary>
        
/// 取消异步下载
        
/// </summary>
        public void CancelAsync(object taskId)
        {
            webClient.CancelAsync();
            cancel 
= true;
            current 
= null;
            AsyncOperation asyncOp 
= userStateToLifetime[taskId] as AsyncOperation;
            
if (asyncOp != null)
            {
                
lock (userStateToLifetime.SyncRoot)
                {
                    userStateToLifetime.Remove(taskId);
                }
            }
        }

        
private bool TaskCanceled(object taskId)
        {
            
return cancel || (userStateToLifetime[taskId] == null);
        }
        
        
private void InitializeComponent()
        {
            components 
= new System.ComponentModel.Container();
        }

        
protected override void Dispose(bool disposing)
        {
            
if (disposing)
            {
                
if (components != null)
                {
                    components.Dispose();
                }
            }
            
base.Dispose(disposing);
        }

        
private void DoDownloadCompleted(object operationState)
        {
            DownloadCompleteEventArgs e 
= operationState as DownloadCompleteEventArgs;
            OnDownloadCompleted(e);
        }

        
private void ReportProgress(object state)
        {
            DownloadProgressEventArgs e 
= state as DownloadProgressEventArgs;
            OnDownloadProgressChanged(e);
        }
    }

更新文件

也就是把下载的文件覆盖到客户端安装的目录,代码如下:

事件参数类

View Code
 /// <summary>
    
/// 文件复制进度报告事件参数
    
/// </summary>
    public class FileCopyProgressChangedEventArgs : ProgressChangedEventArgs
    {
        
public FileCopyProgressChangedEventArgs(int progressPercentage, object userState)
            : 
base(progressPercentage, userState)
        {
        }

        
/// <summary>
        
/// 当前复制的字节数
        
/// </summary>
        public double BytesToCopy { getset; }

        
/// <summary>
        
/// 当前复制操作中的字节总数
        
/// </summary>
        public double TotalBytesToCopy { getset; }

        
/// <summary>
        
/// 当前复制的源文件名
        
/// </summary>
        public string SourceFileName { getset; }

        
/// <summary>
        
/// 当前复制的目标文件名
        
/// </summary>
        public string TargetFileName { getset; }

        
public Manifest Manifest { getset; }
    }

    
/// <summary>
    
/// 文件复制完成事件参数
    
/// </summary>
    public class FileCopyCompletedEventArgs : AsyncCompletedEventArgs
    {
        
public FileCopyCompletedEventArgs(Exception error, bool cancelled, object userState)
            : 
base(error, cancelled, userState)
        {
        }

        
public Manifest Manifest { getset; }
    }

    
public class FileCopyErrorEventArgs : EventArgs
    {
        
public Exception Error { getset; }

        
public Manifest Manifest { getset; }
    }

文件复制类,可以使用异步复制,异步复制提供了事件通知的机制,即可以有进度报告,文件复制也是一个组件类

View Code
 /// <summary>
    
/// 文件复制组件类
    
/// </summary>
    public class FileCopyClass : Component
    {
        
private object defaultTaskId = new object();
        
private int writeFileLength = 1024 * 64;

        
private delegate void WorkerEventHandler(Manifest manifest, string sourcePath, AsyncOperation asyncOp);

        
private SendOrPostCallback onProgressReportDelegate;
        
private SendOrPostCallback onCompletedDelegate;

        
private HybridDictionary userStateToLifetime = new HybridDictionary();

        
private System.ComponentModel.Container components = null;

        
#region Public events

        
/// <summary>
        
/// 文件复制进度事件
        
/// </summary>
        public event EventHandler<FileCopyProgressChangedEventArgs> FileCopyProgressChanged;
        
/// <summary>
        
/// 文件复制完成事件
        
/// </summary>
        public event EventHandler<FileCopyCompletedEventArgs> FileCopyCompleted;

        
public event EventHandler<FileCopyErrorEventArgs> FileCopyError;

        
#endregion

        
#region Construction and destruction

        
public FileCopyClass(IContainer container)
        {
            container.Add(
this);
            InitializeComponent();
            InitializeDelegates();
        }

        
public FileCopyClass()
        {
            InitializeComponent();
            InitializeDelegates();
        }

        
protected virtual void InitializeDelegates()
        {
            onProgressReportDelegate 
= new SendOrPostCallback(ReportProgress);
            onCompletedDelegate 
= new SendOrPostCallback(CopyCompleted);
        }

        
protected override void Dispose(bool disposing)
        {
            
if (disposing)
            {
                
if (components != null)
                {
                    components.Dispose();
                }
            }
            
base.Dispose(disposing);
        }

        
#endregion

        
#region 实现

        
public int WriteFileLength
        {
            
set
            {
                writeFileLength 
= value;
            }
        }

        
public void Copy(Manifest manifest, string sourcePath)
        {
            
string[] sourceFiles = null;
            
string[] targetFiles = null;
            GetFiles(manifest, sourcePath, 
out sourceFiles, out targetFiles);
            
for (int i = 0; i < sourceFiles.Length; i++)
            {
                
if (!Directory.Exists(Path.GetDirectoryName(targetFiles[i])))
                {
                    Directory.CreateDirectory(Path.GetDirectoryName(targetFiles[i]));
                }
                File.Copy(sourceFiles[i], targetFiles[i], 
true);
            }
        }

        
public void CopyAsync(Manifest manifest, string sourcePath)
        {
            CopyAsync(manifest, sourcePath, defaultTaskId);
        }

        
public void CopyAsync(Manifest manifest, string sourcePath, object taskId)
        {
            AsyncOperation asyncOp 
= AsyncOperationManager.CreateOperation(taskId);
            
lock (userStateToLifetime.SyncRoot)
            {
                
if (userStateToLifetime.Contains(taskId))
                {
                    
throw new ArgumentException("参数taskId必须是唯一的""taskId");
                }
                userStateToLifetime[taskId] 
= asyncOp;
            }

            WorkerEventHandler workerDelegate 
= new WorkerEventHandler(FileCopyWorker);
            workerDelegate.BeginInvoke(manifest, sourcePath, asyncOp, 
nullnull);
        }

        
private bool TaskCanceled(object taskId)
        {
            
return (userStateToLifetime[taskId] == null);
        }

        
public void CancelAsync()
        {
            CancelAsync(defaultTaskId);
        }

        
public void CancelAsync(object taskId)
        {
            AsyncOperation asyncOp 
= userStateToLifetime[taskId] as AsyncOperation;
            
if (asyncOp != null)
            {
                
lock (userStateToLifetime.SyncRoot)
                {
                    userStateToLifetime.Remove(taskId);
                }
            }
        }

        
private void FileCopyWorker(Manifest manifest, string sourcePath, AsyncOperation asyncOp)
        {
            Exception exception 
= null;
            FileCopyProgressChangedEventArgs e 
= null;
            Stream rStream 
= null;
            Stream wStream 
= null;
            
double writeBytes = 0;
            
string[] sourceFiles = null
            
string[] targetFiles = null;
            GetFiles(manifest, sourcePath,
out sourceFiles,out targetFiles);
            
if (!TaskCanceled(asyncOp.UserSuppliedState))
            {
                
try
                {
                    
double totalBytes = GetFileLength(sourceFiles);
                    
byte[] buffer = new byte[writeFileLength];
                    
int len = 0;
                    
int offset = 0;
                    
for (int i = 0; i < sourceFiles.Length; i++)
                    {
                        
try
                        {
                            
if (!Directory.Exists(Path.GetDirectoryName(targetFiles[i])))
                            {
                                Directory.CreateDirectory(Path.GetDirectoryName(targetFiles[i]));
                            } 
                            rStream 
= new FileStream(sourceFiles[i], FileMode.Open, FileAccess.Read, FileShare.None);
                            wStream 
= new FileStream(targetFiles[i], FileMode.Create, FileAccess.Write, FileShare.None);
                            
while ((len = rStream.Read(buffer, offset, writeFileLength)) > 0)
                            {
                                wStream.Write(buffer, offset, len);
                                writeBytes 
+= len;
                                e 
= new FileCopyProgressChangedEventArgs((int)(writeBytes / totalBytes * 100), asyncOp.UserSuppliedState);
                                e.SourceFileName 
= sourceFiles[i];
                                e.TargetFileName 
= targetFiles[i];
                                e.TotalBytesToCopy 
= totalBytes;
                                e.BytesToCopy 
= len;
                                e.Manifest 
= manifest;
                                asyncOp.Post(
this.onProgressReportDelegate, e);
                                Thread.Sleep(
1);
                            }
                        }
                        
finally
                        {
                            DisposeStream(wStream);
                            DisposeStream(rStream);
                        }
                    }
                }
                
catch (Exception ex)
                {
                    exception 
= ex;
                    OnFileCopyError(
new FileCopyErrorEventArgs() { Error = ex, Manifest = manifest });
                }
            }
            
this.CompletionMethod(manifest, exception, TaskCanceled(asyncOp.UserSuppliedState), asyncOp);
        }

        
private void GetFiles(Manifest manifest, string sourcePath,out string[] sourceFiles,out string[] targetFiles)
        {
            sourceFiles 
= new string[manifest.ManifestFiles.Files.Length];
            targetFiles 
= new string[manifest.ManifestFiles.Files.Length];
            
string path = Path.GetFullPath(manifest.Application.Location);
            
for (int i = 0; i < manifest.ManifestFiles.Files.Length; i++)
            {
                sourceFiles[i] 
= Path.Combine(sourcePath, manifest.ManifestFiles.Files[i].Source);
                targetFiles[i] 
= Path.Combine(path, manifest.ManifestFiles.Files[i].Source);
            }
        }

        
private void DisposeStream(Stream stream)
        {
            
if (stream != null)
            {
                stream.Flush();
                stream.Close();
                stream.Dispose();
            }
        }

        
private double GetFileLength(string[] sourceFiles)
        {
            
double bytes = 0;
            
foreach (var file in sourceFiles)
            {
                FileInfo fileInfo 
= new FileInfo(file);
                bytes 
+= fileInfo.Length;
            }
            
return bytes;
        }

        
private void CopyCompleted(object operationState)
        {
            FileCopyCompletedEventArgs e 
= operationState as FileCopyCompletedEventArgs;

            OnFileCopyCompleted(e);
        }

        
private void ReportProgress(object state)
        {
            FileCopyProgressChangedEventArgs e 
= state as FileCopyProgressChangedEventArgs;

            OnProgressChanged(e);
        }

        
protected void OnFileCopyCompleted(FileCopyCompletedEventArgs e)
        {
            
if (FileCopyCompleted != null)
            {
                FileCopyCompleted(
this, e);
            }
        }

        
protected void OnProgressChanged(FileCopyProgressChangedEventArgs e)
        {
            
if (FileCopyProgressChanged != null)
            {
                FileCopyProgressChanged(
this, e);
            }
        }

        
protected void OnFileCopyError(FileCopyErrorEventArgs e)
        {
            
if (FileCopyError != null)
            {
                FileCopyError(
this, e);
            }
        }

        
private void CompletionMethod(Manifest manifest, Exception exception, bool canceled, AsyncOperation asyncOp)
        {
            
if (!canceled)
            {
                
lock (userStateToLifetime.SyncRoot)
                {
                    userStateToLifetime.Remove(asyncOp.UserSuppliedState);
                }
            }

            FileCopyCompletedEventArgs e 
= new FileCopyCompletedEventArgs(exception, canceled, asyncOp.UserSuppliedState);
            e.Manifest 
= manifest;
            asyncOp.PostOperationCompleted(onCompletedDelegate, e);
        }

        
#endregion

        
private void InitializeComponent()
        {
            components 
= new System.ComponentModel.Container();
        }
    }

 好了,基本的代码已经完成了,其他都是客户端调用的代码,客户端有2个exe程序,一个是主程序,另外一个是更新程序,所以使用2个exe的原因是,主程序在打开的情况是无法进行更新的,就是文件不能被覆盖,那么主程序只要引用上面写的程序的dll,以及一个配置文件,配置文件的名称在程序写死了的,默认是在exe目录,名称为updateconfiguration.config,主程序只要调用UpdateClass类的CheckForUpdates方法就可以了

Demo

下面说下整体的部署方式

服务器:一个配置文件,记录更新的文件,记录的文件目录一定是存在的,否则会出现404错误

客户端:主程序+更新程序+配置文件,即把更新程序编译后的exe打包到主程序中,

以上程序进行了简单的测试,如果您下载使用了出现了问题,请及时联系我。

作者:风雨彩虹
         
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
原文地址:https://www.cnblogs.com/zbo/p/2111335.html