原理:

工具生成更新配置节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. MySQL v5.7.18 版本解压安装

    下载MySQL https://dev.mysql.com/downloads/mysql/5.1.html#downloads 个人机子是64位的,所以选择下载:Windows (x86, 64-b ...

  2. sql 空值设置默认值

    ifnull(a.discountsign, ') AS "discountsign"

  3. sqlserver 计算数据库时间差

    介绍:datediff(datepart,startdate,enddate) 返回间隔datepart 的数 SELECT datediff(yy,'2010-06-1 10:10',GETDATE ...

  4. 定义serialVersionUID的作用与意义整理

    实现java.io.Serializable这个接口是为序列化,serialVersionUID 用来表明实现序列化类的不同版本间的兼容性.如果你修改了此类, 要修改此值.否则以前用老版本的类序列化的 ...

  5. android 监控软键盘确定 搜索 按钮并赋予点击事件

    在android的实践开发中,为了界面的美观,往往那些搜索框并没有带搜索按钮,而是调用了软键盘的搜索按钮,完成这次时间 1 2 好吧!直接上代码! <EditText android:id=&q ...

  6. 基于Python的交互式访问

    应用迁移中遇到一些有特殊要求的应用,比如需要通过交互生成一些新的config文件,然后启动应用需要依赖于这些文件,这样在构建镜像的时候基本上是没有办法把这些文件固定的,因为他需要根据运行环境去进行动态 ...

  7. Nios II uCLinux/Linux启动分析

    1. 说明 本文采用的Linux源码版本来自Altera公司FTP.不考虑zImage生成的Compress过程.因为zImage是内核binary文件经过gzip 压缩,并在头部添加解压缩代码实现的 ...

  8. linux xfs文件系统无法用readdir获取dirent文件类型d_type则用stat获取暨stat函数讲解

    stat函数讲解 表头文件:    #include <sys/stat.h>             #include <unistd.h>定义函数:    int stat ...

  9. 【好】strong-password-checker,我自己做出来的:)

    我自己做出来的,分了几种情况来考虑.(再后面有加了注释的版本) https://leetcode.com/problems/strong-password-checker/ // 加油! public ...

  10. 如何使用SQLMAP绕过WAF

    WAF(web应用防火墙)逐渐成为安全解决方案的标配之一.正因为有了它,许多公司甚至已经不在意web应用的漏洞.遗憾的是,并不是所有的waf都是不可绕过的!本文将向大家讲述,如何使用注入神器SQLMa ...