原理:

工具生成更新配置节xml放到文件服务器上,外网可访问;

能过本地配置文件与服务器配置文件日期属性对比及配置节版本与大小属性判断有无更新;

存在更新,将文件从服务器下载到客户端,并替换原程序重启;

实现时,更新程序与原主程序是两个不同的启动程序,不存在文件占用,避免替换时文件被占用

如果做成一个程序,下载替换时需要通过外部批处理脚本关闭当前应用,并替换程序重启应用。在系统盘时要注意权限问题;

服务端生成xml代码块:

  public partial class FormMain : Form
{
public FormMain()
{
InitializeComponent();
txtWebUrl.Text = "localhost:8011";
txtWebUrl.ForeColor = Color.Gray;
} //获取当前目录
//string currentDirectory = AppDomain.CurrentDomain.BaseDirectory;
string currentDirectory = System.Environment.CurrentDirectory;
//服务端xml文件名称
string serverXmlName = "AutoupdateService.xml";
//更新文件URL前缀
string url = string.Empty; void CreateXml()
{
//创建文档对象
XmlDocument doc = new XmlDocument(); //创建更新文件根节点
XmlElement root = doc.CreateElement("Files");
//设置更新节点日期
root.SetAttribute("Date", DateTime.Now.ToString("yyyyMMdd"));
////创建日期根节点
//XmlElement versionDate = doc.CreateElement("UpDate");
//versionDate.InnerText = DateTime.Now.ToString("yyyyMMdd");
//doc.AppendChild(versionDate); //头声明
XmlDeclaration xmldecl = doc.CreateXmlDeclaration("1.0", "utf-8", null);
doc.AppendChild(xmldecl); DirectoryInfo dicInfo = new DirectoryInfo(currentDirectory); //调用递归方法组装xml文件
PopuAllDirectory(doc, root, dicInfo);
//追加节点
doc.AppendChild(root);
//保存文档
doc.Save(serverXmlName);
} //递归组装xml文件方法
private void PopuAllDirectory(XmlDocument doc, XmlElement root, DirectoryInfo dicInfo)
{
foreach (FileInfo f in dicInfo.GetFiles())
{
//排除当前目录中生成服务端配置文件、此工具文件、后缀为pdb、config、ssk文件、包含vshost的文件
List<string> notMimefile = new List<string>() { "pdb", "config", "ssk" };
if (!f.Name.Contains("CreateXmlTools") && f.Name != "AutoupdateService.xml"&&f.Name != "AutoUpdater.exe" && !notMimefile.Contains(f.Name.Substring(f.Name.LastIndexOf(".") + )) && f.Name.IndexOf("vshost")==-)
{
string path = dicInfo.FullName.Replace(currentDirectory, "").Replace("\\", "/");
string folderPath=string.Empty;
if (path != string.Empty)
{
folderPath = path.TrimStart('/') + "/";
}
XmlElement child = doc.CreateElement("File");
child.SetAttribute("path", folderPath + f.Name);
child.SetAttribute("url", url + path + "/" + f.Name);
child.SetAttribute("version", FileVersionInfo.GetVersionInfo(f.FullName).FileVersion);
child.SetAttribute("size", f.Length.ToString());
root.AppendChild(child);
}
} foreach (DirectoryInfo di in dicInfo.GetDirectories())
PopuAllDirectory(doc, root, di);
} private void btnCreate_Click(object sender, EventArgs e)
{
string host = txtWebUrl.Text.Trim().TrimEnd('/').ToLower();
url = (host.StartsWith("http") || host.StartsWith("https"))? host:"http://" + host;
CreateXml();
ReadXml();
} private void ReadXml()
{
string path="AutoupdateService.xml";
rtbXml.ReadOnly = true;
if (File.Exists(path))
{
rtbXml.Text = File.ReadAllText(path);
}
} private void txtWebUrl_Enter(object sender, EventArgs e)
{
txtWebUrl.ForeColor = Color.Black;
if (txtWebUrl.Text.Trim() == "localhost:8011")
{
txtWebUrl.Text = string.Empty;
}
} }

主程序更新相关代码块:

 private static string strUpdateConfigPath = Application.StartupPath + @"\PrintLocal.config";
