您的位置:首页 > 编程语言 > C#

C#在线更新程序

2013-12-22 12:18 429 查看
参考文章

通用的在线升级程序。更新的内容包括一些dll或exe或、配置文件。升级的大致流程是这样的,从服务器获取一个更新的配置文件,经过核对后如有新的更新,则会从服务器下载相应的文件更新到被升级的程序目录下。如果被升级的程序在升级之前已经启动,程序则会强制关闭它,待到升级完成之后重新启动相应的程序。在升级之前程序会自动备份一次,以防升级失败造成程序不能运行。

新建一窗体应用程序UpdateWindow

数据实体

class FileEntry
{
public string FileFullName { get; set; }
public string Src { get; set; }
public string Version { get; set; }
public int Size { get; set; }
public UpdateOption Option { get; set; }

}
public enum UpdateOption
{
add,
del
}

程序配置类

窗体代码文件中添加using System.Configuration;引用

 

/// <summary>
/// 程序类,包括系统配置参数
/// </summary>
public class AppParameter
{
/// <summary>
/// 备份路径
/// </summary>
public static string BackupPath = ConfigurationManager.AppSettings["backupPath"];
/// <summary>
/// 更新服务器的URL
/// </summary>
public static string ServerUrl = ConfigurationManager.AppSettings["serverURL"];
/// <summary>
/// 本地更新文件全名
/// </summary>
public static string LocalUpdateConfig = ConfigurationManager.AppSettings["localUpdateConfig"];
/// <summary>
/// 版本号
/// </summary>
public static string Version = ConfigurationManager.AppSettings["version"];
/// <summary>
/// 更新程序路径
/// </summary>
public static string LocalPath = AppDomain.CurrentDomain.BaseDirectory;
/// <summary>
/// 主程序路径
/// </summary>
public static string MainPath = ConfigurationManager.AppSettings["mainPath"];
/// <summary>
/// 有否启动主程序
/// </summary>
public static bool IsRunning = false;
/// <summary>
/// 主程序名
/// </summary>
public static List<string> AppNames = ConfigurationManager.AppSettings["appName"].Split(';').ToList();
}