private static string strUpdaterProPath = Application.StartupPath + @"\AutoUpdater.exe";
//process.StartInfo.FileName = Application.StartupPath + "//AutoUpdater.exe"; private PopTip _tip;
private void PrintService_Load(object sender, EventArgs e)
{
string strUpdateURL = GetConfigValue(strUpdateConfigPath, "ServerUrl");
LocalVersion.Text = GetConfigValue(strUpdateConfigPath, "Date");
RemoteVersion.Text = GetTheLastUpdateTime(strUpdateURL); skin.SkinFile = System.Environment.CurrentDirectory + @"\Skins\DeepCyan.ssk"; System.Timers.Timer time =new System.Timers.Timer();
int intervaltime = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["checkinterval"]);
time.Elapsed +=new System.Timers.ElapsedEventHandler(IntervalCheck);
time.Interval = intervaltime * ;//时间间隔为intervaltime秒钟
time.Start();
} private void IntervalCheck(object source, System.Timers.ElapsedEventArgs e)
{
if (HasNewVersion())
{
_tip = new PopTip();
Action c = () => _tip.ShowDialog();
c.BeginInvoke(null, c);
}
} private void 更新ToolStripMenuItem_Click(object sender, EventArgs e)
{
CheckUpdate();
} /// <summary>
/// 检查更新.
/// </summary>
private void CheckUpdateBt_Click(object sender, EventArgs e)
{
CheckUpdate();
}
private void CheckUpdate() { if (HasNewVersion()) {
if (MessageBox.Show("是否下载更新?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK)
{
Process process = new Process();
process.StartInfo.FileName = strUpdaterProPath;//更新程序所在位置
process.Start();//启动更新程序
Process.GetCurrentProcess().Kill(); //Kill当前程序
};
}
else
{
MessageBox.Show("未检测到新版本.");
}
} #region 检测版本与获取版本信息
internal static bool HasNewVersion()
{
bool hasNewVersion = false;
string strUpdateURL = GetConfigValue(strUpdateConfigPath, "ServerUrl"); //读取本地xml中配置的更新服务器的URL
string strLastUpdateDate = GetConfigValue(strUpdateConfigPath, "Date"); //读取本地Config中配置的最近配置日期 bool ConfigEnabled = Convert.ToBoolean(GetConfigValue(strUpdateConfigPath, "Enabled")); string strTheUpdateDate = GetTheLastUpdateTime(strUpdateURL); //获得更新服务器端的此次更新日期
if (ConfigEnabled && (DateTime.Compare(DateTime.ParseExact(strTheUpdateDate, "yyyyMMdd", null), DateTime.ParseExact(strLastUpdateDate, "yyyyMMdd", null)) > ))
{
hasNewVersion = true;
}
return hasNewVersion;
} internal static string GetConfigValue(string path, string appKey)
{
XmlDocument xDoc = new XmlDocument();
XmlNode xNode;
XmlElement xElem = null;
try
{
xDoc.Load(path);
xNode = xDoc.SelectSingleNode("//Config");
xElem = (XmlElement)xNode.SelectSingleNode(appKey);
}
catch (XmlException ex)
{
MessageBox.Show(ex.Message);
}
if (xElem != null)
return xElem.InnerText;
else
return "";
}
private static string GetTheLastUpdateTime(string path)
{
string Date = "";
var xml = string.Empty;
HttpWebRequest request = WebRequest.Create(path) as HttpWebRequest;
var response = request.GetResponse();
using (var stream = response.GetResponseStream())
{
using (var reader = new StreamReader(stream, Encoding.UTF8))
{
xml = reader.ReadToEnd();
}
}
response.Close();
var element = XElement.Parse(xml);
Date = element.Attribute("Date").Value;
return Date;
}
#endregion

PopTip代码块:

  public partial class PopTip : Form
{
public PopTip()
{
InitializeComponent();
} private int _count; private void OKBt_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{ Hide();
Process process = new Process();
process.StartInfo.FileName = Application.StartupPath + @"\AutoUpdater.exe";//更新程序所在位置
//process.StartInfo.FileName = Application.StartupPath + "//AutoUpdater.exe";//更新程序所在位置
process.Start();//启动更新程序
Process.GetCurrentProcess().Kill(); } private void CancelBt_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
Hide();
} private void PopTip_Load(object sender, EventArgs e)
{
Location = new Point(Screen.PrimaryScreen.Bounds.Width - Width, Screen.PrimaryScreen.Bounds.Height - Height-);
TipLb.Text = "发现新版本,是否马上更新";
OKBt.Text = "是,马上更新";
timer1.Start();
} private void timer1_Tick(object sender, EventArgs e)
{
_count++;
//提示信息显示8秒就关闭
if (_count == )
{
Close();
}
// timer1.Stop();
} }

更新程序相关代码块:

 /// <summary>
/// Class Config
/// </summary>
public class Config
{
public bool Enabled { get; set; }
public string ServerUrl { get; set; }
public string Date { get; set; }
public List<LocalFile> Files { get; set; }
/// <summary>
/// Loads the config.
/// </summary>
/// <param name="file">The file.</param>
/// <returns>Config.</returns>
public static Config LoadConfig(string file)
{
Config config=new Config();
if (File.Exists(file))
{
var xs = new XmlSerializer(typeof(Config));
var sr = new StreamReader(file);
config = xs.Deserialize(sr) as Config;// 这里是序列化
sr.Close();
}
return config;
} /// <summary>
/// Saves the config.
/// </summary>
/// <param name="file">The file.</param>
public void SaveConfig(string file)
{
var xs = new XmlSerializer(typeof(Config));
var sw = new StreamWriter(file);
xs.Serialize(sw, this);
sw.Close();
}
}
public class LocalFile
{
[XmlAttribute("path")]
public string Path { get; set; } [XmlAttribute("version")]
public string Version { get; set; } [XmlAttribute("size")]
public long Size { get; set; }
}
    public class RemoteFile
{
public string Path { get; set; }
public string Url { get; set; }
public string Version { get; set; }
public long Size { get; set; }
}
        public VersionDetails LoadNewVersion()
{
var xml = string.Empty;
HttpWebRequest request = WebRequest.Create(this.ServerUrl) as HttpWebRequest;
var response = request.GetResponse();
using (var stream = response.GetResponseStream())
{
using (var reader = new StreamReader(stream, Encoding.UTF8))
{
xml = reader.ReadToEnd();
}
}
response.Close();
return new VersionDetails(xml);
}
  public class VersionDetails
{
public VersionDetails(string xml)
{
var element = XElement.Parse(xml);
Date = element.Attribute("Date").Value;
Files = this.LoadFiles(element);
}
public string Date
{
get;
internal set;
} public List<RemoteFile> Files
{
get;
internal set;
}
private List<RemoteFile> LoadFiles(XElement element)
{
var files = new List<RemoteFile>(); foreach (var el in element.Elements("File"))
{
var file = new RemoteFile()
{
Path = el.Attribute("path").Value,
Url = el.Attribute("url").Value,
Version = el.Attribute("version").Value,
Size = Convert.ToInt64(el.Attribute("size").Value)
};
files.Add(file);
}
return files;
} }
        public bool HasNewVersion
{
get
{
return LocalVersion.Enabled && (NewVersion.Date != LocalVersion.Date);
}
}

http://blog.csdn.net/learning_hard/article/details/17456751     [你必须知道的异步编程]——基于任务的异步模式  异步下载

文件下载时可采用WebRequest或WebClient下载文件

参考:

http://www.cnblogs.com/KnightsWarrior/archive/2010/10/20/1856255.html#!comments
http://www.cnblogs.com/stoneniqiu/p/3806558.html
http://www.cnblogs.com/iyond/archive/2007/06/14/783301.html
http://www.cnblogs.com/sparkdev/p/6031920.html

winform更新解决办法:

思路一:

生成一个批处理文件
执行批处理文件并且自身退出
批处理文件中执行覆盖操作
批处理中最后一句启动本程序
完成更新

思路二:

主程序A更新自动更新程序B,自动更新程序B更新主程序A

C# Timer用法及实例详解  http://developer.51cto.com/art/200909/149829.htm

System.Timers.Timer t =
new System.Timers.Timer();
//实例化Timer类,设置间隔时间为10000毫秒;
t.Elapsed +=
new System.Timers.ElapsedEventHandler(theout);
//到达时间的时候执行事件;
t.AutoReset = true;
//设置是执行一次(false)还是一直执行(true);
t.Enabled = true;
//是否执行System.Timers.Timer.Elapsed事件; public void theout(
object source,
System.Timers.ElapsedEventArgs e)
{
MessageBox.Show("OK!");
}
  Timer timer1 = new Timer();
timer1.Interval = ;
timer1.Enabled = true;
timer1.Tick += new EventHandler(timer1EventProcessor);//添加事件

https://msdn.microsoft.com/zh-cn/library/3840csdc.aspx  Timer.Tick 事件

http://www.cnblogs.com/ManchesterUnitedFootballClub/p/4596465.html  Winfrom 提示消息框公共类

关于退出程序

this.Close();   只是关闭当前窗口,若不是主窗体的话,是无法退出程序的,另外若有托管线程(非主线程),也无法干净地退出;

Application.Exit(); 方法停止在所有线程上运行的所有消息循环,并关闭应用程序的所有窗口

强制直接退出了整个程序,不只是关闭子窗体:

Process.GetCurrentProcess().Kill();     //终止当前正在运行的线程

或者System.Threading.Thread.CurrentThread.Abort();

或者Application.ExitThread();

System.Environment.Exit(0);   这是最彻底的退出方式,不管什么线程都被强制退出,把程序结束的很干净。

winfrom更新的更多相关文章

  1. c# winfrom 更新控件时停止刷新,解决闪烁问题

    static Dictionary<Control, bool> m_lstFreezeControl = new Dictionary<Control, bool>(); / ...

  2. Winfrom中ListBox绑定List数据源更新问题

    Winfrom中ListBox绑定List数据源更新问题 摘自:http://xiaocai.info/2010/09/winform-listbox-datasource-update/ Winfr ...

  3. 利用SignalR来同步更新Winfrom小试

    之前写了个用Socket来更新多个Winfrom的试例,这两天看了下SignalR,也用这个来试一下 SignalR 地址:https://www.asp.net/signalr 我这个也是基于 ht ...

  4. WINFROM中自定义控件之绑定数据即时更新

    相信在WINFROM中写自定义控件或者用户控件,很多人都多多少少用过点 最近发现一个用户控件,绑定的数据源没办法自动更新,其实以前处理过这类的问题,可是这次遇到又花了1个多小时,所以决定记下来 在用户 ...

  5. 利用SignalR来同步更新Winfrom

    之前写了个用Socket来更新多个Winfrom的试例,这两天看了下SignalR,也用这个来试一下 SignalR 地址:https://www.asp.net/signalr 我这个也是基于 ht ...

  6. .Net自动更新程序GeneralUpdate,适用于wpf,winfrom,控制台应用

    什么是GeneralUpdate: GeneralUpdate是基于.net framwork4.5.2开发的一款(c/s应用)自动升级程序. 第一个版本叫Autoupdate(原博客: WPF自动更 ...

  7. Winfrom强大的自动更新程序

    推荐一:.Net 小型软件自动更新库(SimpAutoUpdater) http://www.fishlee.net/soft/simple_autoupdater/usage.html 下载地址:h ...

  8. Winfrom 如何安全简单的跨线程更新控件

    来源:http://www.cnblogs.com/rainbowzc/archive/2010/09/29/1838788.html 由于多线程可能导致对控件访问的不一致,导致出现问题.C#中默认是 ...

  9. winFrom程序更新自动安装

    我就以一个计算字符长度的程序为例子吧界面如下 代码如下 [C#] 纯文本查看 复制代码 ? 01 02 03 04 private void  button1_Click(object sender, ...

随机推荐

  1. ThreadPoolExecutor(线程池)源码分析

    1. 常量和变量 private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); // 高3位为线程池的运行状态,低29 ...

  2. 将json字符串转换成list<T>

    using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Se ...

  3. HDU 5638 Toposort 拓扑排序 优先队列

    Toposort 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5638 Description There is a directed acycli ...

  4. Failed to Attach to Process ID Xcode 解决办法

    方法1. go to the Product menu and find the Edit Scheme menu there. While in Edit Scheme window, select ...

  5. Python 学习建议(个人愚见)

    前言 本科毕业已经5年+,一直在做iOS开发. 工作方面:从刚入门的小菜鸟码农,后面到BAT里混过两年,到现在带10个人的Team Leader,收入尚可. 生活状态:已婚,儿子刚满1岁,有一定存款, ...

  6. 将图片转换为Base64字符串公共类抽取

    public class ImageToBase64 { //图片转化成base64字符串 public static String GetImageStr(String path,int width ...

  7. 谈谈WEB开发跟非WEB开发各自不同的关注点

    何为非WEB开发呢,个人理解就是不是用浏览器打开的应用统称为非WEB开发,抽象讲可以理解成C/S模式. WEB开发,技术人员的积累在如下几个方面: HTML + CSS + JavaScript 各种 ...

  8. HDUOJ A Mathematical Curiosity 1017

     此题不难就是输出格式麻烦 #include<stdio.h>  int main(){        int T;   scanf("%d",&T);   ...

  9. [转]bing壁纸天天换 初识shell魅力

    原文链接:http://www.cnblogs.com/atskyline/p/3679522.html 原文的程序跑在window上,curl的使用不太一样,想要获取的图片也不太一样.修改后的代码如 ...

  10. hdu1700 Points on Cycle (数学)

    Problem Description There is a cycle with its center on the origin. Now give you a point on the cycl ...