主程序

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Configuration;
using System.Threading;
using System.IO;
namespace UpdateWindow
{
public partial class Form1 : Form
{
private bool isDelete = true;//是否要删除升级配置
private bool runningLock = false;//是否正在升级
private Thread thread;//升级的线程载入窗体时需要检查更新,如果有更新就先进行备份,备份失败的话提示错误
//退出更新,如果没有更新就提示”暂时无更新“
public Form1()
{
InitializeComponent();
}
protected void CloseApp()
{
#region  Process Handling

List<string> processNames = new List<string>();
string mainPro = string.Empty;
processNames.AddRange(AppParameter.AppNames);
for (int i = 0; i < processNames.Count; i++)
{
processNames[i] = processNames[i].Substring(processNames[i].LastIndexOf('\\')).Trim('\\').Replace(".exe", "");
}
mainPro = processNames.FirstOrDefault();
AppParameter.IsRunning = ProcessHelper.IsRunningProcess(mainPro);
if (AppParameter.IsRunning)
{
MessageBox.Show("此操作需要关闭要更新的程序,请保存相关数据按确定继续", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
foreach (string item in processNames)
ProcessHelper.CloseProcess(item);
}

#endregion
}

protected void StartApp()
{
try
{
if (AppParameter.IsRunning) ProcessHelper.StartProcess(AppParameter.AppNames.First());
}
catch (Exception ex)
{

MessageBox.Show("程序无法启动!" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void Form1_Load(object sender, EventArgs e)
{
if (CheckUpdate())
{
if (!Backup())
{
MessageBox.Show("备份失败!");
btnStart.Enabled = false;
isDelete = true;
return;
}

}
else
{
MessageBox.Show("暂时无更新");
this.btnFinish.Enabled = true;
this.btnStart.Enabled = false;
isDelete = false;
this.Close();
}
}

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (runningLock)
{
if (MessageBox.Show("升级还在进行中,中断升级会导致程序不可用,是否中断",
"提示", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk) == DialogResult.Yes)
{
if (thread != null) thread.Abort();
isDelete = true;
AppParameter.IsRunning = false;
}
else
{
e.Cancel = true;
return;
}
}
if (isDelete) File.Delete(AppParameter.LocalUpdateConfig);

StartApp();
}

private void btnStart_Click(object sender, EventArgs e)
{
btnStart.Enabled = false;
UpdateApp();
}

private void btnFinish_Click(object sender, EventArgs e)
{
this.Close();
}
/// <summary>
/// 更新
/// </summary>
public void UpdateApp()
{
//bool flag = false;
int successCount = 0;
int failCount = 0;
int itemIndex = 0;
List<FileEntry> list = ConfigHelper.GetUpdateList();
if (list.Count == 0)
{
MessageBox.Show("版本已是最新", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
this.btnFinish.Enabled = true;
this.btnStart.Enabled = false;
isDelete = false;
this.Close();
return;
}
//Thread[] arrThread = new Thread[5];
//for (int i = 0; i < arrThread.Length; i++)
//{
//    arrThread[i] = new Thread(new ThreadStart(delegate()
//    {
thread = new Thread(new ThreadStart(delegate
{
#region thread method

FileEntry ent = null;

while (true)
{
lock (this)
{
if (itemIndex >= list.Count)
break;
ent = list[itemIndex];

//PrintResultDelegate pd = PrintResult;
string msg = string.Empty;
if (ExecUpdateItem(ent))
{
msg = ent.FileFullName + "更新成功";
successCount++;
}
else
{
msg = ent.FileFullName + "更新失败";
failCount++;
}

if (this.InvokeRequired)
{
//this.Invoke(pd, msg,
//   (int)Math.Ceiling(1f / list.Count * 100));
this.Invoke((Action)delegate()
{
listBox1.Items.Add(msg);
int val = (int)Math.Ceiling(1f / list.Count * 100);
progressBar1.Value = progressBar1.Value + val > 100 ? 100 : progressBar1.Value + val;
});
}

itemIndex++;
if (successCount + failCount == list.Count && this.InvokeRequired)
{
string finishMessage = string.Empty;
//SetButtonDelegate sbtn = SetButton;
//this.Invoke(sbtn);
if (this.InvokeRequired)
{
this.Invoke((Action)delegate()
{
btnFinish.Enabled = true;
});
}
isDelete = failCount != 0;
if (!isDelete)
{
AppParameter.Version = list.Last().Version;
ConfigHelper.UpdateAppConfig("version", AppParameter.Version);
finishMessage = "升级完成,程序已成功升级到" + AppParameter.Version;
}
else
finishMessage = "升级完成,但不成功";
MessageBox.Show(finishMessage, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
runningLock = false;
}
}
}
#endregion
}));
//    }));
//}
runningLock = true;
thread.Start();
//foreach (Thread t in arrThread)
//{
//    t.Start();
//}
}

/// <summary>
/// 执行单个更新
/// </summary>
/// <param name="ent"></param>
/// <returns></returns>
public bool ExecUpdateItem(FileEntry ent)
{
bool result = true;

try
{

if (ent.Option == UpdateOption.del)
File.Delete(ent.FileFullName);
else
HttpHelper.DownLoadFile(ent.Src, Path.Combine(AppParameter.MainPath, ent.FileFullName));
}
catch { result = false; }
return result;
}

/// <summary>
/// 检查更新 有则提示用户 确认后下载新的更新配置
/// </summary>
/// <returns>用户确认信息</returns>
public static bool CheckUpdate()
{
bool result = false;

HttpHelper.DownLoadFile(AppParameter.ServerURL, AppParameter.LocalPath + "temp_config.xml");
if (!File.Exists(AppParameter.LocalUpdateConfig))
result = true;
else
{
long localSize = new FileInfo(AppParameter.LocalUpdateConfig).Length;
long tempSize = new FileInfo(AppParameter.LocalPath + "temp_config.xml").Length;

if (localSize >= tempSize) result = false;

else result = true;
}

if (result)
{
if (File.Exists(AppParameter.LocalUpdateConfig)) File.Delete(AppParameter.LocalUpdateConfig);
File.Copy(AppParameter.LocalPath + "temp_config.xml", AppParameter.LocalUpdateConfig);
}
else
result = false;

File.Delete(AppParameter.LocalPath + "temp_config.xml");
return result;
}

/// <summary>
/// 备份
/// </summary>
public static bool Backup()
{
string sourcePath = Path.Combine(AppParameter.BackupPath, DateTime.Now.ToString("yyyy-MM-dd HH_mm_ss")+"_v_"+AppParameter.Version + ".rar");
return ZipHelper.Zip(AppParameter.MainPath.Trim() , sourcePath);
}

//private void PrintResult(string msg, int val)
//{
//    listBox1.Items.Add(msg);
//    progressBar1.Value = progressBar1.Value + val > 100 ? 100 : progressBar1.Value + val;
//}

//private void SetButton()
//{
//    btnFinish.Enabled = true;
//}
}

}

ConfigHelper

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Configuration;

namespace UpdateWindow
{
public class ConfigHelper
{
public static List<FileEntry> GetUpdateList()
{
List<FileEntry> list = new List<FileEntry>();

XmlDocument xml = new XmlDocument();
xml.Load(AppParameter.LocalUpdateConfig);

XmlNodeList nodeList = xml.SelectNodes("/updateFiles/file[@version>" + AppParameter.Version + "]");

FileEntry ent = null;
foreach (XmlNode node in nodeList)
{
ent = new FileEntry();

ent.FileFullName = node.Attributes["name"].Value;
ent.Src = node.Attributes["src"].Value;
ent.Version = node.Attributes["version"].Value;
ent.Size =Convert.ToInt32( node.Attributes["size"].Value);
ent.Option = (UpdateOption)Enum.Parse(typeof(UpdateOption), node.Attributes["option"].Value);

list.Add(ent);
}

return list;
}

public static void UpdateAppConfig(string key,string value)
{
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.AppSettings.Settings[key].Value = value;
config.Save(ConfigurationSaveMode.Full);
ConfigurationManager.RefreshSection("appSettings");
}
}
}


HttpHelper

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;

namespace UpdateWindow
{
public class HttpHelper
{
public static void DownLoadFile(string url,string fileName)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
WebResponse response = request.GetResponse();
Stream stream = response.GetResponseStream();

//if (!response.ContentType.ToLower().StartsWith("text/"))
//{
byte[] buffer = new byte[1024];
Stream outStream = CreateFile(fileName);
Stream inStream = response.GetResponseStream();

int l;
do
{
l = inStream.Read(buffer, 0, buffer.Length);
if (l > 0)
outStream.Write(buffer, 0, l);
}
while (l > 0);

outStream.Close();
inStream.Close();
//}

}

private static FileStream  CreateFile(string fileName)
{
string filePath = Path.GetDirectoryName(fileName);
if (!Directory.Exists(filePath)) Directory.CreateDirectory(filePath);
return File.Create(fileName);
}
}
}


ZipHelper

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using ICSharpCode.SharpZipLib;
using ICSharpCode.SharpZipLib.Checksums;
using ICSharpCode.SharpZipLib.Zip;

namespace UpdateWindow
{
public class ZipHelper
{
#region 压缩文件
/// 递归压缩文件夹方法
public static bool ZipFileDictory(string FolderToZip, ZipOutputStream s, string ParentFolderName)
{
bool res = true;
string[] folders, filenames;
ZipEntry entry = null;
FileStream fs = null;
Crc32 crc = new Crc32();

try
{

//创建当前文件夹
entry = new ZipEntry(Path.Combine(ParentFolderName, Path.GetFileName(FolderToZip) + "/")); //加上 “/” 才会当成是文件夹创建
s.PutNextEntry(entry);
s.Flush();

//先压缩文件,再递归压缩文件夹
filenames = Directory.GetFiles(FolderToZip);
foreach (string file in filenames)
{
//打开压缩文件
fs = File.OpenRead(file);

byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
entry = new ZipEntry(Path.Combine(ParentFolderName, Path.GetFileName(FolderToZip) + "/" + Path.GetFileName(file)));

entry.DateTime = DateTime.Now;
entry.Size = fs.Length;
fs.Close();

crc.Reset();
crc.Update(buffer);

entry.Crc = crc.Value;

s.PutNextEntry(entry);

s.Write(buffer, 0, buffer.Length);
}
}
catch
{
res = false;
}
finally
{
if (fs != null)
{
fs.Close();
fs = null;
}
if (entry != null)
{
entry = null;
}
GC.Collect();
GC.Collect(1);
}

folders = Directory.GetDirectories(FolderToZip);
foreach (string folder in folders)
{
if (!ZipFileDictory(folder, s, Path.Combine(ParentFolderName, Path.GetFileName(FolderToZip))))
{
return false;
}
}

return res;
}

/// <summary>
/// 压缩目录
/// </summary>
/// <param name="FolderToZip">待压缩的文件夹,全路径格式</param>
/// <param name="ZipedFile">压缩后的文件名,全路径格式</param>
/// <param name="Password"></param>
/// <returns></returns>
public static bool ZipFileDictory(string FolderToZip, string ZipedFile, String Password)
{
bool res;
if (!Directory.Exists(FolderToZip))
{
return false;
}

ZipOutputStream s = new ZipOutputStream(File.Create(ZipedFile));
s.SetLevel(6);
s.Password = Password;

res = ZipFileDictory(FolderToZip, s, "");

s.Finish();
s.Close();

return res;
}

/// <summary>
/// 压缩文件
/// </summary>
/// <param name="FileToZip">要进行压缩的文件名</param>
/// <param name="ZipedFile">压缩后生成的压缩文件名</param>
/// <param name="Password"></param>
/// <returns></returns>
public static bool ZipFile(string FileToZip, string ZipedFile, String Password)
{
//如果文件没有找到,则报错
if (!File.Exists(FileToZip))
{
throw new System.IO.FileNotFoundException("指定要压缩的文件: " + FileToZip + " 不存在!");
}
//FileStream fs = null;
FileStream ZipFile = null;
ZipOutputStream ZipStream = null;
ZipEntry ZipEntry = null;

bool res = true;
try
{
ZipFile = File.OpenRead(FileToZip);
byte[] buffer = new byte[ZipFile.Length];
ZipFile.Read(buffer, 0, buffer.Length);
ZipFile.Close();

ZipFile = File.Create(ZipedFile);
ZipStream = new ZipOutputStream(ZipFile);
ZipStream.Password = Password;
ZipEntry = new ZipEntry(Path.GetFileName(FileToZip));
ZipStream.PutNextEntry(ZipEntry);
ZipStream.SetLevel(6);

ZipStream.Write(buffer, 0, buffer.Length);
}
catch
{
res = false;
}
finally
{
if (ZipEntry != null)
{
ZipEntry = null;
}
if (ZipStream != null)
{
ZipStream.Finish();
ZipStream.Close();
}
if (ZipFile != null)
{
ZipFile.Close();
ZipFile = null;
}
GC.Collect();
GC.Collect(1);
}

return res;
}

/// <summary>
/// 压缩文件 和 文件夹
/// </summary>
/// <param name="FileToZip">待压缩的文件或文件夹,全路径格式</param>
/// <param name="ZipedFile">压缩后生成的压缩文件名,全路径格式</param>
/// <param name="Password"></param>
/// <returns></returns>
public static bool Zip(String FileToZip, String ZipedFile, String Password)
{
if (Directory.Exists(FileToZip))
{
return ZipFileDictory(FileToZip, ZipedFile, Password);
}
else if (File.Exists(FileToZip))
{
return ZipFile(FileToZip, ZipedFile, Password);
}
else
{
return false;
}
}

public static bool Zip(String FileToZip, String ZipedFile)
{
return Zip(FileToZip, ZipedFile, "");
}

#endregion

#region 解压文件
/// <summary>
/// 解压功能(解压压缩文件到指定目录)
/// </summary>
/// <param name="FileToUpZip">待解压的文件</param>
/// <param name="ZipedFolder">指定解压目标目录</param>
/// <param name="Password"></param>
public static void UnZip(string FileToUpZip, string ZipedFolder, string Password)
{
if (!File.Exists(FileToUpZip))
{
return;
}

if (!Directory.Exists(ZipedFolder))
{
Directory.CreateDirectory(ZipedFolder);
}

ZipInputStream s = null;
ZipEntry theEntry = null;

string fileName;
FileStream streamWriter = null;
try
{
s = new ZipInputStream(File.OpenRead(FileToUpZip));
s.Password = Password;
while ((theEntry = s.GetNextEntry()) != null)
{
if (theEntry.Name != String.Empty)
{
fileName = Path.Combine(ZipedFolder, theEntry.Name);
fileName = fileName.Replace("/", "\\");//change by Mr.HopeGi
/**/
///判断文件路径是否是文件夹
if (fileName.EndsWith("/") || fileName.EndsWith("\\"))
{
Directory.CreateDirectory(fileName);
continue;
}

streamWriter = File.Create(fileName);
int size = 2048;
byte[] data = new byte[2048];
while (true)
{
size = s.Read(data, 0, data.Length);
if (size > 0)
{
streamWriter.Write(data, 0, size);
}
else
{
break;
}
}
}
}
}
finally
{
if (streamWriter != null)
{
streamWriter.Close();
streamWriter = null;
}
if (theEntry != null)
{
theEntry = null;
}
if (s != null)
{
s.Close();
s = null;
}
GC.Collect();
GC.Collect(1);
}
}

public static void UnZip(string FileToUpZip, string ZipedFolder)
{
UnZip(FileToUpZip, ZipedFolder, "");
}

#endregion
}
}


ProcessHelper

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace UpdateWindow
{
public class ProcessHelper
{
public static bool IsRunningProcess(string processName)
{
Process[] arrPro = GetProcess();
foreach (Process p in arrPro)
{
if (p.ProcessName == processName) return true;
}
return false;
}

public static void CloseProcess(string processName)
{
Process process = Process.GetProcessesByName(processName).FirstOrDefault();
process.CloseMainWindow();
//if (!result) process.Kill();
if (Process.GetProcessesByName(processName).Length != 0)
process.Kill();
//return result;
}

public static void StartProcess(string fileName)
{
Process process = new Process();
process.StartInfo = new ProcessStartInfo(fileName);
process.Start();

}

public static Process[] GetProcess(string ip = "")
{
if (string.IsNullOrEmpty(ip))
return Process.GetProcesses();
return Process.GetProcesses(ip);
}

}
}


配置文件

<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="backupPath" value="D:\我的文档\Visual Studio 2010\Projects\UpdateWindow\UpdateWindow\backup"/>
<add key="serverURL" value="D:\我的文档\Visual Studio 2010\Projects\UpdateWindow\UpdateWindow\test"/>
<add key="localUpdateConfig" value="D:\我的文档\Visual Studio 2010\Projects\UpdateWindow\UpdateWindow\bin\Debug\updateconfig.xml"/>
<add key="version" value="2"/>
<add key="mainPath" value="D:\我的文档\Visual Studio 2010\Projects\UpdateWindow\UpdateWindow\bin\Debug"/>
<add key="appName" value="D:\我的文档\Visual Studio 2010\Projects\UpdateWindow\UpdateWindow\bin\Debug\UpdateWindow.exe"/>
</appSettings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>


服务器下载的更新配置文件

<?xml version="1.0" encoding="utf-8"?>
<updateFiles>
<file name="doc\clientaccesspolicy.xml"  src="http://localhost:8015/clientaccesspolicy.xml" version="3" size="1394007" option="add"/>
<file name="doc\CnemcWebService.asmx"  src="http://localhost:8015/CnemcWebService.asmx" version="3" size="1394007" option="add"/>
<file name="doc\default.aspx"  src="http://localhost:8015/default.aspx" version="3" size="1191936" option="add"/>
<file name="doc\Silverlight.js"  src="http://localhost:8015/Silverlight.js" version="3" size="1191936" option="add"/>
<file name="doc\index.html"  src="http://localhost:8015/index.html" version="3" size="1191936" option="add"/>
<file name="Index.aspx"  src="http://localhost:8015/Index.aspx" version="3" size="14336" option="add"/>
<file name="ClientBin\Images\Login\CNEMCLogo.png"  src="http://localhost:8015/ClientBin/Images/Login/CNEMCLogo.png" version="3" size="14336" option="add"/>
<file name="ClientBin\Images\MainVisual\back.jpg"  src="http://localhost:8015/ClientBin/Images/MainVisual/back.jpg" version="4" size="14336" option="add"/>
<file name="ClientBin\Images\MainVisual\Flag.png"  src="http://localhost:8015/ClientBin/Images/MainVisual/Flag.png" version="4" size="14336" option="add"/>
<file name="ClientBin\Images\MainVisual\help_icon.png"  src="http://localhost:8015/ClientBin/Images/MainVisual/help_icon.png" version="4" size="14336" option="add"/>
<file name="ClientBin\Images\MainVisual\help_icon_big.png"  src="http://localhost:8015/ClientBin/Images/MainVisual/help_icon_big.png" version="4" size="14336" option="add"/>
<file name="ClientBin\Images\MainVisual\loading.png"  src="http://localhost:8015/ClientBin/Images/MainVisual/loading.png" version="4" size="14336" option="add"/>
<file name="ClientBin\Images\MainVisual\logout_icon.png"  src="http://localhost:8015/ClientBin/Images/MainVisual/logout_icon.png" version="4" size="14336" option="add"/>
<file name="ClientBin\Images\MainVisual\message_icon.png"  src="http://localhost:8015/ClientBin/Images/MainVisual/message_icon.png" version="4" size="14336" option="add"/>
<file name="ClientBin\Images\MainVisual\point.png"  src="http://localhost:8015/ClientBin/Images/MainVisual/point.png" version="4" size="14336" option="add"/>
<file name="ClientBin\Images\MainVisual\profile_edit_icon.png"  src="http://localhost:8015/ClientBin/Images/MainVisual/profile_edit_icon.png" version="4" size="14336" option="add"/>
<file name="ClientBin\Images\MainVisual\square.png"  src="http://localhost:8015/ClientBin/Images/MainVisual/square.png" version="4" size="14336" option="add"/>
</updateFiles>


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: